1119418Sobrien/*- 291396Stmm * Copyright (c) 2000 Matthew R. Green 3178589Smarius * Copyright (c) 2007 Marius Strobl <marius@FreeBSD.org> 491396Stmm * All rights reserved. 591396Stmm * 691396Stmm * Redistribution and use in source and binary forms, with or without 791396Stmm * modification, are permitted provided that the following conditions 891396Stmm * are met: 991396Stmm * 1. Redistributions of source code must retain the above copyright 1091396Stmm * notice, this list of conditions and the following disclaimer. 1191396Stmm * 2. Redistributions in binary form must reproduce the above copyright 1291396Stmm * notice, this list of conditions and the following disclaimer in the 1391396Stmm * documentation and/or other materials provided with the distribution. 1491396Stmm * 3. The name of the author may not be used to endorse or promote products 1591396Stmm * derived from this software without specific prior written permission. 1691396Stmm * 1791396Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1891396Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1991396Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2091396Stmm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2191396Stmm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2291396Stmm * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2391396Stmm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2491396Stmm * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2591396Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2691396Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2791396Stmm * SUCH DAMAGE. 2891396Stmm * 29133731Smarius * from: NetBSD: if_hme_pci.c,v 1.14 2004/03/17 08:58:23 martin Exp 3091396Stmm */ 3191396Stmm 32119418Sobrien#include <sys/cdefs.h> 33119418Sobrien__FBSDID("$FreeBSD$"); 34119418Sobrien 3591396Stmm/* 3691396Stmm * PCI front-end device driver for the HME ethernet device. 3791396Stmm */ 3891396Stmm 3991396Stmm#include <sys/param.h> 4091396Stmm#include <sys/systm.h> 4191396Stmm#include <sys/bus.h> 4291396Stmm#include <sys/kernel.h> 43130026Sphk#include <sys/module.h> 4491396Stmm#include <sys/resource.h> 4591396Stmm#include <sys/socket.h> 4691396Stmm 4791396Stmm#include <machine/bus.h> 48133731Smarius#if defined(__powerpc__) || defined(__sparc64__) 49119696Smarcel#include <dev/ofw/openfirm.h> 5091396Stmm#include <machine/ofw_machdep.h> 51133731Smarius#endif 5291396Stmm#include <machine/resource.h> 5391396Stmm 5491396Stmm#include <sys/rman.h> 5591396Stmm 5691396Stmm#include <net/ethernet.h> 5791396Stmm#include <net/if.h> 5891396Stmm#include <net/if_arp.h> 5991396Stmm#include <net/if_dl.h> 6091396Stmm#include <net/if_media.h> 6191396Stmm 62119351Smarcel#include <dev/mii/mii.h> 63119351Smarcel#include <dev/mii/miivar.h> 6491396Stmm 65119280Simp#include <dev/pci/pcivar.h> 66119280Simp#include <dev/pci/pcireg.h> 6791396Stmm 68119351Smarcel#include <dev/hme/if_hmereg.h> 69119351Smarcel#include <dev/hme/if_hmevar.h> 7091396Stmm 7191396Stmm#include "miibus_if.h" 7291396Stmm 7391396Stmmstruct hme_pci_softc { 7491396Stmm struct hme_softc hsc_hme; /* HME device */ 7591396Stmm struct resource *hsc_sres; 7691396Stmm struct resource *hsc_ires; 7791396Stmm void *hsc_ih; 7891396Stmm}; 7991396Stmm 8091396Stmmstatic int hme_pci_probe(device_t); 8191396Stmmstatic int hme_pci_attach(device_t); 82108976Stmmstatic int hme_pci_detach(device_t); 83108976Stmmstatic int hme_pci_suspend(device_t); 84108976Stmmstatic int hme_pci_resume(device_t); 8591396Stmm 8691396Stmmstatic device_method_t hme_pci_methods[] = { 8791396Stmm /* Device interface */ 8891396Stmm DEVMETHOD(device_probe, hme_pci_probe), 8991396Stmm DEVMETHOD(device_attach, hme_pci_attach), 90108976Stmm DEVMETHOD(device_detach, hme_pci_detach), 91108976Stmm DEVMETHOD(device_suspend, hme_pci_suspend), 92108976Stmm DEVMETHOD(device_resume, hme_pci_resume), 93108976Stmm /* Can just use the suspend method here. */ 94108976Stmm DEVMETHOD(device_shutdown, hme_pci_suspend), 9591396Stmm 9691396Stmm /* MII interface */ 9791396Stmm DEVMETHOD(miibus_readreg, hme_mii_readreg), 9891396Stmm DEVMETHOD(miibus_writereg, hme_mii_writereg), 9991396Stmm DEVMETHOD(miibus_statchg, hme_mii_statchg), 10091396Stmm 101229093Shselasky DEVMETHOD_END 10291396Stmm}; 10391396Stmm 10491396Stmmstatic driver_t hme_pci_driver = { 10591396Stmm "hme", 10691396Stmm hme_pci_methods, 10791396Stmm sizeof(struct hme_pci_softc) 10891396Stmm}; 10991396Stmm 110113506SmdoddDRIVER_MODULE(hme, pci, hme_pci_driver, hme_devclass, 0, 0); 111113506SmdoddMODULE_DEPEND(hme, pci, 1, 1, 1); 112113506SmdoddMODULE_DEPEND(hme, ether, 1, 1, 1); 11391396Stmm 114133731Smarius#define PCI_VENDOR_SUN 0x108e 115133731Smarius#define PCI_PRODUCT_SUN_EBUS 0x1000 116133731Smarius#define PCI_PRODUCT_SUN_HMENETWORK 0x1001 117133731Smarius 11891396Stmmint 11991396Stmmhme_pci_probe(device_t dev) 12091396Stmm{ 12191396Stmm 122133731Smarius if (pci_get_vendor(dev) == PCI_VENDOR_SUN && 123178589Smarius pci_get_device(dev) == PCI_PRODUCT_SUN_HMENETWORK) { 12491396Stmm device_set_desc(dev, "Sun HME 10/100 Ethernet"); 125143161Simp return (BUS_PROBE_DEFAULT); 12691396Stmm } 12791396Stmm return (ENXIO); 12891396Stmm} 12991396Stmm 13091396Stmmint 13191396Stmmhme_pci_attach(device_t dev) 13291396Stmm{ 133178589Smarius struct hme_pci_softc *hsc; 134178589Smarius struct hme_softc *sc; 135178589Smarius bus_space_tag_t memt; 136178589Smarius bus_space_handle_t memh; 137178589Smarius int i, error = 0; 138133731Smarius#if !(defined(__powerpc__) || defined(__sparc64__)) 139133731Smarius device_t *children, ebus_dev; 140133731Smarius struct resource *ebus_rres; 141178589Smarius int j, slot; 142133731Smarius#endif 14391396Stmm 144117116Stmm pci_enable_busmaster(dev); 14591396Stmm /* 146117116Stmm * Some Sun HMEs do have their intpin register bogusly set to 0, 147178589Smarius * although it should be 1. Correct that. 14891396Stmm */ 149117116Stmm if (pci_get_intpin(dev) == 0) 150117116Stmm pci_set_intpin(dev, 1); 15191396Stmm 152178589Smarius hsc = device_get_softc(dev); 153178589Smarius sc = &hsc->hsc_hme; 15491396Stmm sc->sc_dev = dev; 155178470Smarius sc->sc_flags |= HME_PCI; 156137982Syongari mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, 157137982Syongari MTX_DEF); 15891396Stmm 15991396Stmm /* 16091396Stmm * Map five register banks: 16191396Stmm * 16291396Stmm * bank 0: HME SEB registers: +0x0000 16391396Stmm * bank 1: HME ETX registers: +0x2000 16491396Stmm * bank 2: HME ERX registers: +0x4000 16591396Stmm * bank 3: HME MAC registers: +0x6000 16691396Stmm * bank 4: HME MIF registers: +0x7000 16791396Stmm * 16891396Stmm */ 169178589Smarius i = PCIR_BAR(0); 170178589Smarius hsc->hsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 171178589Smarius &i, RF_ACTIVE); 17291396Stmm if (hsc->hsc_sres == NULL) { 17391396Stmm device_printf(dev, "could not map device registers\n"); 174137982Syongari error = ENXIO; 175137982Syongari goto fail_mtx; 17691396Stmm } 177178589Smarius i = 0; 178178589Smarius hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 179178589Smarius &i, RF_SHAREABLE | RF_ACTIVE); 18091396Stmm if (hsc->hsc_ires == NULL) { 18191396Stmm device_printf(dev, "could not allocate interrupt\n"); 18291396Stmm error = ENXIO; 18391396Stmm goto fail_sres; 18491396Stmm } 185178589Smarius memt = rman_get_bustag(hsc->hsc_sres); 186178589Smarius memh = rman_get_bushandle(hsc->hsc_sres); 18791396Stmm sc->sc_sebt = sc->sc_etxt = sc->sc_erxt = sc->sc_mact = sc->sc_mift = 188178589Smarius memt; 189178589Smarius bus_space_subregion(memt, memh, 0x0000, 0x1000, &sc->sc_sebh); 190178589Smarius bus_space_subregion(memt, memh, 0x2000, 0x1000, &sc->sc_etxh); 191178589Smarius bus_space_subregion(memt, memh, 0x4000, 0x1000, &sc->sc_erxh); 192178589Smarius bus_space_subregion(memt, memh, 0x6000, 0x1000, &sc->sc_mach); 193178589Smarius bus_space_subregion(memt, memh, 0x7000, 0x1000, &sc->sc_mifh); 19491396Stmm 195133731Smarius#if defined(__powerpc__) || defined(__sparc64__) 196147256Sbrooks OF_getetheraddr(dev, sc->sc_enaddr); 197133731Smarius#else 198133731Smarius /* 199133731Smarius * Dig out VPD (vital product data) and read NA (network address). 200133731Smarius * 201133731Smarius * The PCI HME is a PCIO chip, which is composed of two functions: 202133731Smarius * function 0: PCI-EBus2 bridge, and 203133731Smarius * function 1: HappyMeal Ethernet controller. 204133731Smarius * 205133731Smarius * The VPD of HME resides in the Boot PROM (PCI FCode) attached 206133731Smarius * to the EBus bridge and can't be accessed via the PCI capability 207133731Smarius * pointer. 208133731Smarius * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) 209133731Smarius * chapter 2 describes the data structure. 210133731Smarius * 211133731Smarius * We don't have a MI EBus driver since no EBus device exists 212178589Smarius * (besides the FCode PROM) on add-on HME boards. The ``no driver 213133731Smarius * attached'' message for function 0 therefore is what is expected. 214133731Smarius */ 21591396Stmm 216178589Smarius#define PCI_ROMHDR_SIZE 0x1c 217178589Smarius#define PCI_ROMHDR_SIG 0x00 218178589Smarius#define PCI_ROMHDR_SIG_MAGIC 0xaa55 /* little endian */ 219178589Smarius#define PCI_ROMHDR_PTR_DATA 0x18 220178589Smarius#define PCI_ROM_SIZE 0x18 221178589Smarius#define PCI_ROM_SIG 0x00 222178589Smarius#define PCI_ROM_SIG_MAGIC 0x52494350 /* "PCIR", endian */ 223178589Smarius /* reversed */ 224178589Smarius#define PCI_ROM_VENDOR 0x04 225178589Smarius#define PCI_ROM_DEVICE 0x06 226178589Smarius#define PCI_ROM_PTR_VPD 0x08 227178589Smarius#define PCI_VPDRES_BYTE0 0x00 228178589Smarius#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) 229178589Smarius#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) 230178589Smarius#define PCI_VPDRES_TYPE_VPD 0x10 /* large */ 231178589Smarius#define PCI_VPDRES_LARGE_LEN_LSB 0x01 232178589Smarius#define PCI_VPDRES_LARGE_LEN_MSB 0x02 233178589Smarius#define PCI_VPDRES_LARGE_DATA 0x03 234178589Smarius#define PCI_VPD_SIZE 0x03 235178589Smarius#define PCI_VPD_KEY0 0x00 236178589Smarius#define PCI_VPD_KEY1 0x01 237178589Smarius#define PCI_VPD_LEN 0x02 238178589Smarius#define PCI_VPD_DATA 0x03 239178589Smarius 240178589Smarius#define HME_ROM_READ_N(n, offs) bus_space_read_ ## n (memt, memh, (offs)) 241178589Smarius#define HME_ROM_READ_1(offs) HME_ROM_READ_N(1, (offs)) 242178589Smarius#define HME_ROM_READ_2(offs) HME_ROM_READ_N(2, (offs)) 243178589Smarius#define HME_ROM_READ_4(offs) HME_ROM_READ_N(4, (offs)) 244178589Smarius 245133731Smarius /* Search accompanying EBus bridge. */ 246133731Smarius slot = pci_get_slot(dev); 247178589Smarius if (device_get_children(device_get_parent(dev), &children, &i) != 0) { 248133731Smarius device_printf(dev, "could not get children\n"); 249133731Smarius error = ENXIO; 250133731Smarius goto fail_sres; 251133731Smarius } 252133731Smarius ebus_dev = NULL; 253178589Smarius for (j = 0; j < i; j++) { 254178589Smarius if (pci_get_class(children[j]) == PCIC_BRIDGE && 255178589Smarius pci_get_vendor(children[j]) == PCI_VENDOR_SUN && 256178589Smarius pci_get_device(children[j]) == PCI_PRODUCT_SUN_EBUS && 257178589Smarius pci_get_slot(children[j]) == slot) { 258178589Smarius ebus_dev = children[j]; 259133731Smarius break; 260133731Smarius } 261133731Smarius } 262133731Smarius if (ebus_dev == NULL) { 263133731Smarius device_printf(dev, "could not find EBus bridge\n"); 264133731Smarius error = ENXIO; 265133731Smarius goto fail_children; 266133731Smarius } 267133731Smarius 268133731Smarius /* Map EBus bridge PROM registers. */ 269178589Smarius i = PCIR_BAR(0); 270133731Smarius if ((ebus_rres = bus_alloc_resource_any(ebus_dev, SYS_RES_MEMORY, 271178589Smarius &i, RF_ACTIVE)) == NULL) { 272133731Smarius device_printf(dev, "could not map PROM registers\n"); 273133731Smarius error = ENXIO; 274133731Smarius goto fail_children; 275133731Smarius } 276178589Smarius memt = rman_get_bustag(ebus_rres); 277178589Smarius memh = rman_get_bushandle(ebus_rres); 278133731Smarius 279178589Smarius /* Read PCI Expansion ROM header. */ 280178589Smarius if (HME_ROM_READ_2(PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC || 281178589Smarius (i = HME_ROM_READ_2(PCI_ROMHDR_PTR_DATA)) < PCI_ROMHDR_SIZE) { 282178589Smarius device_printf(dev, "unexpected PCI Expansion ROM header\n"); 283133731Smarius error = ENXIO; 284133731Smarius goto fail_rres; 285133731Smarius } 286133731Smarius 287178589Smarius /* Read PCI Expansion ROM data. */ 288178589Smarius if (HME_ROM_READ_4(i + PCI_ROM_SIG) != PCI_ROM_SIG_MAGIC || 289178589Smarius HME_ROM_READ_2(i + PCI_ROM_VENDOR) != pci_get_vendor(dev) || 290178589Smarius HME_ROM_READ_2(i + PCI_ROM_DEVICE) != pci_get_device(dev) || 291178589Smarius (j = HME_ROM_READ_2(i + PCI_ROM_PTR_VPD)) < i + PCI_ROM_SIZE) { 292178589Smarius device_printf(dev, "unexpected PCI Expansion ROM data\n"); 293133731Smarius error = ENXIO; 294133731Smarius goto fail_rres; 295133731Smarius } 296133731Smarius 297133731Smarius /* 298133731Smarius * Read PCI VPD. 299138712Smarius * SUNW,hme cards have a single large resource VPD-R tag 300178589Smarius * containing one NA. SUNW,qfe cards have four large resource 301142117Smarius * VPD-R tags containing one NA each (all four HME chips share 302142117Smarius * the same PROM). 303138712Smarius * The VPD used on both cards is not in PCI 2.2 standard format 304178589Smarius * however. The length in the resource header is in big endian 305138712Smarius * and the end tag is non-standard (0x79) and followed by an 306178589Smarius * all-zero "checksum" byte. Sun calls this a "Fresh Choice 307138712Smarius * Ethernet" VPD... 308133731Smarius */ 309142964Smarius /* Look at the end tag to determine whether this is a VPD with 4 NAs. */ 310178589Smarius if (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 311178589Smarius ETHER_ADDR_LEN) != 0x79 && 312178589Smarius HME_ROM_READ_1(j + 4 * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 313178589Smarius ETHER_ADDR_LEN)) == 0x79) 314142964Smarius /* Use the Nth NA for the Nth HME on this SUNW,qfe. */ 315178589Smarius j += slot * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 316178589Smarius ETHER_ADDR_LEN); 317178589Smarius if (PCI_VPDRES_ISLARGE(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) == 0 || 318178589Smarius PCI_VPDRES_LARGE_NAME(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) != 319178589Smarius PCI_VPDRES_TYPE_VPD || 320178589Smarius (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_LSB) << 8 | 321178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_MSB)) != 322178589Smarius PCI_VPD_SIZE + ETHER_ADDR_LEN || 323178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY0) != 324178589Smarius 0x4e /* N */ || 325178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY1) != 326178589Smarius 0x41 /* A */ || 327178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_LEN) != 328178589Smarius ETHER_ADDR_LEN) { 329133731Smarius device_printf(dev, "unexpected PCI VPD\n"); 330133731Smarius error = ENXIO; 331133731Smarius goto fail_rres; 332133731Smarius } 333178589Smarius bus_space_read_region_1(memt, memh, j + PCI_VPDRES_LARGE_DATA + 334178589Smarius PCI_VPD_DATA, sc->sc_enaddr, ETHER_ADDR_LEN); 335133731Smarius 336133731Smariusfail_rres: 337178589Smarius bus_release_resource(ebus_dev, SYS_RES_MEMORY, 338178589Smarius rman_get_rid(ebus_rres), ebus_rres); 339133731Smariusfail_children: 340133731Smarius free(children, M_TEMP); 341133731Smarius if (error != 0) 342133731Smarius goto fail_sres; 343133731Smarius#endif 344133731Smarius 34591396Stmm sc->sc_burst = 64; /* XXX */ 34691396Stmm 34791396Stmm /* 34891396Stmm * call the main configure 34991396Stmm */ 35091396Stmm if ((error = hme_config(sc)) != 0) { 35191396Stmm device_printf(dev, "could not be configured\n"); 35291396Stmm goto fail_ires; 35391396Stmm } 35491396Stmm 355137982Syongari if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET | 356166901Spiso INTR_MPSAFE, NULL, hme_intr, sc, &hsc->hsc_ih)) != 0) { 35791396Stmm device_printf(dev, "couldn't establish interrupt\n"); 358108976Stmm hme_detach(sc); 35991396Stmm goto fail_ires; 36091396Stmm } 36191396Stmm return (0); 36291396Stmm 36391396Stmmfail_ires: 364178589Smarius bus_release_resource(dev, SYS_RES_IRQ, 365178589Smarius rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 36691396Stmmfail_sres: 367178589Smarius bus_release_resource(dev, SYS_RES_MEMORY, 368178589Smarius rman_get_rid(hsc->hsc_sres), hsc->hsc_sres); 369137982Syongarifail_mtx: 370137982Syongari mtx_destroy(&sc->sc_lock); 371133599Smarius return (error); 37291396Stmm} 373108976Stmm 374108976Stmmstatic int 375108976Stmmhme_pci_detach(device_t dev) 376108976Stmm{ 377178589Smarius struct hme_pci_softc *hsc; 378178589Smarius struct hme_softc *sc; 379108976Stmm 380178589Smarius hsc = device_get_softc(dev); 381178589Smarius sc = &hsc->hsc_hme; 382137982Syongari bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih); 383108976Stmm hme_detach(sc); 384178589Smarius bus_release_resource(dev, SYS_RES_IRQ, 385178589Smarius rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 386178589Smarius bus_release_resource(dev, SYS_RES_MEMORY, 387178589Smarius rman_get_rid(hsc->hsc_sres), hsc->hsc_sres); 388147878Smarius mtx_destroy(&sc->sc_lock); 389108976Stmm return (0); 390108976Stmm} 391108976Stmm 392108976Stmmstatic int 393108976Stmmhme_pci_suspend(device_t dev) 394108976Stmm{ 395178589Smarius struct hme_pci_softc *hsc; 396108976Stmm 397178589Smarius hsc = device_get_softc(dev); 398178589Smarius hme_suspend(&hsc->hsc_hme); 399108976Stmm return (0); 400108976Stmm} 401108976Stmm 402108976Stmmstatic int 403108976Stmmhme_pci_resume(device_t dev) 404108976Stmm{ 405178589Smarius struct hme_pci_softc *hsc; 406108976Stmm 407178589Smarius hsc = device_get_softc(dev); 408178589Smarius hme_resume(&hsc->hsc_hme); 409108976Stmm return (0); 410108976Stmm} 411