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