if_hme_pci.c revision 138712
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 138712 2004-12-12 00:32:51Z marius $"); 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 (0); 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. 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 bus_space_read_region_1(romt, romh, 313 vpdoff + slot * (3 + sizeof(struct pci_vpd) + ETHER_ADDR_LEN), 314 buf, sizeof(buf)); 315 vpd = (void *)(buf + 3); 316 if (PCI_VPDRES_ISLARGE(buf[0]) == 0 || 317 PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD || 318 (buf[1] << 8 | buf[2]) != sizeof(struct pci_vpd) + ETHER_ADDR_LEN || 319 vpd->vpd_key0 != 0x4e /* N */ || 320 vpd->vpd_key1 != 0x41 /* A */ || 321 vpd->vpd_len != ETHER_ADDR_LEN) { 322 device_printf(dev, "unexpected PCI VPD\n"); 323 error = ENXIO; 324 goto fail_rres; 325 } 326 if (buf + 3 + sizeof(struct pci_vpd) == NULL) { 327 device_printf(dev, "could not read network address\n"); 328 error = ENXIO; 329 goto fail_rres; 330 } 331 bcopy(buf + 3 + sizeof(struct pci_vpd), sc->sc_arpcom.ac_enaddr, 332 ETHER_ADDR_LEN); 333 334fail_rres: 335 bus_release_resource(ebus_dev, SYS_RES_MEMORY, ebus_rrid, ebus_rres); 336fail_children: 337 free(children, M_TEMP); 338 if (error != 0) 339 goto fail_sres; 340#endif 341 342 sc->sc_burst = 64; /* XXX */ 343 344 /* 345 * call the main configure 346 */ 347 if ((error = hme_config(sc)) != 0) { 348 device_printf(dev, "could not be configured\n"); 349 goto fail_ires; 350 } 351 352 if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET | 353 INTR_MPSAFE, hme_intr, sc, &hsc->hsc_ih)) != 0) { 354 device_printf(dev, "couldn't establish interrupt\n"); 355 hme_detach(sc); 356 goto fail_ires; 357 } 358 return (0); 359 360fail_ires: 361 bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires); 362fail_sres: 363 bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres); 364fail_mtx: 365 mtx_destroy(&sc->sc_lock); 366 return (error); 367} 368 369static int 370hme_pci_detach(device_t dev) 371{ 372 struct hme_pci_softc *hsc = device_get_softc(dev); 373 struct hme_softc *sc = &hsc->hsc_hme; 374 375 bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih); 376 hme_detach(sc); 377 bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires); 378 bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres); 379 return (0); 380} 381 382static int 383hme_pci_suspend(device_t dev) 384{ 385 struct hme_pci_softc *hsc = device_get_softc(dev); 386 struct hme_softc *sc = &hsc->hsc_hme; 387 388 hme_suspend(sc); 389 return (0); 390} 391 392static int 393hme_pci_resume(device_t dev) 394{ 395 struct hme_pci_softc *hsc = device_get_softc(dev); 396 struct hme_softc *sc = &hsc->hsc_hme; 397 398 hme_resume(sc); 399 return (0); 400} 401