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