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/23/2002 02:07:49
In article <200108272230.f7RMUv505866@fuji.augustsson.net>
augustss@fuji.augustsson.net writes:
> >Description:
> If you try to include the hme driver in a i386 (and others, I
> presume) kernel it fails. The reason is that if_hme_pci.c
> refers to the function myetheraddr() which seems to be SUN
> specific.
I recently got a PCI HME device (SunSwift) and trying to use it.
The PCI HME device is an Sun PCIO chip, which contains two PCI functions.
Reference: http://www.sun.com/processors/manuals/802-7837.pdf
PCI bus --+- (function 0) EBus bridge - ROM
+- (function 1) HME
The EBus Boot PROM has FCode ROM, and has an Etheret address in it.
The HME device has ROM area, but it doesn't have any data (all 0xff).
I have make it works on Alpha by following changes.
I know this is kludgy. It steals the Ethernet address
by looking at different device (EBus bridge) in HME match function,
and passes it via static variables.
Is this fix OK? Do you have better fix?
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/22 16:17:01
@@ -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;
@@ -71,6 +79,14 @@ void hmeattach_pci __P((struct device *,
CFATTACH_DECL(hme_pci, sizeof(struct hme_pci_softc),
hmematch_pci, hmeattach_pci, NULL, NULL);
+#if HME_USE_LOCAL_MAC_ADDRESS
+/*
+ * local Ethernet address
+ */
+u_int8_t hme_enaddr[ETHER_ADDR_LEN];
+int hme_has_enaddr;
+#endif /* HME_USE_LOCAL_MAC_ADDRESS */
+
int
hmematch_pci(parent, cf, aux)
struct device *parent;
@@ -78,11 +94,95 @@ hmematch_pci(parent, cf, aux)
void *aux;
{
struct pci_attach_args *pa = aux;
+#if HME_USE_LOCAL_MAC_ADDRESS
+ bus_space_tag_t romt;
+ bus_space_handle_t romh;
+ bus_size_t romsize;
+ unsigned char buf[32];
+ int dataoff, vpdoff;
+ struct pci_vpd *vpd;
+ static const unsigned char promhdr[] = { 0x55, 0xaa };
+#define PROMHDR_PTR_DATA 0x18
+ static const unsigned char 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 unsigned char 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 */
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_HMENETWORK)
return (1);
+#if HME_USE_LOCAL_MAC_ADDRESS
+#define PCI_EBUS2_BOOTROM 0x10
+ if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
+ PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN &&
+ (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_EBUS ||
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_EBUSIII) &&
+ pci_mapreg_map(pa, PCI_EBUS2_BOOTROM, PCI_MAPREG_TYPE_MEM,
+ BUS_SPACE_MAP_CACHEABLE | BUS_SPACE_MAP_PREFETCHABLE,
+ &romt, &romh, 0, &romsize) == 0) {
+
+ /*
+ * Dig out VPD (vital product data) and steal Ethernet address.
+ * The VPD of hme resides in the Boot PROM (PCI FCode) attached
+ * to the EBus interface. Wow!
+ */
+
+ /* read PCI Expension 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 Expension 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) {
+
+ /* 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 && */ /* ? */
+ vpd->vpd_key0 == 0x4E /* N */ &&
+ vpd->vpd_key1 == 0x41 /* A */ &&
+ vpd->vpd_len == ETHER_ADDR_LEN) {
+ /*
+ * Ethernet address found
+ */
+ memcpy(hme_enaddr, buf + 6,
+ ETHER_ADDR_LEN);
+ hme_has_enaddr = 1;
+ printf("hme: read Ethernet address from EBus FCode PROM (%s)\n",
+ ether_sprintf(buf + 6));
+ }
+ }
+ }
+ bus_space_unmap(romt, romh, romsize);
+ /* do not attach EBus bridge */
+ /* FALLTHROUGH */
+ }
+#endif /* HME_USE_LOCAL_MAC_ADDRESS */
+
return (0);
}
@@ -98,9 +198,10 @@ hmeattach_pci(parent, self, aux)
pcireg_t csr;
const char *intrstr;
int type;
-
+#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));
@@ -174,7 +275,16 @@ hmeattach_pci(parent, self, aux)
return;
}
- myetheraddr(sc->sc_enaddr);
+#if HME_USE_LOCAL_MAC_ADDRESS
+ if (hme_has_enaddr)
+ memcpy(sc->sc_enaddr, hme_enaddr, ETHER_ADDR_LEN);
+#endif
+#ifdef __sparc__
+#if HME_USE_LOCAL_MAC_ADDRESS
+ else
+#endif
+ myetheraddr(sc->sc_enaddr);
+#endif
/*
* Map and establish our interrupt.