Subject: Re: kern/13797: hme driver does not compile on i386
To: None <gnats-bugs@gnats.netbsd.org, tech-kern@netbsd.org>
From: ITOH Yasufumi <itohy@netbsd.org>
List: tech-kern
Date: 12/26/2002 22:23:48
Here's a modified version.
OK to commit this?
(I only tested on alpha.)
--
ITOH Yasufumi
Index: if_hme_pci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_hme_pci.c,v
retrieving revision 1.12
diff -p -u -r1.12 if_hme_pci.c
--- if_hme_pci.c 2002/10/02 16:51:26 1.12
+++ if_hme_pci.c 2002/12/26 11:38:28
@@ -58,6 +58,14 @@ __KERNEL_RCSID(0, "$NetBSD: if_hme_pci.c
#include <dev/ic/hmevar.h>
+#ifndef HME_USE_LOCAL_MAC_ADDRESS
+#ifdef __sparc__
+#define HME_USE_LOCAL_MAC_ADDRESS 0 /* use system-wide address */
+#else
+#define HME_USE_LOCAL_MAC_ADDRESS 1
+#endif
+#endif
+
struct hme_pci_softc {
struct hme_softc hsc_hme; /* HME device */
bus_space_tag_t hsc_memt;
@@ -98,9 +106,38 @@ hmeattach_pci(parent, self, aux)
pcireg_t csr;
const char *intrstr;
int type;
-
+#if HME_USE_LOCAL_MAC_ADDRESS
+ struct pci_attach_args ebus_pa;
+ pcireg_t ebus_cl, ebus_id;
+ u_int8_t *enaddr;
+ bus_space_tag_t romt;
+ bus_space_handle_t romh;
+ bus_size_t romsize;
+ u_int8_t buf[32];
+ int dataoff, vpdoff;
+ struct pci_vpd *vpd;
+ static const u_int8_t promhdr[] = { 0x55, 0xaa };
+#define PROMHDR_PTR_DATA 0x18
+ static const u_int8_t promdat[] = {
+ 0x50, 0x43, 0x49, 0x52, /* "PCIR" */
+ PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8,
+ PCI_PRODUCT_SUN_HMENETWORK & 0xff,
+ PCI_PRODUCT_SUN_HMENETWORK >> 8
+ };
+#define PROMDATA_PTR_VPD 0x08
+#define PROMDATA_DATA2 0x0a
+ static const u_int8_t promdat2[] = {
+ 0x18, 0x00, /* structure length */
+ 0x00, /* structure revision */
+ 0x00, /* interface revision */
+ PCI_SUBCLASS_NETWORK_ETHERNET, /* subclass code */
+ PCI_CLASS_NETWORK /* class code */
+ };
+#endif /* HME_USE_LOCAL_MAC_ADDRESS */
+#ifdef __sparc__
/* XXX the following declarations should be elsewhere */
extern void myetheraddr __P((u_char *));
+#endif
printf(": Sun Happy Meal Ethernet, rev. %d\n",
PCI_REVISION(pa->pa_class));
@@ -173,8 +210,86 @@ hmeattach_pci(parent, self, aux)
sc->sc_dev.dv_xname);
return;
}
+
+#if HME_USE_LOCAL_MAC_ADDRESS
+ /*
+ * Dig out VPD (vital product data) and acquire Ethernet address.
+ * The VPD of hme resides in the Boot PROM (PCI FCode) attached
+ * to the EBus interface.
+ */
+ /*
+ * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later)
+ * chapter 2 describes the data structure.
+ */
+
+ enaddr = NULL;
- myetheraddr(sc->sc_enaddr);
+ /* get a PCI tag for the EBus bridge (function 0 of the same device) */
+ ebus_pa = *pa;
+ ebus_pa.pa_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 0);
+
+ ebus_cl = pci_conf_read(ebus_pa.pa_pc, ebus_pa.pa_tag, PCI_CLASS_REG);
+ ebus_id = pci_conf_read(ebus_pa.pa_pc, ebus_pa.pa_tag, PCI_ID_REG);
+
+#define PCI_EBUS2_BOOTROM 0x10
+ if (PCI_CLASS(ebus_cl) == PCI_CLASS_BRIDGE &&
+ PCI_PRODUCT(ebus_id) == PCI_PRODUCT_SUN_EBUS &&
+ pci_mapreg_map(&ebus_pa, PCI_EBUS2_BOOTROM, PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_CACHEABLE | BUS_SPACE_MAP_PREFETCHABLE,
+ &romt, &romh, 0, &romsize) == 0) {
+
+ /* read PCI Expansion PROM Header */
+ bus_space_read_region_1(romt, romh, 0, buf, sizeof buf);
+ if (memcmp(buf, promhdr, sizeof promhdr) == 0 &&
+ (dataoff = (buf[PROMHDR_PTR_DATA] |
+ (buf[PROMHDR_PTR_DATA + 1] << 8))) >= 0x1c) {
+
+ /* read PCI Expansion PROM Data */
+ bus_space_read_region_1(romt, romh, dataoff,
+ buf, sizeof buf);
+ if (memcmp(buf, promdat, sizeof promdat) == 0 &&
+ memcmp(buf + PROMDATA_DATA2, promdat2,
+ sizeof promdat2) == 0 &&
+ (vpdoff = (buf[PROMDATA_PTR_VPD] |
+ (buf[PROMDATA_PTR_VPD + 1] << 8))) >= 0x1c) {
+
+ /*
+ * The VPD of hme is not in PCI 2.2 standard
+ * format. The length in the resource header
+ * is in big endian, and resources are not
+ * properly terminated (only one resource
+ * and no end tag).
+ */
+ /* read PCI VPD */
+ bus_space_read_region_1(romt, romh,
+ vpdoff, buf, sizeof buf);
+ vpd = (void *)(buf + 3);
+ if (PCI_VPDRES_ISLARGE(buf[0]) &&
+ PCI_VPDRES_LARGE_NAME(buf[0])
+ == PCI_VPDRES_TYPE_VPD &&
+ /* buf[1] == 0 && buf[2] == 9 && */ /*len*/
+ vpd->vpd_key0 == 0x4e /* N */ &&
+ vpd->vpd_key1 == 0x41 /* A */ &&
+ vpd->vpd_len == ETHER_ADDR_LEN) {
+ /*
+ * Ethernet address found
+ */
+ enaddr = buf + 6;
+ }
+ }
+ }
+ bus_space_unmap(romt, romh, romsize);
+ }
+
+ if (enaddr)
+ memcpy(sc->sc_enaddr, enaddr, ETHER_ADDR_LEN);
+ else
+#endif /* HME_USE_LOCAL_MAC_ADDRESS */
+#ifdef __sparc__
+ myetheraddr(sc->sc_enaddr);
+#else
+ printf("%s: no Ethernet address found\n", sc->sc_dev.dv_xname);
+#endif
/*
* Map and establish our interrupt.