1 /*- 2 * Copyright (c) 2015 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Semihalf under 6 * the sponsorship of the FreeBSD Foundation. 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 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, 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 30 /* PCIe external MAC root complex driver (PEM) for Cavium Thunder SOC */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include "opt_platform.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/bus.h> 40 #include <sys/kernel.h> 41 #include <sys/malloc.h> 42 #include <sys/module.h> 43 #include <sys/rman.h> 44 #include <sys/endian.h> 45 46 #ifdef FDT 47 #include <dev/ofw/openfirm.h> 48 #include <dev/ofw/ofw_bus.h> 49 #include <dev/ofw/ofw_bus_subr.h> 50 #include <dev/ofw/ofw_pci.h> 51 #endif 52 53 #include <dev/pci/pcivar.h> 54 #include <dev/pci/pcireg.h> 55 #include <dev/pci/pci_host_generic.h> 56 57 #include <machine/bus.h> 58 #include <machine/resource.h> 59 #include <machine/smp.h> 60 #include <machine/intr.h> 61 62 #include <arm64/cavium/thunder_pcie_common.h> 63 #include <arm64/cavium/thunder_pcie_pem.h> 64 #include "pcib_if.h" 65 66 #define THUNDER_PEM_DEVICE_ID 0xa020 67 #define THUNDER_PEM_VENDOR_ID 0x177d 68 69 /* ThunderX specific defines */ 70 #define THUNDER_PEMn_REG_BASE(unit) (0x87e0c0000000UL | ((unit) << 24)) 71 #define PCIERC_CFG002 0x08 72 #define PCIERC_CFG006 0x18 73 #define PCIERC_CFG032 0x80 74 #define PCIERC_CFG006_SEC_BUS(reg) (((reg) >> 8) & 0xFF) 75 #define PEM_CFG_RD_REG_ALIGN(reg) ((reg) & ~0x3) 76 #define PEM_CFG_RD_REG_DATA(val) (((val) >> 32) & 0xFFFFFFFF) 77 #define PEM_CFG_RD 0x30 78 #define PEM_CFG_LINK_MASK 0x3 79 #define PEM_CFG_LINK_RDY 0x3 80 #define PEM_CFG_SLIX_TO_REG(slix) ((slix) << 4) 81 #define SBNUM_OFFSET 0x8 82 #define SBNUM_MASK 0xFF 83 #define PEM_ON_REG 0x420 84 #define PEM_CTL_STATUS 0x0 85 #define PEM_LINK_ENABLE (1 << 4) 86 #define PEM_LINK_DLLA (1 << 29) 87 #define PEM_LINK_LT (1 << 27) 88 #define PEM_BUS_SHIFT (24) 89 #define PEM_SLOT_SHIFT (19) 90 #define PEM_FUNC_SHIFT (16) 91 #define SLIX_S2M_REGX_ACC 0x874001000000UL 92 #define SLIX_S2M_REGX_ACC_SIZE 0x1000 93 #define SLIX_S2M_REGX_ACC_SPACING 0x001000000000UL 94 #define SLI_BASE 0x880000000000UL 95 #define SLI_WINDOW_SPACING 0x004000000000UL 96 #define SLI_WINDOW_SIZE 0x0000FF000000UL 97 #define SLI_PCI_OFFSET 0x001000000000UL 98 #define SLI_NODE_SHIFT (44) 99 #define SLI_NODE_MASK (3) 100 #define SLI_GROUP_SHIFT (40) 101 #define SLI_ID_SHIFT (24) 102 #define SLI_ID_MASK (7) 103 #define SLI_PEMS_PER_GROUP (3) 104 #define SLI_GROUPS_PER_NODE (2) 105 #define SLI_PEMS_PER_NODE (SLI_PEMS_PER_GROUP * SLI_GROUPS_PER_NODE) 106 #define SLI_ACC_REG_CNT (256) 107 108 /* 109 * Each PEM device creates its own bus with 110 * own address translation, so we can adjust bus addresses 111 * as we want. To support 32-bit cards let's assume 112 * PCI window assignment looks as following: 113 * 114 * 0x00000000 - 0x000FFFFF IO 115 * 0x00100000 - 0xFFFFFFFF Memory 116 */ 117 #define PCI_IO_BASE 0x00000000UL 118 #define PCI_IO_SIZE 0x00100000UL 119 #define PCI_MEMORY_BASE PCI_IO_SIZE 120 #define PCI_MEMORY_SIZE 0xFFF00000UL 121 122 #define RID_PEM_SPACE 1 123 124 static struct resource * thunder_pem_alloc_resource(device_t, device_t, int, 125 int *, rman_res_t, rman_res_t, rman_res_t, u_int); 126 static int thunder_pem_attach(device_t); 127 static int thunder_pem_detach(device_t); 128 static uint64_t thunder_pem_config_reg_read(struct thunder_pem_softc *, int); 129 static int thunder_pem_link_init(struct thunder_pem_softc *); 130 static int thunder_pem_maxslots(device_t); 131 static int thunder_pem_probe(device_t); 132 static uint32_t thunder_pem_read_config(device_t, u_int, u_int, u_int, u_int, 133 int); 134 static int thunder_pem_read_ivar(device_t, device_t, int, uintptr_t *); 135 static void thunder_pem_release_all(device_t); 136 static int thunder_pem_release_resource(device_t, device_t, int, int, 137 struct resource *); 138 static void thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *, 139 int, int); 140 static void thunder_pem_write_config(device_t, u_int, u_int, u_int, u_int, 141 uint32_t, int); 142 static int thunder_pem_write_ivar(device_t, device_t, int, uintptr_t); 143 144 /* Global handlers for SLI interface */ 145 static bus_space_handle_t sli0_s2m_regx_base = 0; 146 static bus_space_handle_t sli1_s2m_regx_base = 0; 147 148 static device_method_t thunder_pem_methods[] = { 149 /* Device interface */ 150 DEVMETHOD(device_probe, thunder_pem_probe), 151 DEVMETHOD(device_attach, thunder_pem_attach), 152 DEVMETHOD(device_detach, thunder_pem_detach), 153 DEVMETHOD(pcib_maxslots, thunder_pem_maxslots), 154 DEVMETHOD(pcib_read_config, thunder_pem_read_config), 155 DEVMETHOD(pcib_write_config, thunder_pem_write_config), 156 DEVMETHOD(bus_read_ivar, thunder_pem_read_ivar), 157 DEVMETHOD(bus_write_ivar, thunder_pem_write_ivar), 158 DEVMETHOD(bus_alloc_resource, thunder_pem_alloc_resource), 159 DEVMETHOD(bus_release_resource, thunder_pem_release_resource), 160 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 161 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 162 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 163 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 164 165 DEVMETHOD(pcib_map_msi, arm_map_msi), 166 DEVMETHOD(pcib_alloc_msix, arm_alloc_msix), 167 DEVMETHOD(pcib_release_msix, arm_release_msix), 168 DEVMETHOD(pcib_alloc_msi, arm_alloc_msi), 169 DEVMETHOD(pcib_release_msi, arm_release_msi), 170 DEVMETHOD_END 171 }; 172 173 DEFINE_CLASS_0(pcib, thunder_pem_driver, thunder_pem_methods, 174 sizeof(struct thunder_pem_softc)); 175 176 static devclass_t thunder_pem_devclass; 177 178 DRIVER_MODULE(thunder_pem, pci, thunder_pem_driver, thunder_pem_devclass, 0, 0); 179 MODULE_DEPEND(thunder_pem, pci, 1, 1, 1); 180 181 static int 182 thunder_pem_maxslots(device_t dev) 183 { 184 185 #if 0 186 /* max slots per bus acc. to standard */ 187 return (PCI_SLOTMAX); 188 #else 189 /* 190 * ARM64TODO Workaround - otherwise an em(4) interface appears to be 191 * present on every PCI function on the bus to which it is connected 192 */ 193 return (0); 194 #endif 195 } 196 197 static int 198 thunder_pem_read_ivar(device_t dev, device_t child, int index, 199 uintptr_t *result) 200 { 201 struct thunder_pem_softc *sc; 202 int secondary_bus = 0; 203 204 sc = device_get_softc(dev); 205 206 if (index == PCIB_IVAR_BUS) { 207 secondary_bus = thunder_pem_config_reg_read(sc, PCIERC_CFG006); 208 *result = PCIERC_CFG006_SEC_BUS(secondary_bus); 209 return (0); 210 } 211 if (index == PCIB_IVAR_DOMAIN) { 212 *result = sc->id; 213 return (0); 214 } 215 216 return (ENOENT); 217 } 218 219 static int 220 thunder_pem_write_ivar(device_t dev, device_t child, int index, 221 uintptr_t value) 222 { 223 224 return (ENOENT); 225 } 226 227 static int 228 thunder_pem_identify(device_t dev) 229 { 230 struct thunder_pem_softc *sc; 231 rman_res_t start; 232 233 sc = device_get_softc(dev); 234 start = rman_get_start(sc->reg); 235 236 /* Calculate PEM designations from its address */ 237 sc->node = (start >> SLI_NODE_SHIFT) & SLI_NODE_MASK; 238 sc->id = ((start >> SLI_ID_SHIFT) & SLI_ID_MASK) + 239 (SLI_PEMS_PER_NODE * sc->node); 240 sc->sli = sc->id % SLI_PEMS_PER_GROUP; 241 sc->sli_group = (sc->id / SLI_PEMS_PER_GROUP) % SLI_GROUPS_PER_NODE; 242 sc->sli_window_base = SLI_BASE | 243 (((uint64_t)sc->node) << SLI_NODE_SHIFT) | 244 ((uint64_t)sc->sli_group << SLI_GROUP_SHIFT); 245 sc->sli_window_base += SLI_WINDOW_SPACING * sc->sli; 246 247 return (0); 248 } 249 250 static void 251 thunder_pem_slix_s2m_regx_acc_modify(struct thunder_pem_softc *sc, 252 int sli_group, int slix) 253 { 254 uint64_t regval; 255 bus_space_handle_t handle = 0; 256 257 KASSERT(slix >= 0 && slix <= SLI_ACC_REG_CNT, ("Invalid SLI index")); 258 259 if (sli_group == 0) 260 handle = sli0_s2m_regx_base; 261 else if (sli_group == 1) 262 handle = sli1_s2m_regx_base; 263 else 264 device_printf(sc->dev, "SLI group is not correct\n"); 265 266 if (handle) { 267 /* Clear lower 32-bits of the SLIx register */ 268 regval = bus_space_read_8(sc->reg_bst, handle, 269 PEM_CFG_SLIX_TO_REG(slix)); 270 regval &= ~(0xFFFFFFFFUL); 271 bus_space_write_8(sc->reg_bst, handle, 272 PEM_CFG_SLIX_TO_REG(slix), regval); 273 } 274 } 275 276 static int 277 thunder_pem_link_init(struct thunder_pem_softc *sc) 278 { 279 uint64_t regval; 280 281 /* check whether PEM is safe to access. */ 282 regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_ON_REG); 283 if ((regval & PEM_CFG_LINK_MASK) != PEM_CFG_LINK_RDY) { 284 device_printf(sc->dev, "PEM%d is not ON\n", sc->id); 285 return (ENXIO); 286 } 287 288 regval = bus_space_read_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS); 289 regval |= PEM_LINK_ENABLE; 290 bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CTL_STATUS, regval); 291 292 /* Wait 1ms as per Cavium specification */ 293 DELAY(1000); 294 295 regval = thunder_pem_config_reg_read(sc, PCIERC_CFG032); 296 297 if (((regval & PEM_LINK_DLLA) == 0) || ((regval & PEM_LINK_LT) != 0)) { 298 device_printf(sc->dev, "PCIe RC: Port %d Link Timeout\n", 299 sc->id); 300 return (ENXIO); 301 } 302 303 return (0); 304 } 305 306 static int 307 thunder_pem_init(struct thunder_pem_softc *sc) 308 { 309 int i, retval = 0; 310 311 retval = thunder_pem_link_init(sc); 312 if (retval) { 313 device_printf(sc->dev, "%s failed\n", __func__); 314 return retval; 315 } 316 317 retval = bus_space_map(sc->reg_bst, sc->sli_window_base, 318 SLI_WINDOW_SIZE, 0, &sc->pem_sli_base); 319 if (retval) { 320 device_printf(sc->dev, 321 "Unable to map RC%d pem_addr base address", sc->id); 322 return (ENOMEM); 323 } 324 325 /* To support 32-bit PCIe devices, set S2M_REGx_ACC[BA]=0x0 */ 326 for (i = 0; i < SLI_ACC_REG_CNT; i++) { 327 thunder_pem_slix_s2m_regx_acc_modify(sc, sc->sli_group, i); 328 } 329 330 return (retval); 331 } 332 333 static uint64_t 334 thunder_pem_config_reg_read(struct thunder_pem_softc *sc, int reg) 335 { 336 uint64_t data; 337 338 /* Write to ADDR register */ 339 bus_space_write_8(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD, 340 PEM_CFG_RD_REG_ALIGN(reg)); 341 bus_space_barrier(sc->reg_bst, sc->reg_bsh, PEM_CFG_RD, 8, 342 BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 343 /* Read from DATA register */ 344 data = PEM_CFG_RD_REG_DATA(bus_space_read_8(sc->reg_bst, sc->reg_bsh, 345 PEM_CFG_RD)); 346 347 return (data); 348 } 349 350 static uint32_t 351 thunder_pem_read_config(device_t dev, u_int bus, u_int slot, 352 u_int func, u_int reg, int bytes) 353 { 354 uint64_t offset; 355 uint32_t data; 356 struct thunder_pem_softc *sc; 357 bus_space_tag_t t; 358 bus_space_handle_t h; 359 360 if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) || 361 (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) 362 return (~0U); 363 364 sc = device_get_softc(dev); 365 366 /* Calculate offset */ 367 offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) | 368 (func << PEM_FUNC_SHIFT) | reg; 369 t = sc->reg_bst; 370 h = sc->pem_sli_base; 371 372 switch (bytes) { 373 case 1: 374 data = bus_space_read_1(t, h, offset); 375 break; 376 case 2: 377 data = le16toh(bus_space_read_2(t, h, offset)); 378 break; 379 case 4: 380 data = le32toh(bus_space_read_4(t, h, offset)); 381 break; 382 default: 383 return (~0U); 384 } 385 386 return (data); 387 } 388 389 static void 390 thunder_pem_write_config(device_t dev, u_int bus, u_int slot, 391 u_int func, u_int reg, uint32_t val, int bytes) 392 { 393 uint64_t offset; 394 struct thunder_pem_softc *sc; 395 bus_space_tag_t t; 396 bus_space_handle_t h; 397 398 if ((bus > PCI_BUSMAX) || (slot > PCI_SLOTMAX) || 399 (func > PCI_FUNCMAX) || (reg > PCIE_REGMAX)) 400 return; 401 402 sc = device_get_softc(dev); 403 404 /* Calculate offset */ 405 offset = (bus << PEM_BUS_SHIFT) | (slot << PEM_SLOT_SHIFT) | 406 (func << PEM_FUNC_SHIFT) | reg; 407 t = sc->reg_bst; 408 h = sc->pem_sli_base; 409 410 switch (bytes) { 411 case 1: 412 bus_space_write_1(t, h, offset, val); 413 break; 414 case 2: 415 bus_space_write_2(t, h, offset, htole16(val)); 416 break; 417 case 4: 418 bus_space_write_4(t, h, offset, htole32(val)); 419 break; 420 default: 421 return; 422 } 423 } 424 425 static struct resource * 426 thunder_pem_alloc_resource(device_t dev, device_t child, int type, int *rid, 427 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 428 { 429 struct thunder_pem_softc *sc = device_get_softc(dev); 430 struct rman *rm = NULL; 431 struct resource *res; 432 device_t parent_dev; 433 434 switch (type) { 435 case SYS_RES_IOPORT: 436 rm = &sc->io_rman; 437 break; 438 case SYS_RES_MEMORY: 439 rm = &sc->mem_rman; 440 break; 441 default: 442 /* Find parent device. On ThunderX we know an exact path. */ 443 parent_dev = device_get_parent(device_get_parent(dev)); 444 return (BUS_ALLOC_RESOURCE(parent_dev, dev, type, rid, start, 445 end, count, flags)); 446 }; 447 448 if (RMAN_IS_DEFAULT_RANGE(start, end)) { 449 device_printf(dev, 450 "Cannot allocate resource with unspecified range\n"); 451 goto fail; 452 } 453 454 /* Translate PCI address to host PHYS */ 455 if (range_addr_is_pci(sc->ranges, start, count) == 0) 456 goto fail; 457 start = range_addr_pci_to_phys(sc->ranges, start); 458 end = start + count - 1; 459 460 if (bootverbose) { 461 device_printf(dev, 462 "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n", 463 start, end, count); 464 } 465 466 res = rman_reserve_resource(rm, start, end, count, flags, child); 467 if (res == NULL) 468 goto fail; 469 470 rman_set_rid(res, *rid); 471 472 if (flags & RF_ACTIVE) 473 if (bus_activate_resource(child, type, *rid, res)) { 474 rman_release_resource(res); 475 goto fail; 476 } 477 478 return (res); 479 480 fail: 481 if (bootverbose) { 482 device_printf(dev, "%s FAIL: type=%d, rid=%d, " 483 "start=%016lx, end=%016lx, count=%016lx, flags=%x\n", 484 __func__, type, *rid, start, end, count, flags); 485 } 486 487 return (NULL); 488 } 489 490 static int 491 thunder_pem_release_resource(device_t dev, device_t child, int type, int rid, 492 struct resource *res) 493 { 494 device_t parent_dev; 495 496 /* Find parent device. On ThunderX we know an exact path. */ 497 parent_dev = device_get_parent(device_get_parent(dev)); 498 499 if ((type != SYS_RES_MEMORY) && (type != SYS_RES_IOPORT)) 500 return (BUS_RELEASE_RESOURCE(parent_dev, child, 501 type, rid, res)); 502 503 return (rman_release_resource(res)); 504 } 505 506 static int 507 thunder_pem_probe(device_t dev) 508 { 509 uint16_t pci_vendor_id; 510 uint16_t pci_device_id; 511 512 pci_vendor_id = pci_get_vendor(dev); 513 pci_device_id = pci_get_device(dev); 514 515 if ((pci_vendor_id == THUNDER_PEM_VENDOR_ID) && 516 (pci_device_id == THUNDER_PEM_DEVICE_ID)) { 517 device_set_desc_copy(dev, THUNDER_PEM_DESC); 518 return (0); 519 } 520 521 return (ENXIO); 522 } 523 524 static int 525 thunder_pem_attach(device_t dev) 526 { 527 devclass_t pci_class; 528 device_t parent; 529 struct thunder_pem_softc *sc; 530 int error; 531 int rid; 532 533 sc = device_get_softc(dev); 534 sc->dev = dev; 535 536 /* Allocate memory for resource */ 537 pci_class = devclass_find("pci"); 538 parent = device_get_parent(dev); 539 if (device_get_devclass(parent) == pci_class) 540 rid = PCIR_BAR(0); 541 else 542 rid = RID_PEM_SPACE; 543 544 sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 545 &rid, RF_ACTIVE); 546 if (sc->reg == NULL) { 547 device_printf(dev, "Failed to allocate resource\n"); 548 return (ENXIO); 549 } 550 sc->reg_bst = rman_get_bustag(sc->reg); 551 sc->reg_bsh = rman_get_bushandle(sc->reg); 552 553 /* Map SLI, do it only once */ 554 if (!sli0_s2m_regx_base) { 555 bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC, 556 SLIX_S2M_REGX_ACC_SIZE, 0, &sli0_s2m_regx_base); 557 } 558 if (!sli1_s2m_regx_base) { 559 bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC + 560 SLIX_S2M_REGX_ACC_SPACING, SLIX_S2M_REGX_ACC_SIZE, 0, 561 &sli1_s2m_regx_base); 562 } 563 564 if ((sli0_s2m_regx_base == 0) || (sli1_s2m_regx_base == 0)) { 565 device_printf(dev, 566 "bus_space_map failed to map slix_s2m_regx_base\n"); 567 goto fail; 568 } 569 570 /* Identify PEM */ 571 if (thunder_pem_identify(dev) != 0) 572 goto fail; 573 574 /* Initialize rman and allocate regions */ 575 sc->mem_rman.rm_type = RMAN_ARRAY; 576 sc->mem_rman.rm_descr = "PEM PCIe Memory"; 577 error = rman_init(&sc->mem_rman); 578 if (error != 0) { 579 device_printf(dev, "memory rman_init() failed. error = %d\n", 580 error); 581 goto fail; 582 } 583 sc->io_rman.rm_type = RMAN_ARRAY; 584 sc->io_rman.rm_descr = "PEM PCIe IO"; 585 error = rman_init(&sc->io_rman); 586 if (error != 0) { 587 device_printf(dev, "IO rman_init() failed. error = %d\n", 588 error); 589 goto fail_mem; 590 } 591 592 /* 593 * We ignore the values that may have been provided in FDT 594 * and configure ranges according to the below formula 595 * for all types of devices. This is because some DTBs provided 596 * by EFI do not have proper ranges property or don't have them 597 * at all. 598 */ 599 /* Fill memory window */ 600 sc->ranges[0].pci_base = PCI_MEMORY_BASE; 601 sc->ranges[0].size = PCI_MEMORY_SIZE; 602 sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET + 603 sc->ranges[0].pci_base; 604 rman_manage_region(&sc->mem_rman, sc->ranges[0].phys_base, 605 sc->ranges[0].phys_base + sc->ranges[0].size - 1); 606 607 /* Fill IO window */ 608 sc->ranges[1].pci_base = PCI_IO_BASE; 609 sc->ranges[1].size = PCI_IO_SIZE; 610 sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET + 611 sc->ranges[1].pci_base; 612 rman_manage_region(&sc->io_rman, sc->ranges[1].phys_base, 613 sc->ranges[1].phys_base + sc->ranges[1].size - 1); 614 615 if (thunder_pem_init(sc)) { 616 device_printf(dev, "Failure during PEM init\n"); 617 goto fail_io; 618 } 619 620 device_add_child(dev, "pci", -1); 621 622 return (bus_generic_attach(dev)); 623 624 fail_io: 625 rman_fini(&sc->io_rman); 626 fail_mem: 627 rman_fini(&sc->mem_rman); 628 fail: 629 bus_free_resource(dev, SYS_RES_MEMORY, sc->reg); 630 return (ENXIO); 631 } 632 633 static void 634 thunder_pem_release_all(device_t dev) 635 { 636 struct thunder_pem_softc *sc; 637 638 sc = device_get_softc(dev); 639 640 rman_fini(&sc->io_rman); 641 rman_fini(&sc->mem_rman); 642 643 if (sc->reg != NULL) 644 bus_free_resource(dev, SYS_RES_MEMORY, sc->reg); 645 } 646 647 static int 648 thunder_pem_detach(device_t dev) 649 { 650 651 thunder_pem_release_all(dev); 652 653 return (0); 654 } 655