Compute the EEPROM checksum to determine the presence of valid EEPROM data.

If EEPROM data is invalid, allow a MD hook to supply EEPROM data instead.
This commit is contained in:
gavan 2006-02-16 00:02:00 +00:00
parent 4975ba94fa
commit 7600be39ae
2 changed files with 91 additions and 9 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_wm.c,v 1.111 2006/02/07 06:20:04 thorpej Exp $ */ /* $NetBSD: if_wm.c,v 1.112 2006/02/16 00:02:00 gavan Exp $ */
/* /*
* Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@ -47,7 +47,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.111 2006/02/07 06:20:04 thorpej Exp $"); __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.112 2006/02/16 00:02:00 gavan Exp $");
#include "bpfilter.h" #include "bpfilter.h"
#include "rnd.h" #include "rnd.h"
@ -98,6 +98,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.111 2006/02/07 06:20:04 thorpej Exp $");
#include <dev/pci/pcidevs.h> #include <dev/pci/pcidevs.h>
#include <dev/pci/if_wmreg.h> #include <dev/pci/if_wmreg.h>
#include <dev/pci/if_wmvar.h>
#ifdef WM_DEBUG #ifdef WM_DEBUG
#define WM_DEBUG_LINK 0x01 #define WM_DEBUG_LINK 0x01
@ -357,6 +358,7 @@ do { \
#define WM_F_HAS_MII 0x01 /* has MII */ #define WM_F_HAS_MII 0x01 /* has MII */
#define WM_F_EEPROM_HANDSHAKE 0x02 /* requires EEPROM handshake */ #define WM_F_EEPROM_HANDSHAKE 0x02 /* requires EEPROM handshake */
#define WM_F_EEPROM_SPI 0x04 /* EEPROM is SPI */ #define WM_F_EEPROM_SPI 0x04 /* EEPROM is SPI */
#define WM_F_EEPROM_MD 0x08 /* EEPROM not present, use MD hook */
#define WM_F_IOH_VALID 0x10 /* I/O handle is valid */ #define WM_F_IOH_VALID 0x10 /* I/O handle is valid */
#define WM_F_BUS64 0x20 /* bus is 64-bit */ #define WM_F_BUS64 0x20 /* bus is 64-bit */
#define WM_F_PCIX 0x40 /* bus is PCI-X */ #define WM_F_PCIX 0x40 /* bus is PCI-X */
@ -463,7 +465,11 @@ static void wm_reset(struct wm_softc *);
static void wm_rxdrain(struct wm_softc *); static void wm_rxdrain(struct wm_softc *);
static int wm_add_rxbuf(struct wm_softc *, int); static int wm_add_rxbuf(struct wm_softc *, int);
static int wm_read_eeprom(struct wm_softc *, int, int, u_int16_t *); static int wm_read_eeprom(struct wm_softc *, int, int, u_int16_t *);
static int wm_validate_eeprom_checksum(struct wm_softc *);
static void wm_tick(void *); static void wm_tick(void *);
#ifdef __HAVE_WM_READ_EEPROM_HOOK
extern int wm_read_eeprom_hook(int, int, u_int16_t *);
#endif
static void wm_set_filter(struct wm_softc *); static void wm_set_filter(struct wm_softc *);
@ -1066,13 +1072,30 @@ wm_attach(struct device *parent, struct device *self, void *aux)
sc->sc_flags |= WM_F_EEPROM_SPI; sc->sc_flags |= WM_F_EEPROM_SPI;
sc->sc_ee_addrbits = (reg & EECD_EE_ABITS) ? 16 : 8; sc->sc_ee_addrbits = (reg & EECD_EE_ABITS) ? 16 : 8;
} }
if (sc->sc_flags & WM_F_EEPROM_SPI)
eetype = "SPI"; /*
else * Defer printing the EEPROM type until after verifying the checksum
eetype = "MicroWire"; * This allows the EEPROM type to be printed correctly in the case
aprint_verbose("%s: %u word (%d address bits) %s EEPROM\n", * that no EEPROM is attached.
sc->sc_dev.dv_xname, 1U << sc->sc_ee_addrbits, */
sc->sc_ee_addrbits, eetype);
/*
* Validate the EEPROM checksum. If the checksum fails:
*
* If __HAVE_WM_READ_EEPROM_HOOK, we defer to the device-specific
* hook for EEPROM reads. Otherwise we have run out of options,
* so bail.
*/
if (wm_validate_eeprom_checksum(sc)) {
#ifdef __HAVE_WM_READ_EEPROM_HOOK
sc->sc_flags |= WM_F_EEPROM_MD;
#else
aprint_error("%s: EEPROM failed checksum\n",
sc->sc_dev.dv_xname);
return;
#endif
}
/* /*
* Read the Ethernet address from the EEPROM. * Read the Ethernet address from the EEPROM.
@ -1083,6 +1106,19 @@ wm_attach(struct device *parent, struct device *self, void *aux)
sc->sc_dev.dv_xname); sc->sc_dev.dv_xname);
return; return;
} }
if (sc->sc_flags & WM_F_EEPROM_MD)
aprint_verbose("%s: No EEPROM\n", sc->sc_dev.dv_xname);
else {
if (sc->sc_flags & WM_F_EEPROM_SPI)
eetype = "SPI";
else
eetype = "MicroWire";
aprint_verbose("%s: %u word (%d address bits) %s EEPROM\n",
sc->sc_dev.dv_xname, 1U << sc->sc_ee_addrbits,
sc->sc_ee_addrbits, eetype);
}
enaddr[0] = myea[0] & 0xff; enaddr[0] = myea[0] & 0xff;
enaddr[1] = myea[0] >> 8; enaddr[1] = myea[0] >> 8;
enaddr[2] = myea[1] & 0xff; enaddr[2] = myea[1] & 0xff;
@ -3111,6 +3147,35 @@ wm_read_eeprom_spi(struct wm_softc *sc, int word, int wordcnt, uint16_t *data)
return (0); return (0);
} }
#define EEPROM_CHECKSUM 0xBABA
#define EEPROM_SIZE 0x0040
/*
* wm_validate_eeprom_checksum
*
* The checksum is defined as the sum of the first 64 (16 bit) words.
*/
static int
wm_validate_eeprom_checksum(struct wm_softc *sc)
{
uint16_t checksum;
uint16_t eeprom_data;
int i;
checksum = 0;
for (i = 0; i < EEPROM_SIZE; i++) {
if(wm_read_eeprom(sc, i, 1, &eeprom_data))
return 1;
checksum += eeprom_data;
}
if (checksum != (uint16_t) EEPROM_CHECKSUM)
return 1;
return 0;
}
/* /*
* wm_read_eeprom: * wm_read_eeprom:
* *
@ -3121,6 +3186,13 @@ wm_read_eeprom(struct wm_softc *sc, int word, int wordcnt, uint16_t *data)
{ {
int rv; int rv;
#ifdef __HAVE_WM_READ_EEPROM_HOOK
if (sc->sc_flags & WM_F_EEPROM_MD) {
rv = wm_read_eeprom_hook(word, wordcnt, data);
return (rv);
}
#endif
if (wm_acquire_eeprom(sc)) if (wm_acquire_eeprom(sc))
return (1); return (1);

10
sys/dev/pci/if_wmvar.h Normal file
View File

@ -0,0 +1,10 @@
/* $NetBSD: if_wmvar.h,v 1.1 2006/02/16 00:02:00 gavan Exp $ */
#ifndef _DEV_PCI_IF_WMVAR_H_
#define _DEV_PCI_IF_WMVAR_H_
#ifdef __HAVE_WM_READ_EEPROM_HOOK
extern int wm_read_eeprom_hook(int, int, u_int16_t *);
#endif /* __HAVE_WM_READ_EEPROM_HOOK */
#endif /* _DEV_PCI_IF_WMVAR_H_ */