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> 43257176Sglebius#include <sys/lock.h> 44257176Sglebius#include <sys/malloc.h> 45130026Sphk#include <sys/module.h> 46257176Sglebius#include <sys/mutex.h> 4791396Stmm#include <sys/resource.h> 4891396Stmm#include <sys/socket.h> 4991396Stmm 5091396Stmm#include <machine/bus.h> 51133731Smarius#if defined(__powerpc__) || defined(__sparc64__) 52119696Smarcel#include <dev/ofw/openfirm.h> 5391396Stmm#include <machine/ofw_machdep.h> 54133731Smarius#endif 5591396Stmm#include <machine/resource.h> 5691396Stmm 5791396Stmm#include <sys/rman.h> 5891396Stmm 5991396Stmm#include <net/ethernet.h> 6091396Stmm#include <net/if.h> 6191396Stmm#include <net/if_arp.h> 6291396Stmm#include <net/if_dl.h> 6391396Stmm#include <net/if_media.h> 6491396Stmm 65119351Smarcel#include <dev/mii/mii.h> 66119351Smarcel#include <dev/mii/miivar.h> 6791396Stmm 68119280Simp#include <dev/pci/pcivar.h> 69119280Simp#include <dev/pci/pcireg.h> 7091396Stmm 71119351Smarcel#include <dev/hme/if_hmereg.h> 72119351Smarcel#include <dev/hme/if_hmevar.h> 7391396Stmm 7491396Stmm#include "miibus_if.h" 7591396Stmm 7691396Stmmstruct hme_pci_softc { 7791396Stmm struct hme_softc hsc_hme; /* HME device */ 7891396Stmm struct resource *hsc_sres; 7991396Stmm struct resource *hsc_ires; 8091396Stmm void *hsc_ih; 8191396Stmm}; 8291396Stmm 8391396Stmmstatic int hme_pci_probe(device_t); 8491396Stmmstatic int hme_pci_attach(device_t); 85108976Stmmstatic int hme_pci_detach(device_t); 86108976Stmmstatic int hme_pci_suspend(device_t); 87108976Stmmstatic int hme_pci_resume(device_t); 8891396Stmm 8991396Stmmstatic device_method_t hme_pci_methods[] = { 9091396Stmm /* Device interface */ 9191396Stmm DEVMETHOD(device_probe, hme_pci_probe), 9291396Stmm DEVMETHOD(device_attach, hme_pci_attach), 93108976Stmm DEVMETHOD(device_detach, hme_pci_detach), 94108976Stmm DEVMETHOD(device_suspend, hme_pci_suspend), 95108976Stmm DEVMETHOD(device_resume, hme_pci_resume), 96108976Stmm /* Can just use the suspend method here. */ 97108976Stmm DEVMETHOD(device_shutdown, hme_pci_suspend), 9891396Stmm 9991396Stmm /* MII interface */ 10091396Stmm DEVMETHOD(miibus_readreg, hme_mii_readreg), 10191396Stmm DEVMETHOD(miibus_writereg, hme_mii_writereg), 10291396Stmm DEVMETHOD(miibus_statchg, hme_mii_statchg), 10391396Stmm 104227843Smarius DEVMETHOD_END 10591396Stmm}; 10691396Stmm 10791396Stmmstatic driver_t hme_pci_driver = { 10891396Stmm "hme", 10991396Stmm hme_pci_methods, 11091396Stmm sizeof(struct hme_pci_softc) 11191396Stmm}; 11291396Stmm 113113506SmdoddDRIVER_MODULE(hme, pci, hme_pci_driver, hme_devclass, 0, 0); 114113506SmdoddMODULE_DEPEND(hme, pci, 1, 1, 1); 115113506SmdoddMODULE_DEPEND(hme, ether, 1, 1, 1); 11691396Stmm 117133731Smarius#define PCI_VENDOR_SUN 0x108e 118133731Smarius#define PCI_PRODUCT_SUN_EBUS 0x1000 119133731Smarius#define PCI_PRODUCT_SUN_HMENETWORK 0x1001 120133731Smarius 12191396Stmmint 12291396Stmmhme_pci_probe(device_t dev) 12391396Stmm{ 12491396Stmm 125133731Smarius if (pci_get_vendor(dev) == PCI_VENDOR_SUN && 126178589Smarius pci_get_device(dev) == PCI_PRODUCT_SUN_HMENETWORK) { 12791396Stmm device_set_desc(dev, "Sun HME 10/100 Ethernet"); 128143161Simp return (BUS_PROBE_DEFAULT); 12991396Stmm } 13091396Stmm return (ENXIO); 13191396Stmm} 13291396Stmm 13391396Stmmint 13491396Stmmhme_pci_attach(device_t dev) 13591396Stmm{ 136178589Smarius struct hme_pci_softc *hsc; 137178589Smarius struct hme_softc *sc; 138178589Smarius bus_space_tag_t memt; 139178589Smarius bus_space_handle_t memh; 140178589Smarius int i, error = 0; 141133731Smarius#if !(defined(__powerpc__) || defined(__sparc64__)) 142133731Smarius device_t *children, ebus_dev; 143133731Smarius struct resource *ebus_rres; 144178589Smarius int j, slot; 145133731Smarius#endif 14691396Stmm 147117116Stmm pci_enable_busmaster(dev); 14891396Stmm /* 149117116Stmm * Some Sun HMEs do have their intpin register bogusly set to 0, 150178589Smarius * although it should be 1. Correct that. 15191396Stmm */ 152117116Stmm if (pci_get_intpin(dev) == 0) 153117116Stmm pci_set_intpin(dev, 1); 15491396Stmm 155178589Smarius hsc = device_get_softc(dev); 156178589Smarius sc = &hsc->hsc_hme; 15791396Stmm sc->sc_dev = dev; 158178470Smarius sc->sc_flags |= HME_PCI; 159137982Syongari mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, 160137982Syongari MTX_DEF); 16191396Stmm 16291396Stmm /* 16391396Stmm * Map five register banks: 16491396Stmm * 16591396Stmm * bank 0: HME SEB registers: +0x0000 16691396Stmm * bank 1: HME ETX registers: +0x2000 16791396Stmm * bank 2: HME ERX registers: +0x4000 16891396Stmm * bank 3: HME MAC registers: +0x6000 16991396Stmm * bank 4: HME MIF registers: +0x7000 17091396Stmm * 17191396Stmm */ 172178589Smarius i = PCIR_BAR(0); 173178589Smarius hsc->hsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 174178589Smarius &i, RF_ACTIVE); 17591396Stmm if (hsc->hsc_sres == NULL) { 17691396Stmm device_printf(dev, "could not map device registers\n"); 177137982Syongari error = ENXIO; 178137982Syongari goto fail_mtx; 17991396Stmm } 180178589Smarius i = 0; 181178589Smarius hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 182178589Smarius &i, RF_SHAREABLE | RF_ACTIVE); 18391396Stmm if (hsc->hsc_ires == NULL) { 18491396Stmm device_printf(dev, "could not allocate interrupt\n"); 18591396Stmm error = ENXIO; 18691396Stmm goto fail_sres; 18791396Stmm } 188178589Smarius memt = rman_get_bustag(hsc->hsc_sres); 189178589Smarius memh = rman_get_bushandle(hsc->hsc_sres); 19091396Stmm sc->sc_sebt = sc->sc_etxt = sc->sc_erxt = sc->sc_mact = sc->sc_mift = 191178589Smarius memt; 192178589Smarius bus_space_subregion(memt, memh, 0x0000, 0x1000, &sc->sc_sebh); 193178589Smarius bus_space_subregion(memt, memh, 0x2000, 0x1000, &sc->sc_etxh); 194178589Smarius bus_space_subregion(memt, memh, 0x4000, 0x1000, &sc->sc_erxh); 195178589Smarius bus_space_subregion(memt, memh, 0x6000, 0x1000, &sc->sc_mach); 196178589Smarius bus_space_subregion(memt, memh, 0x7000, 0x1000, &sc->sc_mifh); 19791396Stmm 198133731Smarius#if defined(__powerpc__) || defined(__sparc64__) 199147256Sbrooks OF_getetheraddr(dev, sc->sc_enaddr); 200133731Smarius#else 201133731Smarius /* 202133731Smarius * Dig out VPD (vital product data) and read NA (network address). 203133731Smarius * 204133731Smarius * The PCI HME is a PCIO chip, which is composed of two functions: 205133731Smarius * function 0: PCI-EBus2 bridge, and 206133731Smarius * function 1: HappyMeal Ethernet controller. 207133731Smarius * 208133731Smarius * The VPD of HME resides in the Boot PROM (PCI FCode) attached 209133731Smarius * to the EBus bridge and can't be accessed via the PCI capability 210133731Smarius * pointer. 211133731Smarius * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) 212133731Smarius * chapter 2 describes the data structure. 213133731Smarius * 214133731Smarius * We don't have a MI EBus driver since no EBus device exists 215178589Smarius * (besides the FCode PROM) on add-on HME boards. The ``no driver 216133731Smarius * attached'' message for function 0 therefore is what is expected. 217133731Smarius */ 21891396Stmm 219178589Smarius#define PCI_ROMHDR_SIZE 0x1c 220178589Smarius#define PCI_ROMHDR_SIG 0x00 221178589Smarius#define PCI_ROMHDR_SIG_MAGIC 0xaa55 /* little endian */ 222178589Smarius#define PCI_ROMHDR_PTR_DATA 0x18 223178589Smarius#define PCI_ROM_SIZE 0x18 224178589Smarius#define PCI_ROM_SIG 0x00 225178589Smarius#define PCI_ROM_SIG_MAGIC 0x52494350 /* "PCIR", endian */ 226178589Smarius /* reversed */ 227178589Smarius#define PCI_ROM_VENDOR 0x04 228178589Smarius#define PCI_ROM_DEVICE 0x06 229178589Smarius#define PCI_ROM_PTR_VPD 0x08 230178589Smarius#define PCI_VPDRES_BYTE0 0x00 231178589Smarius#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) 232178589Smarius#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) 233178589Smarius#define PCI_VPDRES_TYPE_VPD 0x10 /* large */ 234178589Smarius#define PCI_VPDRES_LARGE_LEN_LSB 0x01 235178589Smarius#define PCI_VPDRES_LARGE_LEN_MSB 0x02 236178589Smarius#define PCI_VPDRES_LARGE_DATA 0x03 237178589Smarius#define PCI_VPD_SIZE 0x03 238178589Smarius#define PCI_VPD_KEY0 0x00 239178589Smarius#define PCI_VPD_KEY1 0x01 240178589Smarius#define PCI_VPD_LEN 0x02 241178589Smarius#define PCI_VPD_DATA 0x03 242178589Smarius 243178589Smarius#define HME_ROM_READ_N(n, offs) bus_space_read_ ## n (memt, memh, (offs)) 244178589Smarius#define HME_ROM_READ_1(offs) HME_ROM_READ_N(1, (offs)) 245178589Smarius#define HME_ROM_READ_2(offs) HME_ROM_READ_N(2, (offs)) 246178589Smarius#define HME_ROM_READ_4(offs) HME_ROM_READ_N(4, (offs)) 247178589Smarius 248133731Smarius /* Search accompanying EBus bridge. */ 249133731Smarius slot = pci_get_slot(dev); 250178589Smarius if (device_get_children(device_get_parent(dev), &children, &i) != 0) { 251133731Smarius device_printf(dev, "could not get children\n"); 252133731Smarius error = ENXIO; 253133731Smarius goto fail_sres; 254133731Smarius } 255133731Smarius ebus_dev = NULL; 256178589Smarius for (j = 0; j < i; j++) { 257178589Smarius if (pci_get_class(children[j]) == PCIC_BRIDGE && 258178589Smarius pci_get_vendor(children[j]) == PCI_VENDOR_SUN && 259178589Smarius pci_get_device(children[j]) == PCI_PRODUCT_SUN_EBUS && 260178589Smarius pci_get_slot(children[j]) == slot) { 261178589Smarius ebus_dev = children[j]; 262133731Smarius break; 263133731Smarius } 264133731Smarius } 265133731Smarius if (ebus_dev == NULL) { 266133731Smarius device_printf(dev, "could not find EBus bridge\n"); 267133731Smarius error = ENXIO; 268133731Smarius goto fail_children; 269133731Smarius } 270133731Smarius 271133731Smarius /* Map EBus bridge PROM registers. */ 272178589Smarius i = PCIR_BAR(0); 273133731Smarius if ((ebus_rres = bus_alloc_resource_any(ebus_dev, SYS_RES_MEMORY, 274178589Smarius &i, RF_ACTIVE)) == NULL) { 275133731Smarius device_printf(dev, "could not map PROM registers\n"); 276133731Smarius error = ENXIO; 277133731Smarius goto fail_children; 278133731Smarius } 279178589Smarius memt = rman_get_bustag(ebus_rres); 280178589Smarius memh = rman_get_bushandle(ebus_rres); 281133731Smarius 282178589Smarius /* Read PCI Expansion ROM header. */ 283178589Smarius if (HME_ROM_READ_2(PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC || 284178589Smarius (i = HME_ROM_READ_2(PCI_ROMHDR_PTR_DATA)) < PCI_ROMHDR_SIZE) { 285178589Smarius device_printf(dev, "unexpected PCI Expansion ROM header\n"); 286133731Smarius error = ENXIO; 287133731Smarius goto fail_rres; 288133731Smarius } 289133731Smarius 290178589Smarius /* Read PCI Expansion ROM data. */ 291178589Smarius if (HME_ROM_READ_4(i + PCI_ROM_SIG) != PCI_ROM_SIG_MAGIC || 292178589Smarius HME_ROM_READ_2(i + PCI_ROM_VENDOR) != pci_get_vendor(dev) || 293178589Smarius HME_ROM_READ_2(i + PCI_ROM_DEVICE) != pci_get_device(dev) || 294178589Smarius (j = HME_ROM_READ_2(i + PCI_ROM_PTR_VPD)) < i + PCI_ROM_SIZE) { 295178589Smarius device_printf(dev, "unexpected PCI Expansion ROM data\n"); 296133731Smarius error = ENXIO; 297133731Smarius goto fail_rres; 298133731Smarius } 299133731Smarius 300133731Smarius /* 301133731Smarius * Read PCI VPD. 302138712Smarius * SUNW,hme cards have a single large resource VPD-R tag 303178589Smarius * containing one NA. SUNW,qfe cards have four large resource 304142117Smarius * VPD-R tags containing one NA each (all four HME chips share 305142117Smarius * the same PROM). 306138712Smarius * The VPD used on both cards is not in PCI 2.2 standard format 307178589Smarius * however. The length in the resource header is in big endian 308138712Smarius * and the end tag is non-standard (0x79) and followed by an 309178589Smarius * all-zero "checksum" byte. Sun calls this a "Fresh Choice 310138712Smarius * Ethernet" VPD... 311133731Smarius */ 312142964Smarius /* Look at the end tag to determine whether this is a VPD with 4 NAs. */ 313178589Smarius if (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 314178589Smarius ETHER_ADDR_LEN) != 0x79 && 315178589Smarius HME_ROM_READ_1(j + 4 * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 316178589Smarius ETHER_ADDR_LEN)) == 0x79) 317142964Smarius /* Use the Nth NA for the Nth HME on this SUNW,qfe. */ 318178589Smarius j += slot * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 319178589Smarius ETHER_ADDR_LEN); 320178589Smarius if (PCI_VPDRES_ISLARGE(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) == 0 || 321178589Smarius PCI_VPDRES_LARGE_NAME(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) != 322178589Smarius PCI_VPDRES_TYPE_VPD || 323178589Smarius (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_LSB) << 8 | 324178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_MSB)) != 325178589Smarius PCI_VPD_SIZE + ETHER_ADDR_LEN || 326178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY0) != 327178589Smarius 0x4e /* N */ || 328178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY1) != 329178589Smarius 0x41 /* A */ || 330178589Smarius HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_LEN) != 331178589Smarius ETHER_ADDR_LEN) { 332133731Smarius device_printf(dev, "unexpected PCI VPD\n"); 333133731Smarius error = ENXIO; 334133731Smarius goto fail_rres; 335133731Smarius } 336178589Smarius bus_space_read_region_1(memt, memh, j + PCI_VPDRES_LARGE_DATA + 337178589Smarius PCI_VPD_DATA, sc->sc_enaddr, ETHER_ADDR_LEN); 338133731Smarius 339133731Smariusfail_rres: 340178589Smarius bus_release_resource(ebus_dev, SYS_RES_MEMORY, 341178589Smarius rman_get_rid(ebus_rres), ebus_rres); 342133731Smariusfail_children: 343133731Smarius free(children, M_TEMP); 344133731Smarius if (error != 0) 345133731Smarius goto fail_sres; 346133731Smarius#endif 347133731Smarius 34891396Stmm sc->sc_burst = 64; /* XXX */ 34991396Stmm 35091396Stmm /* 35191396Stmm * call the main configure 35291396Stmm */ 35391396Stmm if ((error = hme_config(sc)) != 0) { 35491396Stmm device_printf(dev, "could not be configured\n"); 35591396Stmm goto fail_ires; 35691396Stmm } 35791396Stmm 358137982Syongari if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET | 359166901Spiso INTR_MPSAFE, NULL, hme_intr, sc, &hsc->hsc_ih)) != 0) { 36091396Stmm device_printf(dev, "couldn't establish interrupt\n"); 361108976Stmm hme_detach(sc); 36291396Stmm goto fail_ires; 36391396Stmm } 36491396Stmm return (0); 36591396Stmm 36691396Stmmfail_ires: 367178589Smarius bus_release_resource(dev, SYS_RES_IRQ, 368178589Smarius rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 36991396Stmmfail_sres: 370178589Smarius bus_release_resource(dev, SYS_RES_MEMORY, 371178589Smarius rman_get_rid(hsc->hsc_sres), hsc->hsc_sres); 372137982Syongarifail_mtx: 373137982Syongari mtx_destroy(&sc->sc_lock); 374133599Smarius return (error); 37591396Stmm} 376108976Stmm 377108976Stmmstatic int 378108976Stmmhme_pci_detach(device_t dev) 379108976Stmm{ 380178589Smarius struct hme_pci_softc *hsc; 381178589Smarius struct hme_softc *sc; 382108976Stmm 383178589Smarius hsc = device_get_softc(dev); 384178589Smarius sc = &hsc->hsc_hme; 385137982Syongari bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih); 386108976Stmm hme_detach(sc); 387178589Smarius bus_release_resource(dev, SYS_RES_IRQ, 388178589Smarius rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 389178589Smarius bus_release_resource(dev, SYS_RES_MEMORY, 390178589Smarius rman_get_rid(hsc->hsc_sres), hsc->hsc_sres); 391147878Smarius mtx_destroy(&sc->sc_lock); 392108976Stmm return (0); 393108976Stmm} 394108976Stmm 395108976Stmmstatic int 396108976Stmmhme_pci_suspend(device_t dev) 397108976Stmm{ 398178589Smarius struct hme_pci_softc *hsc; 399108976Stmm 400178589Smarius hsc = device_get_softc(dev); 401178589Smarius hme_suspend(&hsc->hsc_hme); 402108976Stmm return (0); 403108976Stmm} 404108976Stmm 405108976Stmmstatic int 406108976Stmmhme_pci_resume(device_t dev) 407108976Stmm{ 408178589Smarius struct hme_pci_softc *hsc; 409108976Stmm 410178589Smarius hsc = device_get_softc(dev); 411178589Smarius hme_resume(&hsc->hsc_hme); 412108976Stmm return (0); 413108976Stmm} 414