diff options
author | yongari <yongari@FreeBSD.org> | 2011-02-18 02:14:53 +0000 |
---|---|---|
committer | yongari <yongari@FreeBSD.org> | 2011-02-18 02:14:53 +0000 |
commit | dc543f1c565aff6c848614be2c8831e4d6711e28 (patch) | |
tree | ff4c31ff67cd1056e6e77d4ae150a1f2ceebe3dd /sys/dev | |
parent | c06fd95fe5e99df3b53a22cef747f99a883dd98a (diff) | |
download | FreeBSD-src-dc543f1c565aff6c848614be2c8831e4d6711e28.zip FreeBSD-src-dc543f1c565aff6c848614be2c8831e4d6711e28.tar.gz |
When driver have to use base softc due to lack of SROM on second
port, copy SROM information from base softc as well and run SROM
parser again. This change is necessary for some dual port
controllers to make dc(4) correctly detect PHY media based on first
port configuration table.
While I'm here add a check for validity of the base softc before
duplicating SROM contents from base softc. If driver failed to
attach to the first port it can access invalid area.
PR: kern/79262
Reviewed by: marius
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/dc/if_dc.c | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 40752a8..14e68e1 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -1815,6 +1815,7 @@ dc_attach(device_t dev) 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; @@ -2108,8 +2109,24 @@ dc_attach(device_t dev) 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. */ @@ -3875,12 +3892,30 @@ dc_check_multiport(struct dc_softc *sc) continue; if (unit > device_get_unit(sc->dc_dev)) continue; + if (device_is_attached(child) == 0) + 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); |