summaryrefslogtreecommitdiffstats
path: root/sys/dev/gem/if_gem_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/gem/if_gem_pci.c')
-rw-r--r--sys/dev/gem/if_gem_pci.c165
1 files changed, 126 insertions, 39 deletions
diff --git a/sys/dev/gem/if_gem_pci.c b/sys/dev/gem/if_gem_pci.c
index 77f89cf..742bf8f 100644
--- a/sys/dev/gem/if_gem_pci.c
+++ b/sys/dev/gem/if_gem_pci.c
@@ -25,50 +25,41 @@
* SUCH DAMAGE.
*
* from: NetBSD: if_gem_pci.c,v 1.7 2001/10/18 15:09:15 thorpej Exp
- *
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
- * PCI bindings for Sun GEM ethernet controllers.
+ * PCI bindings for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
-#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/resource.h>
+#include <sys/rman.h>
#include <sys/socket.h>
-#include <machine/endian.h>
-
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/if_dl.h>
-#include <net/if_media.h>
#include <machine/bus.h>
-#include <machine/resource.h>
+#if defined(__powerpc__) || defined(__sparc64__)
#include <dev/ofw/openfirm.h>
#include <machine/ofw_machdep.h>
-
-#include <sys/rman.h>
-
-#include <dev/mii/mii.h>
-#include <dev/mii/miivar.h>
+#endif
+#include <machine/resource.h>
#include <dev/gem/if_gemreg.h>
#include <dev/gem/if_gemvar.h>
-#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
#include "miibus_if.h"
@@ -106,41 +97,35 @@ static driver_t gem_pci_driver = {
sizeof(struct gem_softc)
};
-
DRIVER_MODULE(gem, pci, gem_pci_driver, gem_devclass, 0, 0);
MODULE_DEPEND(gem, pci, 1, 1, 1);
MODULE_DEPEND(gem, ether, 1, 1, 1);
-struct gem_pci_dev {
- u_int32_t gpd_devid;
- int gpd_variant;
- char *gpd_desc;
+static const struct gem_pci_dev {
+ uint32_t gpd_devid;
+ int gpd_variant;
+ const char *gpd_desc;
} gem_pci_devlist[] = {
- { 0x1101108e, GEM_SUN_GEM, "Sun ERI 10/100 Ethernet Adaptor" },
- { 0x2bad108e, GEM_SUN_GEM, "Sun GEM Gigabit Ethernet Adaptor" },
- { 0x0021106b, GEM_APPLE_GMAC, "Apple GMAC Ethernet Adaptor" },
- { 0x0024106b, GEM_APPLE_GMAC, "Apple GMAC2 Ethernet Adaptor" },
- { 0x0032106b, GEM_APPLE_GMAC, "Apple GMAC3 Ethernet Adaptor" },
+ { 0x1101108e, GEM_SUN_ERI, "Sun ERI 10/100 Ethernet" },
+ { 0x2bad108e, GEM_SUN_GEM, "Sun GEM Gigabit Ethernet" },
+ { 0x0021106b, GEM_APPLE_GMAC, "Apple UniNorth GMAC Ethernet" },
+ { 0x0024106b, GEM_APPLE_GMAC, "Apple Pangea GMAC Ethernet" },
+ { 0x0032106b, GEM_APPLE_GMAC, "Apple UniNorth2 GMAC Ethernet" },
+ { 0x004c106b, GEM_APPLE_K2_GMAC,"Apple K2 GMAC Ethernet" },
+ { 0x0051106b, GEM_APPLE_GMAC, "Apple Shasta GMAC Ethernet" },
+ { 0x006b106b, GEM_APPLE_GMAC, "Apple Intrepid 2 GMAC Ethernet" },
{ 0, 0, NULL }
};
-/*
- * Attach routines need to be split out to different bus-specific files.
- */
static int
gem_pci_probe(dev)
device_t dev;
{
int i;
- u_int32_t devid;
- struct gem_softc *sc;
- devid = pci_get_devid(dev);
for (i = 0; gem_pci_devlist[i].gpd_desc != NULL; i++) {
- if (devid == gem_pci_devlist[i].gpd_devid) {
+ if (pci_get_devid(dev) == gem_pci_devlist[i].gpd_devid) {
device_set_desc(dev, gem_pci_devlist[i].gpd_desc);
- sc = device_get_softc(dev);
- sc->sc_variant = gem_pci_devlist[i].gpd_variant;
return (BUS_PROBE_DEFAULT);
}
}
@@ -149,7 +134,7 @@ gem_pci_probe(dev)
}
static struct resource_spec gem_pci_res_spec[] = {
- { SYS_RES_MEMORY, PCI_GEM_BASEADDR, RF_ACTIVE },
+ { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ SYS_RES_IRQ, 0, RF_SHAREABLE | RF_ACTIVE },
{ -1, 0 }
};
@@ -158,7 +143,24 @@ static int
gem_pci_attach(dev)
device_t dev;
{
- struct gem_softc *sc = device_get_softc(dev);
+ struct gem_softc *sc;
+ int i;
+#if !(defined(__powerpc__) || defined(__sparc64__))
+ int j;
+#endif
+
+ sc = device_get_softc(dev);
+ sc->sc_variant = GEM_UNKNOWN;
+ for (i = 0; gem_pci_devlist[i].gpd_desc != NULL; i++) {
+ if (pci_get_devid(dev) == gem_pci_devlist[i].gpd_devid) {
+ sc->sc_variant = gem_pci_devlist[i].gpd_variant;
+ break;
+ }
+ }
+ if (sc->sc_variant == GEM_UNKNOWN) {
+ device_printf(dev, "unknown adaptor\n");
+ return (ENXIO);
+ }
pci_enable_busmaster(dev);
@@ -170,7 +172,7 @@ gem_pci_attach(dev)
pci_set_intpin(dev, 1);
sc->sc_dev = dev;
- sc->sc_pci = 1; /* XXX */
+ sc->sc_flags |= GEM_PCI; /* XXX */
if (bus_alloc_resources(dev, gem_pci_res_spec, sc->sc_res)) {
device_printf(dev, "failed to allocate resources\n");
@@ -180,8 +182,93 @@ gem_pci_attach(dev)
GEM_LOCK_INIT(sc, device_get_nameunit(dev));
- /* All platform that this driver is used on must provide this. */
+#if defined(__powerpc__) || defined(__sparc64__)
OF_getetheraddr(dev, sc->sc_enaddr);
+#else
+ /*
+ * Dig out VPD (vital product data) and read NA (network address).
+ * The VPD of GEM resides in the PCI Expansion ROM (PCI FCode) and
+ * can't be accessed via the PCI capability pointer.
+ * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later)
+ * chapter 2 describes the data structure.
+ */
+
+#define PCI_ROMHDR_SIZE 0x1c
+#define PCI_ROMHDR_SIG 0x00
+#define PCI_ROMHDR_SIG_MAGIC 0xaa55 /* little endian */
+#define PCI_ROMHDR_PTR_DATA 0x18
+#define PCI_ROM_SIZE 0x18
+#define PCI_ROM_SIG 0x00
+#define PCI_ROM_SIG_MAGIC 0x52494350 /* "PCIR", endian */
+ /* reversed */
+#define PCI_ROM_VENDOR 0x04
+#define PCI_ROM_DEVICE 0x06
+#define PCI_ROM_PTR_VPD 0x08
+#define PCI_VPDRES_BYTE0 0x00
+#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80)
+#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f)
+#define PCI_VPDRES_TYPE_VPD 0x10 /* large */
+#define PCI_VPDRES_LARGE_LEN_LSB 0x01
+#define PCI_VPDRES_LARGE_LEN_MSB 0x02
+#define PCI_VPDRES_LARGE_DATA 0x03
+#define PCI_VPD_SIZE 0x03
+#define PCI_VPD_KEY0 0x00
+#define PCI_VPD_KEY1 0x01
+#define PCI_VPD_LEN 0x02
+#define PCI_VPD_DATA 0x03
+
+#define GEM_ROM_READ_N(n, sc, offs) \
+ bus_read_ ## n ((sc)->sc_res[0], GEM_PCI_ROM_OFFSET + (offs))
+#define GEM_ROM_READ_1(sc, offs) GEM_ROM_READ_N(1, (sc), (offs))
+#define GEM_ROM_READ_2(sc, offs) GEM_ROM_READ_N(2, (sc), (offs))
+#define GEM_ROM_READ_4(sc, offs) GEM_ROM_READ_N(4, (sc), (offs))
+
+ /* Read PCI Expansion ROM header. */
+ if (GEM_ROM_READ_2(sc, PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC ||
+ (i = GEM_ROM_READ_2(sc, PCI_ROMHDR_PTR_DATA)) < PCI_ROMHDR_SIZE) {
+ device_printf(dev, "unexpected PCI Expansion ROM header\n");
+ goto fail;
+ }
+
+ /* Read PCI Expansion ROM data. */
+ if (GEM_ROM_READ_4(sc, i + PCI_ROM_SIG) != PCI_ROM_SIG_MAGIC ||
+ GEM_ROM_READ_2(sc, i + PCI_ROM_VENDOR) != pci_get_vendor(dev) ||
+ GEM_ROM_READ_2(sc, i + PCI_ROM_DEVICE) != pci_get_device(dev) ||
+ (j = GEM_ROM_READ_2(sc, i + PCI_ROM_PTR_VPD)) < i + PCI_ROM_SIZE) {
+ device_printf(dev, "unexpected PCI Expansion ROM data\n");
+ goto fail;
+ }
+
+ /*
+ * Read PCI VPD.
+ * SUNW,pci-gem cards have a single large resource VPD-R tag
+ * containing one NA. The VPD used is not in PCI 2.2 standard
+ * format however. The length in the resource header is in big
+ * endian and the end tag is non-standard (0x79) and followed
+ * by an all-zero "checksum" byte. Sun calls this a "Fresh
+ * Choice Ethernet" VPD...
+ */
+ if (PCI_VPDRES_ISLARGE(GEM_ROM_READ_1(sc, j + PCI_VPDRES_BYTE0)) == 0 ||
+ PCI_VPDRES_LARGE_NAME(GEM_ROM_READ_1(sc, j + PCI_VPDRES_BYTE0)) !=
+ PCI_VPDRES_TYPE_VPD ||
+ (GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_LEN_LSB) << 8 |
+ GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_LEN_MSB)) !=
+ PCI_VPD_SIZE + ETHER_ADDR_LEN ||
+ GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY0) !=
+ 0x4e /* N */ ||
+ GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY1) !=
+ 0x41 /* A */ ||
+ GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_LEN) !=
+ ETHER_ADDR_LEN ||
+ GEM_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_DATA +
+ ETHER_ADDR_LEN) != 0x79) {
+ device_printf(dev, "unexpected PCI VPD\n");
+ goto fail;
+ }
+ bus_read_region_1(sc->sc_res[0], GEM_PCI_ROM_OFFSET + j +
+ PCI_VPDRES_LARGE_DATA + PCI_VPD_DATA, sc->sc_enaddr,
+ ETHER_ADDR_LEN);
+#endif
/*
* call the main configure
@@ -200,8 +287,8 @@ gem_pci_attach(dev)
return (0);
fail:
- bus_release_resources(dev, gem_pci_res_spec, sc->sc_res);
GEM_LOCK_DESTROY(sc);
+ bus_release_resources(dev, gem_pci_res_spec, sc->sc_res);
return (ENXIO);
}
OpenPOWER on IntegriCloud