aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/dc
diff options
context:
space:
mode:
authorPyun YongHyeon <yongari@FreeBSD.org>2010-10-14 17:22:38 +0000
committerPyun YongHyeon <yongari@FreeBSD.org>2010-10-14 17:22:38 +0000
commit39d76ed635a327afb17f12a52ae23d1e92dbcf6f (patch)
treed3b7ed76a25b124c1ed41b7494053d348cafbbc3 /sys/dev/dc
parent3f237b0b0c08a8856f0ee8920e7d90d193362af3 (diff)
Notes
Diffstat (limited to 'sys/dev/dc')
-rw-r--r--sys/dev/dc/if_dc.c46
-rw-r--r--sys/dev/dc/if_dcreg.h1
2 files changed, 47 insertions, 0 deletions
diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c
index a1df655849f6..19bf069e9215 100644
--- a/sys/dev/dc/if_dc.c
+++ b/sys/dev/dc/if_dc.c
@@ -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);
+}
diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h
index 20fd2ce1ba4f..32acc4a1bdf1 100644
--- a/sys/dev/dc/if_dcreg.h
+++ b/sys/dev/dc/if_dcreg.h
@@ -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;