1/*- 2 * Copyright (c) 2000 Matthew R. Green 3 * Copyright (c) 2007 Marius Strobl <marius@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * from: NetBSD: if_hme_pci.c,v 1.14 2004/03/17 08:58:23 martin Exp 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35/* 36 * PCI front-end device driver for the HME ethernet device. 37 */ 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/bus.h> 42#include <sys/kernel.h> 43#include <sys/lock.h> 44#include <sys/malloc.h> 45#include <sys/module.h> 46#include <sys/mutex.h> 47#include <sys/resource.h> 48#include <sys/socket.h> 49 50#include <machine/bus.h> 51#if defined(__powerpc__) || defined(__sparc64__) 52#include <dev/ofw/openfirm.h> 53#include <machine/ofw_machdep.h> 54#endif 55#include <machine/resource.h> 56 57#include <sys/rman.h> 58 59#include <net/ethernet.h> 60#include <net/if.h> 61#include <net/if_arp.h> 62#include <net/if_dl.h> 63#include <net/if_media.h> 64 65#include <dev/mii/mii.h> 66#include <dev/mii/miivar.h> 67 68#include <dev/pci/pcivar.h> 69#include <dev/pci/pcireg.h> 70 71#include <dev/hme/if_hmereg.h> 72#include <dev/hme/if_hmevar.h> 73 74#include "miibus_if.h" 75 76struct hme_pci_softc { 77 struct hme_softc hsc_hme; /* HME device */ 78 struct resource *hsc_sres; 79 struct resource *hsc_ires; 80 void *hsc_ih; 81}; 82 83static int hme_pci_probe(device_t); 84static int hme_pci_attach(device_t); 85static int hme_pci_detach(device_t); 86static int hme_pci_suspend(device_t); 87static int hme_pci_resume(device_t); 88 89static device_method_t hme_pci_methods[] = { 90 /* Device interface */ 91 DEVMETHOD(device_probe, hme_pci_probe), 92 DEVMETHOD(device_attach, hme_pci_attach), 93 DEVMETHOD(device_detach, hme_pci_detach), 94 DEVMETHOD(device_suspend, hme_pci_suspend), 95 DEVMETHOD(device_resume, hme_pci_resume), 96 /* Can just use the suspend method here. */ 97 DEVMETHOD(device_shutdown, hme_pci_suspend), 98 99 /* MII interface */ 100 DEVMETHOD(miibus_readreg, hme_mii_readreg), 101 DEVMETHOD(miibus_writereg, hme_mii_writereg), 102 DEVMETHOD(miibus_statchg, hme_mii_statchg), 103 104 DEVMETHOD_END 105}; 106 107static driver_t hme_pci_driver = { 108 "hme", 109 hme_pci_methods, 110 sizeof(struct hme_pci_softc) 111}; 112 113DRIVER_MODULE(hme, pci, hme_pci_driver, hme_devclass, 0, 0); 114MODULE_DEPEND(hme, pci, 1, 1, 1); 115MODULE_DEPEND(hme, ether, 1, 1, 1); 116 117#define PCI_VENDOR_SUN 0x108e 118#define PCI_PRODUCT_SUN_EBUS 0x1000 119#define PCI_PRODUCT_SUN_HMENETWORK 0x1001 120 121int 122hme_pci_probe(device_t dev) 123{ 124 125 if (pci_get_vendor(dev) == PCI_VENDOR_SUN && 126 pci_get_device(dev) == PCI_PRODUCT_SUN_HMENETWORK) { 127 device_set_desc(dev, "Sun HME 10/100 Ethernet"); 128 return (BUS_PROBE_DEFAULT); 129 } 130 return (ENXIO); 131} 132 133int 134hme_pci_attach(device_t dev) 135{ 136 struct hme_pci_softc *hsc; 137 struct hme_softc *sc; 138 bus_space_tag_t memt; 139 bus_space_handle_t memh; 140 int i, error = 0; 141#if !(defined(__powerpc__) || defined(__sparc64__)) 142 device_t *children, ebus_dev; 143 struct resource *ebus_rres; 144 int j, slot; 145#endif 146 147 pci_enable_busmaster(dev); 148 /* 149 * Some Sun HMEs do have their intpin register bogusly set to 0, 150 * although it should be 1. Correct that. 151 */ 152 if (pci_get_intpin(dev) == 0) 153 pci_set_intpin(dev, 1); 154 155 hsc = device_get_softc(dev); 156 sc = &hsc->hsc_hme; 157 sc->sc_dev = dev; 158 sc->sc_flags |= HME_PCI; 159 mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, 160 MTX_DEF); 161 162 /* 163 * Map five register banks: 164 * 165 * bank 0: HME SEB registers: +0x0000 166 * bank 1: HME ETX registers: +0x2000 167 * bank 2: HME ERX registers: +0x4000 168 * bank 3: HME MAC registers: +0x6000 169 * bank 4: HME MIF registers: +0x7000 170 * 171 */ 172 i = PCIR_BAR(0); 173 hsc->hsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 174 &i, RF_ACTIVE); 175 if (hsc->hsc_sres == NULL) { 176 device_printf(dev, "could not map device registers\n"); 177 error = ENXIO; 178 goto fail_mtx; 179 } 180 i = 0; 181 hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 182 &i, RF_SHAREABLE | RF_ACTIVE); 183 if (hsc->hsc_ires == NULL) { 184 device_printf(dev, "could not allocate interrupt\n"); 185 error = ENXIO; 186 goto fail_sres; 187 } 188 memt = rman_get_bustag(hsc->hsc_sres); 189 memh = rman_get_bushandle(hsc->hsc_sres); 190 sc->sc_sebt = sc->sc_etxt = sc->sc_erxt = sc->sc_mact = sc->sc_mift = 191 memt; 192 bus_space_subregion(memt, memh, 0x0000, 0x1000, &sc->sc_sebh); 193 bus_space_subregion(memt, memh, 0x2000, 0x1000, &sc->sc_etxh); 194 bus_space_subregion(memt, memh, 0x4000, 0x1000, &sc->sc_erxh); 195 bus_space_subregion(memt, memh, 0x6000, 0x1000, &sc->sc_mach); 196 bus_space_subregion(memt, memh, 0x7000, 0x1000, &sc->sc_mifh); 197 198#if defined(__powerpc__) || defined(__sparc64__) 199 OF_getetheraddr(dev, sc->sc_enaddr); 200#else 201 /* 202 * Dig out VPD (vital product data) and read NA (network address). 203 * 204 * The PCI HME is a PCIO chip, which is composed of two functions: 205 * function 0: PCI-EBus2 bridge, and 206 * function 1: HappyMeal Ethernet controller. 207 * 208 * The VPD of HME resides in the Boot PROM (PCI FCode) attached 209 * to the EBus bridge and can't be accessed via the PCI capability 210 * pointer. 211 * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) 212 * chapter 2 describes the data structure. 213 * 214 * We don't have a MI EBus driver since no EBus device exists 215 * (besides the FCode PROM) on add-on HME boards. The ``no driver 216 * attached'' message for function 0 therefore is what is expected. 217 */ 218 219#define PCI_ROMHDR_SIZE 0x1c 220#define PCI_ROMHDR_SIG 0x00 221#define PCI_ROMHDR_SIG_MAGIC 0xaa55 /* little endian */ 222#define PCI_ROMHDR_PTR_DATA 0x18 223#define PCI_ROM_SIZE 0x18 224#define PCI_ROM_SIG 0x00 225#define PCI_ROM_SIG_MAGIC 0x52494350 /* "PCIR", endian */ 226 /* reversed */ 227#define PCI_ROM_VENDOR 0x04 228#define PCI_ROM_DEVICE 0x06 229#define PCI_ROM_PTR_VPD 0x08 230#define PCI_VPDRES_BYTE0 0x00 231#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) 232#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) 233#define PCI_VPDRES_TYPE_VPD 0x10 /* large */ 234#define PCI_VPDRES_LARGE_LEN_LSB 0x01 235#define PCI_VPDRES_LARGE_LEN_MSB 0x02 236#define PCI_VPDRES_LARGE_DATA 0x03 237#define PCI_VPD_SIZE 0x03 238#define PCI_VPD_KEY0 0x00 239#define PCI_VPD_KEY1 0x01 240#define PCI_VPD_LEN 0x02 241#define PCI_VPD_DATA 0x03 242 243#define HME_ROM_READ_N(n, offs) bus_space_read_ ## n (memt, memh, (offs)) 244#define HME_ROM_READ_1(offs) HME_ROM_READ_N(1, (offs)) 245#define HME_ROM_READ_2(offs) HME_ROM_READ_N(2, (offs)) 246#define HME_ROM_READ_4(offs) HME_ROM_READ_N(4, (offs)) 247 248 /* Search accompanying EBus bridge. */ 249 slot = pci_get_slot(dev); 250 if (device_get_children(device_get_parent(dev), &children, &i) != 0) { 251 device_printf(dev, "could not get children\n"); 252 error = ENXIO; 253 goto fail_sres; 254 } 255 ebus_dev = NULL; 256 for (j = 0; j < i; j++) { 257 if (pci_get_class(children[j]) == PCIC_BRIDGE && 258 pci_get_vendor(children[j]) == PCI_VENDOR_SUN && 259 pci_get_device(children[j]) == PCI_PRODUCT_SUN_EBUS && 260 pci_get_slot(children[j]) == slot) { 261 ebus_dev = children[j]; 262 break; 263 } 264 } 265 if (ebus_dev == NULL) { 266 device_printf(dev, "could not find EBus bridge\n"); 267 error = ENXIO; 268 goto fail_children; 269 } 270 271 /* Map EBus bridge PROM registers. */ 272 i = PCIR_BAR(0); 273 if ((ebus_rres = bus_alloc_resource_any(ebus_dev, SYS_RES_MEMORY, 274 &i, RF_ACTIVE)) == NULL) { 275 device_printf(dev, "could not map PROM registers\n"); 276 error = ENXIO; 277 goto fail_children; 278 } 279 memt = rman_get_bustag(ebus_rres); 280 memh = rman_get_bushandle(ebus_rres); 281 282 /* Read PCI Expansion ROM header. */ 283 if (HME_ROM_READ_2(PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC || 284 (i = HME_ROM_READ_2(PCI_ROMHDR_PTR_DATA)) < PCI_ROMHDR_SIZE) { 285 device_printf(dev, "unexpected PCI Expansion ROM header\n"); 286 error = ENXIO; 287 goto fail_rres; 288 } 289 290 /* Read PCI Expansion ROM data. */ 291 if (HME_ROM_READ_4(i + PCI_ROM_SIG) != PCI_ROM_SIG_MAGIC || 292 HME_ROM_READ_2(i + PCI_ROM_VENDOR) != pci_get_vendor(dev) || 293 HME_ROM_READ_2(i + PCI_ROM_DEVICE) != pci_get_device(dev) || 294 (j = HME_ROM_READ_2(i + PCI_ROM_PTR_VPD)) < i + PCI_ROM_SIZE) { 295 device_printf(dev, "unexpected PCI Expansion ROM data\n"); 296 error = ENXIO; 297 goto fail_rres; 298 } 299 300 /* 301 * Read PCI VPD. 302 * SUNW,hme cards have a single large resource VPD-R tag 303 * containing one NA. SUNW,qfe cards have four large resource 304 * VPD-R tags containing one NA each (all four HME chips share 305 * the same PROM). 306 * The VPD used on both cards is not in PCI 2.2 standard format 307 * however. The length in the resource header is in big endian 308 * and the end tag is non-standard (0x79) and followed by an 309 * all-zero "checksum" byte. Sun calls this a "Fresh Choice 310 * Ethernet" VPD... 311 */ 312 /* Look at the end tag to determine whether this is a VPD with 4 NAs. */ 313 if (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 314 ETHER_ADDR_LEN) != 0x79 && 315 HME_ROM_READ_1(j + 4 * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 316 ETHER_ADDR_LEN)) == 0x79) 317 /* Use the Nth NA for the Nth HME on this SUNW,qfe. */ 318 j += slot * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + 319 ETHER_ADDR_LEN); 320 if (PCI_VPDRES_ISLARGE(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) == 0 || 321 PCI_VPDRES_LARGE_NAME(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) != 322 PCI_VPDRES_TYPE_VPD || 323 (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_LSB) << 8 | 324 HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_MSB)) != 325 PCI_VPD_SIZE + ETHER_ADDR_LEN || 326 HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY0) != 327 0x4e /* N */ || 328 HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY1) != 329 0x41 /* A */ || 330 HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_LEN) != 331 ETHER_ADDR_LEN) { 332 device_printf(dev, "unexpected PCI VPD\n"); 333 error = ENXIO; 334 goto fail_rres; 335 } 336 bus_space_read_region_1(memt, memh, j + PCI_VPDRES_LARGE_DATA + 337 PCI_VPD_DATA, sc->sc_enaddr, ETHER_ADDR_LEN); 338 339fail_rres: 340 bus_release_resource(ebus_dev, SYS_RES_MEMORY, 341 rman_get_rid(ebus_rres), ebus_rres); 342fail_children: 343 free(children, M_TEMP); 344 if (error != 0) 345 goto fail_sres; 346#endif 347 348 sc->sc_burst = 64; /* XXX */ 349 350 /* 351 * call the main configure 352 */ 353 if ((error = hme_config(sc)) != 0) { 354 device_printf(dev, "could not be configured\n"); 355 goto fail_ires; 356 } 357 358 if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET | 359 INTR_MPSAFE, NULL, hme_intr, sc, &hsc->hsc_ih)) != 0) { 360 device_printf(dev, "couldn't establish interrupt\n"); 361 hme_detach(sc); 362 goto fail_ires; 363 } 364 return (0); 365 366fail_ires: 367 bus_release_resource(dev, SYS_RES_IRQ, 368 rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 369fail_sres: 370 bus_release_resource(dev, SYS_RES_MEMORY, 371 rman_get_rid(hsc->hsc_sres), hsc->hsc_sres); 372fail_mtx: 373 mtx_destroy(&sc->sc_lock); 374 return (error); 375} 376 377static int 378hme_pci_detach(device_t dev) 379{ 380 struct hme_pci_softc *hsc; 381 struct hme_softc *sc; 382 383 hsc = device_get_softc(dev); 384 sc = &hsc->hsc_hme; 385 bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih); 386 hme_detach(sc); 387 bus_release_resource(dev, SYS_RES_IRQ, 388 rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); 389 bus_release_resource(dev, SYS_RES_MEMORY, 390 rman_get_rid(hsc->hsc_sres), hsc->hsc_sres); 391 mtx_destroy(&sc->sc_lock); 392 return (0); 393} 394 395static int 396hme_pci_suspend(device_t dev) 397{ 398 struct hme_pci_softc *hsc; 399 400 hsc = device_get_softc(dev); 401 hme_suspend(&hsc->hsc_hme); 402 return (0); 403} 404 405static int 406hme_pci_resume(device_t dev) 407{ 408 struct hme_pci_softc *hsc; 409 410 hsc = device_get_softc(dev); 411 hme_resume(&hsc->hsc_hme); 412 return (0); 413} 414