Index: sys/dev/dc/if_dc.c =================================================================== --- sys/dev/dc/if_dc.c (revision 211712) +++ sys/dev/dc/if_dc.c (working copy) @@ -260,6 +260,8 @@ static void dc_eeprom_getword_pnic(struct dc_softc *, int, u_int16_t *); static void dc_eeprom_getword_xircom(struct dc_softc *, int, u_int16_t *); static void dc_eeprom_width(struct dc_softc *); +static int dc_srom_crcok(struct dc_softc *); +static int dc_isv_srom(struct dc_softc *); static void dc_read_eeprom(struct dc_softc *, caddr_t, int, int, int); static void dc_mii_writebit(struct dc_softc *, int); @@ -1729,14 +1731,75 @@ sc->dc_mi = m; } +static int +dc_srom_crcok(struct dc_softc *sc) +{ + uint32_t crc; + + crc = ether_crc32_le(sc->dc_srom, DC_ROM_CRC32_CHECKSUM); + crc = (crc & 0xffff) ^ 0xffff; + if (crc == DC_ROM_GETW(sc->dc_srom, DC_ROM_CRC32_CHECKSUM)) + return (1); + + /* + * Try an alternate checksum. + */ + crc = ether_crc32_le(sc->dc_srom, DC_ROM_CRC32_CHECKSUM1); + crc = (crc & 0xffff) ^ 0xffff; + if (crc == DC_ROM_GETW(sc->dc_srom, DC_ROM_CRC32_CHECKSUM1)) + return (1); + + return (0); +} + +static int +dc_isv_srom(struct dc_softc *sc) +{ + int i; + uint16_t cksum; + + if (dc_srom_crcok(sc)) { + /* + * SROM CRC checks out; must be in the new format. + */ + return (1); + } + + cksum = DC_ROM_GETW(sc->dc_srom, DC_ROM_CRC32_CHECKSUM); + if (cksum == 0xffff || cksum == 0) { + /* + * No checksum present. Check the SROM ID; 18 bytes of 0 + * followed by 1 (version) followed by the number of + * adapters which use this SROM (should be non-zero). + */ + device_printf(sc->dc_dev, "No checksum found in SROM\n"); + for (i = 0; i < DC_ROM_SROM_FORMAT_VERION; i++) { + if (sc->dc_srom[i] != 0) + return (0); + } + if (sc->dc_srom[DC_ROM_SROM_FORMAT_VERION] != 1) + return (0); + if (sc->dc_srom[DC_ROM_CHIP_COUNT] == 0) + return (0); + return (1); + } + + return (0); +} + static void 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); dc_read_eeprom(sc, (caddr_t)sc->dc_srom, 0, (size / 2), 0); + if (dc_isv_srom(sc) == 0) { + device_printf(sc->dc_dev, "Unknown or invalid SROM format\n"); + return; + } + sc->dc_flags |= DC_SROM_VALID; } static void @@ -2087,6 +2150,26 @@ dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0); break; } + /* + * If we still have invalid station address, see whether controller + * has a valid SROM. If it also has a valid SROM, use station + * address of chip 0 as a base address. Some multi-port controllers + * just store station address for chip 0 if they have a shared SROM. + */ + if ((sc->dc_flags & DC_SROM_VALID) != 0 && + (((eaddr[0] == 0 && (eaddr[1] & ~0xffff) == 0)) || + ((eaddr[0] == 0xffffffff && (eaddr[1] & ~0xffff) == 0xffff)))) { + for (i = 0; i < sc->dc_srom[DC_ROM_CHIP_COUNT]; i++) { + if (sc->dc_srom[DC_ROM_CHIPn_DEVICE_NUMBER(i)] == + device_get_unit(dev)) + break; + } + if (i != sc->dc_srom[DC_ROM_CHIP_COUNT]) { + bcopy(&sc->dc_srom[DC_ROM_IEEE_NETWORK_ADDRESS], eaddr, + ETHER_ADDR_LEN); + eaddr[1] += device_get_unit(dev); + } + } /* 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, Index: sys/dev/dc/if_dcreg.h =================================================================== --- sys/dev/dc/if_dcreg.h (revision 211712) +++ sys/dev/dc/if_dcreg.h (working copy) @@ -781,6 +781,7 @@ #define DC_TULIP_LEDS 0x00004000 #define DC_TX_ONE 0x00008000 #define DC_TX_ALIGN 0x00010000 /* align mbuf on tx */ +#define DC_SROM_VALID 0x00100000 /* * register space access macros @@ -1060,6 +1061,45 @@ #define DC_CWUC_LOCK 0x00000100 /* + * Maximum size of a DEC Ethernet Address ROM or SROM. + */ +#define DC_ROM_SIZE(bits) (2 << (bits)) +#define DC_MAX_ROM_SIZE 512 + +/* + * Format of the standard Tulip SROM information: + * + * Byte offset Size Usage + * 0 18 reserved + * 18 1 SROM Format Version + * 19 1 Chip Count + * 20 6 IEEE Network Address + * 26 1 Chip 0 Device Number + * 27 2 Chip 0 Info Leaf Offset + * 29 1 Chip 1 Device Number + * 30 2 Chip 1 Info Leaf Offset + * 32 1 Chip 2 Device Number + * 33 2 Chip 2 Info Leaf Offset + * ... 1 Chip n Device Number + * ... 2 Chip n Info Leaf Offset + * ... ... ... + * Chip Info Leaf Information + * ... + * ... + * ... + * 126 2 CRC32 checksum + */ +#define DC_ROM_SROM_FORMAT_VERION 18 /* B */ +#define DC_ROM_CHIP_COUNT 19 /* B */ +#define DC_ROM_IEEE_NETWORK_ADDRESS 20 +#define DC_ROM_CHIPn_DEVICE_NUMBER(n) (26 + ((n) * 3))/* B */ +#define DC_ROM_CHIPn_INFO_LEAF_OFFSET(n) (27 + ((n) * 3))/* W */ +#define DC_ROM_CRC32_CHECKSUM 126 /* W */ +#define DC_ROM_CRC32_CHECKSUM1 94 /* W */ + +#define DC_ROM_GETW(data, off) ((uint32_t)(data)[(off)] | \ + (uint32_t)((data)[(off) + 1]) << 8) +/* * SROM nonsense. */