/*
*
* Copyright (C) 2001 Eduardo Horvath.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
* PCI bindings for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers
*/
/*
* Some Sun GEMs/ERIs do have their intpin register bogusly set to 0,
* although it should be 1. correct that.
*/
if (pa->pa_intrpin == 0)
pa->pa_intrpin = 1;
sc->sc_variant = GEM_UNKNOWN;
if (pci_dma64_available(pa))
sc->sc_dmatag = pa->pa_dmat64;
else
sc->sc_dmatag = pa->pa_dmat;
sc->sc_flags |= GEM_PCI;
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN) {
if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK)
sc->sc_variant = GEM_SUN_GEM;
if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK)
sc->sc_variant = GEM_SUN_ERI;
} else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE) {
if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC ||
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 ||
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3 ||
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC ||
PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_INTREPID2_GMAC)
sc->sc_variant = GEM_APPLE_GMAC;
if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC)
sc->sc_variant = GEM_APPLE_K2_GMAC;
}
if (sc->sc_variant == GEM_UNKNOWN) {
aprint_error_dev(sc->sc_dev, "unknown adaptor\n");
return;
}
/* XXX Need to check for a 64-bit mem BAR? */
if (pci_mapreg_map(pa, PCI_GEM_BASEADDR,
PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0,
&sc->sc_bustag, &sc->sc_h1, NULL, &sc->sc_size) != 0)
{
aprint_error_dev(sc->sc_dev,
"unable to map device registers\n");
return;
}
if (bus_space_subregion(sc->sc_bustag, sc->sc_h1,
GEM_PCI_BANK2_OFFSET, GEM_PCI_BANK2_SIZE, &sc->sc_h2)) {
aprint_error_dev(sc->sc_dev,
"unable to create bank 2 subregion\n");
return;
}
buf = kmem_alloc(GEM_TMP_BUFSIZE, KM_SLEEP);
if ((data = prop_dictionary_get(device_properties(sc->sc_dev),
"mac-address")) != NULL) {
memcpy(enaddr, prop_data_value(data), ETHER_ADDR_LEN);
got_addr = 1;
if ((data = prop_dictionary_get(device_properties(sc->sc_dev),
"shared-pins")) != NULL) {
memcpy(buf, prop_data_value(data),
prop_data_size(data));
if (isserdes(buf)) {
sc->sc_flags |= GEM_SERDES;
}
}
} else {
/*
* Dig out VPD (vital product data) and acquire Ethernet
* address. The VPD of gem resides in the PCI PROM (PCI FCode).
*/
/*
* ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and
* later) chapter 2 describes the data structure.
*/
/*
* The VPD of gem 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(sc->sc_bustag,
romh, vpdoff, buf, 64);
vpd = (void *)(buf + 3);
if (PCI_VPDRES_ISLARGE(buf[0]) &&
PCI_VPDRES_LARGE_NAME(buf[0])
== PCI_VPDRES_TYPE_VPD &&
vpd->vpd_key0 == 0x4e /* N */ &&
vpd->vpd_key1 == 0x41 /* A */ &&
vpd->vpd_len == ETHER_ADDR_LEN) {
/*
* Ethernet address found
*/
enp = buf + 6;
}
}
}
}
if (!got_addr) {
printf("%s: no Ethernet address found\n",
device_xname(sc->sc_dev));
/* should we bail here? */
}
if (pci_intr_map(pa, &gsc->gsc_handle) != 0) {
aprint_error_dev(sc->sc_dev, "unable to map interrupt\n");
return;
}
gsc->gsc_pc = pa->pa_pc;
gem_pci_estintr(gsc);
/* Finish off the attach. */
gem_attach(sc, enaddr);
if (pmf_device_register1(sc->sc_dev,
gem_pci_suspend, gem_pci_resume, gem_shutdown))
pmf_class_network_register(sc->sc_dev, &sc->sc_ethercom.ec_if);
else
aprint_error_dev(sc->sc_dev,
"could not establish power handlers\n");
}