It seems some multi-port dc(4) controllers shares SROM of the first

port such that reading station address from second port always
returned 0xFF:0xFF:0xFF:0xFF:0xFF:0xFF Unfortunately it seems there
is no easy way to know whether SROM is shared or not. Workaround
the issue by traversing dc(4) device list and see whether we're
using second port and use station address of controller 0 as base
station address of second port.

PR:		kern/79262
MFC after:	2 weeks
This commit is contained in:
Pyun YongHyeon 2010-10-14 17:22:38 +00:00
parent 3f237b0b0c
commit 39d76ed635
2 changed files with 47 additions and 0 deletions

View File

@ -293,6 +293,7 @@ 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);
static int dc_check_multiport(struct dc_softc *);
#ifdef DC_USEIOSPACE
#define DC_RES SYS_RES_IOPORT
@ -2088,6 +2089,20 @@ dc_attach(device_t dev)
break;
}
bcopy(eaddr, sc->dc_eaddr, sizeof(eaddr));
/*
* If we still have invalid station address, see whether we can
* find station address for chip 0. Some multi-port controllers
* just store station address for chip 0 if they have a shared
* SROM.
*/
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)
bcopy(sc->dc_eaddr, eaddr, sizeof(eaddr));
}
/* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */
error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
@ -3808,3 +3823,34 @@ dc_shutdown(device_t dev)
return (0);
}
static int
dc_check_multiport(struct dc_softc *sc)
{
struct dc_softc *dsc;
devclass_t dc;
device_t child;
uint8_t *eaddr;
int unit;
dc = devclass_find("dc");
for (unit = 0; unit < devclass_get_maxunit(dc); unit++) {
child = devclass_get_device(dc, unit);
if (child == NULL)
continue;
if (child == sc->dc_dev)
continue;
if (device_get_parent(child) != device_get_parent(sc->dc_dev))
continue;
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_get_nameunit(child));
bcopy(dsc->dc_eaddr, sc->dc_eaddr, ETHER_ADDR_LEN);
eaddr = (uint8_t *)sc->dc_eaddr;
eaddr[5]++;
return (0);
}
return (ENOENT);
}

View File

@ -745,6 +745,7 @@ struct dc_softc {
int dc_if_media;
u_int32_t dc_flags;
u_int32_t dc_txthresh;
u_int32_t dc_eaddr[2];
u_int8_t *dc_srom;
struct dc_mediainfo *dc_mi;
struct dc_list_data *dc_ldata;