if_hme_pci.c revision 133731
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 133731 2004-08-14 22:38:20Z 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#define PROMDATA_DATA2 0x0a 161 static const uint8_t promdat2[] = { 162 0x18, 0x00, /* structure length */ 163 0x00, /* structure revision */ 164 0x00, /* interface revision */ 165 PCIS_NETWORK_ETHERNET, /* subclass code */ 166 PCIC_NETWORK /* class code */ 167 }; 168#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) 169#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) 170#define PCI_VPDRES_TYPE_VPD 0x10 /* large */ 171 struct pci_vpd { 172 uint8_t vpd_key0; 173 uint8_t vpd_key1; 174 uint8_t vpd_len; 175 } *vpd; 176#endif 177 178 pci_enable_busmaster(dev); 179 /* 180 * Some Sun HMEs do have their intpin register bogusly set to 0, 181 * although it should be 1. correct that. 182 */ 183 if (pci_get_intpin(dev) == 0) 184 pci_set_intpin(dev, 1); 185 186 sc->sc_pci = 1; 187 sc->sc_dev = dev; 188 189 /* 190 * Map five register banks: 191 * 192 * bank 0: HME SEB registers: +0x0000 193 * bank 1: HME ETX registers: +0x2000 194 * bank 2: HME ERX registers: +0x4000 195 * bank 3: HME MAC registers: +0x6000 196 * bank 4: HME MIF registers: +0x7000 197 * 198 */ 199 hsc->hsc_srid = PCI_HME_BASEADDR; 200 hsc->hsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 201 &hsc->hsc_srid, RF_ACTIVE); 202 if (hsc->hsc_sres == NULL) { 203 device_printf(dev, "could not map device registers\n"); 204 return (ENXIO); 205 } 206 hsc->hsc_irid = 0; 207 hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 208 &hsc->hsc_irid, RF_SHAREABLE | RF_ACTIVE); 209 if (hsc->hsc_ires == NULL) { 210 device_printf(dev, "could not allocate interrupt\n"); 211 error = ENXIO; 212 goto fail_sres; 213 } 214 hsc->hsc_memt = rman_get_bustag(hsc->hsc_sres); 215 hsc->hsc_memh = rman_get_bushandle(hsc->hsc_sres); 216 sc->sc_sebt = sc->sc_etxt = sc->sc_erxt = sc->sc_mact = sc->sc_mift = 217 hsc->hsc_memt; 218 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x0000, 0x1000, 219 &sc->sc_sebh); 220 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x2000, 0x1000, 221 &sc->sc_etxh); 222 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x4000, 0x1000, 223 &sc->sc_erxh); 224 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x6000, 0x1000, 225 &sc->sc_mach); 226 bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x7000, 0x1000, 227 &sc->sc_mifh); 228 229#if defined(__powerpc__) || defined(__sparc64__) 230 OF_getetheraddr(dev, sc->sc_arpcom.ac_enaddr); 231#else 232 /* 233 * Dig out VPD (vital product data) and read NA (network address). 234 * 235 * The PCI HME is a PCIO chip, which is composed of two functions: 236 * function 0: PCI-EBus2 bridge, and 237 * function 1: HappyMeal Ethernet controller. 238 * 239 * The VPD of HME resides in the Boot PROM (PCI FCode) attached 240 * to the EBus bridge and can't be accessed via the PCI capability 241 * pointer. 242 * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) 243 * chapter 2 describes the data structure. 244 * 245 * We don't have a MI EBus driver since no EBus device exists 246 * (besides the FCode PROM) on add-on HME boards. The ``no driver 247 * attached'' message for function 0 therefore is what is expected. 248 */ 249 250 /* Search accompanying EBus bridge. */ 251 slot = pci_get_slot(dev); 252 if (device_get_children(device_get_parent(dev), &children, 253 &nchildren) != 0) { 254 device_printf(dev, "could not get children\n"); 255 error = ENXIO; 256 goto fail_sres; 257 } 258 ebus_dev = NULL; 259 for (i = 0; i < nchildren; i++) { 260 if (pci_get_class(children[i]) == PCIC_BRIDGE && 261 pci_get_vendor(children[i]) == PCI_VENDOR_SUN && 262 pci_get_device(children[i]) == PCI_PRODUCT_SUN_EBUS && 263 pci_get_slot(children[i]) == slot) { 264 ebus_dev = children[i]; 265 break; 266 } 267 } 268 if (ebus_dev == NULL) { 269 device_printf(dev, "could not find EBus bridge\n"); 270 error = ENXIO; 271 goto fail_children; 272 } 273 274 /* Map EBus bridge PROM registers. */ 275#define PCI_EBUS2_BOOTROM 0x10 276 ebus_rrid = PCI_EBUS2_BOOTROM; 277 if ((ebus_rres = bus_alloc_resource_any(ebus_dev, SYS_RES_MEMORY, 278 &ebus_rrid, RF_ACTIVE)) == NULL) { 279 device_printf(dev, "could not map PROM registers\n"); 280 error = ENXIO; 281 goto fail_children; 282 } 283 romt = rman_get_bustag(ebus_rres); 284 romh = rman_get_bushandle(ebus_rres); 285 286 /* Read PCI expansion PROM header. */ 287 bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf)); 288 if (memcmp(buf, promhdr, sizeof(promhdr)) != 0 || 289 (dataoff = (buf[PROMHDR_PTR_DATA] | 290 (buf[PROMHDR_PTR_DATA + 1] << 8))) < 0x1c) { 291 device_printf(dev, "unexpected PCI expansion PROM header\n"); 292 error = ENXIO; 293 goto fail_rres; 294 } 295 296 /* Read PCI expansion PROM data. */ 297 bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf)); 298 if (memcmp(buf, promdat, sizeof(promdat)) != 0 || 299 memcmp(buf + PROMDATA_DATA2, promdat2, sizeof(promdat2)) != 0 || 300 (vpdoff = (buf[PROMDATA_PTR_VPD] | 301 (buf[PROMDATA_PTR_VPD + 1] << 8))) < 0x1c) { 302 device_printf(dev, "unexpected PCI expansion PROM data\n"); 303 error = ENXIO; 304 goto fail_rres; 305 } 306 307 /* 308 * Read PCI VPD. 309 * The VPD of HME is not in PCI 2.2 standard format. The length in 310 * the resource header is in big endian, and resources are not 311 * properly terminated (only one resource and no end tag). 312 */ 313 bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); 314 vpd = (void *)(buf + 3); 315 if (PCI_VPDRES_ISLARGE(buf[0]) == 0 || 316 PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD || 317 /* buf[1] != 0 || buf[2] != 9 || */ /*len*/ 318 vpd->vpd_key0 != 0x4e /* N */ || 319 vpd->vpd_key1 != 0x41 /* A */ || 320 vpd->vpd_len != ETHER_ADDR_LEN) { 321 device_printf(dev, "unexpected PCI VPD\n"); 322 error = ENXIO; 323 goto fail_rres; 324 } 325 if (buf + 6 == NULL) { 326 device_printf(dev, "could not read network address\n"); 327 error = ENXIO; 328 goto fail_rres; 329 } 330 bcopy(buf + 6, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); 331 332fail_rres: 333 bus_release_resource(ebus_dev, SYS_RES_MEMORY, ebus_rrid, ebus_rres); 334fail_children: 335 free(children, M_TEMP); 336 if (error != 0) 337 goto fail_sres; 338#endif 339 340 sc->sc_burst = 64; /* XXX */ 341 342 /* 343 * call the main configure 344 */ 345 if ((error = hme_config(sc)) != 0) { 346 device_printf(dev, "could not be configured\n"); 347 goto fail_ires; 348 } 349 350 if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET, hme_intr, 351 sc, &hsc->hsc_ih)) != 0) { 352 device_printf(dev, "couldn't establish interrupt\n"); 353 hme_detach(sc); 354 goto fail_ires; 355 } 356 return (0); 357 358fail_ires: 359 bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires); 360fail_sres: 361 bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres); 362 return (error); 363} 364 365static int 366hme_pci_detach(device_t dev) 367{ 368 struct hme_pci_softc *hsc = device_get_softc(dev); 369 struct hme_softc *sc = &hsc->hsc_hme; 370 371 hme_detach(sc); 372 373 bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih); 374 bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires); 375 bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres); 376 return (0); 377} 378 379static int 380hme_pci_suspend(device_t dev) 381{ 382 struct hme_pci_softc *hsc = device_get_softc(dev); 383 struct hme_softc *sc = &hsc->hsc_hme; 384 385 hme_suspend(sc); 386 return (0); 387} 388 389static int 390hme_pci_resume(device_t dev) 391{ 392 struct hme_pci_softc *hsc = device_get_softc(dev); 393 struct hme_softc *sc = &hsc->hsc_hme; 394 395 hme_resume(sc); 396 return (0); 397} 398