if_hme_pci.c revision 143161
1/*- 2 * Copyright (c) 2000 Matthew R. Green 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * from: NetBSD: if_hme_pci.c,v 1.14 2004/03/17 08:58:23 martin Exp 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/dev/hme/if_hme_pci.c 143161 2005-03-05 18:30:12Z imp $"); 33 34/* 35 * PCI front-end device driver for the HME ethernet device. 36 */ 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/bus.h> 41#include <sys/kernel.h> 42#include <sys/module.h> 43#include <sys/resource.h> 44#include <sys/socket.h> 45 46#include <machine/bus.h> 47#if defined(__powerpc__) || defined(__sparc64__) 48#include <dev/ofw/openfirm.h> 49#include <machine/ofw_machdep.h> 50#endif 51#include <machine/resource.h> 52 53#include <sys/rman.h> 54 55#include <net/ethernet.h> 56#include <net/if.h> 57#include <net/if_arp.h> 58#include <net/if_dl.h> 59#include <net/if_media.h> 60 61#include <dev/mii/mii.h> 62#include <dev/mii/miivar.h> 63 64#include <dev/pci/pcivar.h> 65#include <dev/pci/pcireg.h> 66 67#include <dev/hme/if_hmereg.h> 68#include <dev/hme/if_hmevar.h> 69 70#include "miibus_if.h" 71 72struct hme_pci_softc { 73 struct hme_softc hsc_hme; /* HME device */ 74 struct resource *hsc_sres; 75 int hsc_srid; 76 struct resource *hsc_ires; 77 int hsc_irid; 78 bus_space_tag_t hsc_memt; 79 bus_space_handle_t hsc_memh; 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 /* bus interface */ 100 DEVMETHOD(bus_print_child, bus_generic_print_child), 101 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 102 103 /* MII interface */ 104 DEVMETHOD(miibus_readreg, hme_mii_readreg), 105 DEVMETHOD(miibus_writereg, hme_mii_writereg), 106 DEVMETHOD(miibus_statchg, hme_mii_statchg), 107 108 { 0, 0 } 109}; 110 111static driver_t hme_pci_driver = { 112 "hme", 113 hme_pci_methods, 114 sizeof(struct hme_pci_softc) 115}; 116 117DRIVER_MODULE(hme, pci, hme_pci_driver, hme_devclass, 0, 0); 118MODULE_DEPEND(hme, pci, 1, 1, 1); 119MODULE_DEPEND(hme, ether, 1, 1, 1); 120 121#define PCI_VENDOR_SUN 0x108e 122#define PCI_PRODUCT_SUN_EBUS 0x1000 123#define PCI_PRODUCT_SUN_HMENETWORK 0x1001 124 125int 126hme_pci_probe(device_t dev) 127{ 128 129 if (pci_get_vendor(dev) == PCI_VENDOR_SUN && 130 pci_get_device(dev) == PCI_PRODUCT_SUN_HMENETWORK) { 131 device_set_desc(dev, "Sun HME 10/100 Ethernet"); 132 return (BUS_PROBE_DEFAULT); 133 } 134 return (ENXIO); 135} 136 137int 138hme_pci_attach(device_t dev) 139{ 140 struct hme_pci_softc *hsc = device_get_softc(dev); 141 struct hme_softc *sc = &hsc->hsc_hme; 142 int error = 0; 143#if !(defined(__powerpc__) || defined(__sparc64__)) 144 device_t *children, ebus_dev; 145 struct resource *ebus_rres; 146 bus_space_handle_t romh; 147 bus_space_tag_t romt; 148 int dataoff, ebus_rrid, slot, vpdoff; 149 int i, nchildren; 150 uint8_t buf[32]; 151 static const uint8_t promhdr[] = { 0x55, 0xaa }; 152#define PROMHDR_PTR_DATA 0x18 153 static const uint8_t promdat[] = { 154 0x50, 0x43, 0x49, 0x52, /* "PCIR" */ 155 PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8, 156 PCI_PRODUCT_SUN_HMENETWORK & 0xff, 157 PCI_PRODUCT_SUN_HMENETWORK >> 8 158 }; 159#define PROMDATA_PTR_VPD 0x08 160 struct pci_vpd { 161 uint8_t vpd_key0; 162 uint8_t vpd_key1; 163 uint8_t vpd_len; 164 } *vpd; 165#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) 166#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) 167#define PCI_VPDRES_TYPE_VPD 0x10 /* large */ 168#endif 169 170 pci_enable_busmaster(dev); 171 /* 172 * Some Sun HMEs do have their intpin register bogusly set to 0, 173 * although it should be 1. correct that. 174 */ 175 if (pci_get_intpin(dev) == 0) 176 pci_set_intpin(dev, 1); 177 178 sc->sc_pci = 1; 179 sc->sc_dev = dev; 180 mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, 181 MTX_DEF); 182 183 /* 184 * Map five register banks: 185 * 186 * bank 0: HME SEB registers: +0x0000 187 * bank 1: HME ETX registers: +0x2000 188 * bank 2: HME ERX registers: +0x4000 189 * bank 3: HME MAC registers: +0x6000 190 * bank 4: HME MIF registers: +0x7000 191 * 192 */ 193 hsc->hsc_srid = PCI_HME_BASEADDR; 194 hsc->hsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 195 &hsc->hsc_srid, RF_ACTIVE); 196 if (hsc->hsc_sres == NULL) { 197 device_printf(dev, "could not map device registers\n"); 198 error = ENXIO; 199 goto fail_mtx; 200 } 201 hsc->hsc_irid = 0; 202 hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 203 &hsc->hsc_irid, RF_SHAREABLE | RF_ACTIVE); 204 if (hsc->hsc_ires == NULL) { 205 device_printf(dev, "could not allocate interrupt\n"); 206 error = ENXIO; 207 goto fail_sres; 208 } 209 hsc->hsc_memt = rman_get_bustag(hsc->hsc_sres); 210 hsc->hsc_memh = rman_get_bushandle(hsc->hsc_sres); 211 sc->sc_sebt = sc->sc_etxt = sc->sc_erxt = sc->sc_mact = sc->sc_mift = 212 hsc->hsc_memt; 213 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x0000, 0x1000, 214 &sc->sc_sebh); 215 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x2000, 0x1000, 216 &sc->sc_etxh); 217 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x4000, 0x1000, 218 &sc->sc_erxh); 219 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x6000, 0x1000, 220 &sc->sc_mach); 221 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x7000, 0x1000, 222 &sc->sc_mifh); 223 224#if defined(__powerpc__) || defined(__sparc64__) 225 OF_getetheraddr(dev, sc->sc_arpcom.ac_enaddr); 226#else 227 /* 228 * Dig out VPD (vital product data) and read NA (network address). 229 * 230 * The PCI HME is a PCIO chip, which is composed of two functions: 231 * function 0: PCI-EBus2 bridge, and 232 * function 1: HappyMeal Ethernet controller. 233 * 234 * The VPD of HME resides in the Boot PROM (PCI FCode) attached 235 * to the EBus bridge and can't be accessed via the PCI capability 236 * pointer. 237 * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) 238 * chapter 2 describes the data structure. 239 * 240 * We don't have a MI EBus driver since no EBus device exists 241 * (besides the FCode PROM) on add-on HME boards. The ``no driver 242 * attached'' message for function 0 therefore is what is expected. 243 */ 244 245 /* Search accompanying EBus bridge. */ 246 slot = pci_get_slot(dev); 247 if (device_get_children(device_get_parent(dev), &children, 248 &nchildren) != 0) { 249 device_printf(dev, "could not get children\n"); 250 error = ENXIO; 251 goto fail_sres; 252 } 253 ebus_dev = NULL; 254 for (i = 0; i < nchildren; i++) { 255 if (pci_get_class(children[i]) == PCIC_BRIDGE && 256 pci_get_vendor(children[i]) == PCI_VENDOR_SUN && 257 pci_get_device(children[i]) == PCI_PRODUCT_SUN_EBUS && 258 pci_get_slot(children[i]) == slot) { 259 ebus_dev = children[i]; 260 break; 261 } 262 } 263 if (ebus_dev == NULL) { 264 device_printf(dev, "could not find EBus bridge\n"); 265 error = ENXIO; 266 goto fail_children; 267 } 268 269 /* Map EBus bridge PROM registers. */ 270#define PCI_EBUS2_BOOTROM 0x10 271 ebus_rrid = PCI_EBUS2_BOOTROM; 272 if ((ebus_rres = bus_alloc_resource_any(ebus_dev, SYS_RES_MEMORY, 273 &ebus_rrid, RF_ACTIVE)) == NULL) { 274 device_printf(dev, "could not map PROM registers\n"); 275 error = ENXIO; 276 goto fail_children; 277 } 278 romt = rman_get_bustag(ebus_rres); 279 romh = rman_get_bushandle(ebus_rres); 280 281 /* Read PCI expansion PROM header. */ 282 bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf)); 283 if (memcmp(buf, promhdr, sizeof(promhdr)) != 0 || 284 (dataoff = (buf[PROMHDR_PTR_DATA] | 285 (buf[PROMHDR_PTR_DATA + 1] << 8))) < 0x1c) { 286 device_printf(dev, "unexpected PCI expansion PROM header\n"); 287 error = ENXIO; 288 goto fail_rres; 289 } 290 291 /* Read PCI expansion PROM data. */ 292 bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf)); 293 if (memcmp(buf, promdat, sizeof(promdat)) != 0 || 294 (vpdoff = (buf[PROMDATA_PTR_VPD] | 295 (buf[PROMDATA_PTR_VPD + 1] << 8))) < 0x1c) { 296 device_printf(dev, "unexpected PCI expansion PROM 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 (bus_space_read_1(romt, romh, 315 vpdoff + 3 + sizeof(struct pci_vpd) + ETHER_ADDR_LEN) != 0x79 && 316 bus_space_read_1(romt, romh, 317 vpdoff + 4 * (3 + sizeof(struct pci_vpd) + ETHER_ADDR_LEN)) == 0x79) 318 /* Use the Nth NA for the Nth HME on this SUNW,qfe. */ 319 vpdoff += slot * (3 + sizeof(struct pci_vpd) + ETHER_ADDR_LEN); 320 bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); 321 vpd = (void *)(buf + 3); 322 if (PCI_VPDRES_ISLARGE(buf[0]) == 0 || 323 PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD || 324 (buf[1] << 8 | buf[2]) != sizeof(struct pci_vpd) + ETHER_ADDR_LEN || 325 vpd->vpd_key0 != 0x4e /* N */ || 326 vpd->vpd_key1 != 0x41 /* A */ || 327 vpd->vpd_len != ETHER_ADDR_LEN) { 328 device_printf(dev, "unexpected PCI VPD\n"); 329 error = ENXIO; 330 goto fail_rres; 331 } 332 bcopy(buf + 3 + sizeof(struct pci_vpd), sc->sc_arpcom.ac_enaddr, 333 ETHER_ADDR_LEN); 334 335fail_rres: 336 bus_release_resource(ebus_dev, SYS_RES_MEMORY, ebus_rrid, ebus_rres); 337fail_children: 338 free(children, M_TEMP); 339 if (error != 0) 340 goto fail_sres; 341#endif 342 343 sc->sc_burst = 64; /* XXX */ 344 345 /* 346 * call the main configure 347 */ 348 if ((error = hme_config(sc)) != 0) { 349 device_printf(dev, "could not be configured\n"); 350 goto fail_ires; 351 } 352 353 if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET | 354 INTR_MPSAFE, hme_intr, sc, &hsc->hsc_ih)) != 0) { 355 device_printf(dev, "couldn't establish interrupt\n"); 356 hme_detach(sc); 357 goto fail_ires; 358 } 359 return (0); 360 361fail_ires: 362 bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires); 363fail_sres: 364 bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres); 365fail_mtx: 366 mtx_destroy(&sc->sc_lock); 367 return (error); 368} 369 370static int 371hme_pci_detach(device_t dev) 372{ 373 struct hme_pci_softc *hsc = device_get_softc(dev); 374 struct hme_softc *sc = &hsc->hsc_hme; 375 376 bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih); 377 hme_detach(sc); 378 bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires); 379 bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres); 380 return (0); 381} 382 383static int 384hme_pci_suspend(device_t dev) 385{ 386 struct hme_pci_softc *hsc = device_get_softc(dev); 387 struct hme_softc *sc = &hsc->hsc_hme; 388 389 hme_suspend(sc); 390 return (0); 391} 392 393static int 394hme_pci_resume(device_t dev) 395{ 396 struct hme_pci_softc *hsc = device_get_softc(dev); 397 struct hme_softc *sc = &hsc->hsc_hme; 398 399 hme_resume(sc); 400 return (0); 401} 402