1300548Sadrian/*- 2300548Sadrian * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com> 3300548Sadrian * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org> 4300548Sadrian * All rights reserved. 5300548Sadrian * 6300548Sadrian * Redistribution and use in source and binary forms, with or without 7300548Sadrian * modification, are permitted provided that the following conditions 8300548Sadrian * are met: 9300548Sadrian * 1. Redistributions of source code must retain the above copyright 10300548Sadrian * notice, this list of conditions and the following disclaimer, 11300548Sadrian * without modification. 12300548Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 13300548Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 14300548Sadrian * redistribution must be conditioned upon including a substantially 15300548Sadrian * similar Disclaimer requirement for further binary redistribution. 16300548Sadrian * 17300548Sadrian * NO WARRANTY 18300548Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19300548Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20300548Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 21300548Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22300548Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 23300548Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24300548Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25300548Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 26300548Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27300548Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28300548Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 29300548Sadrian */ 30300548Sadrian 31300548Sadrian#include <sys/cdefs.h> 32300548Sadrian__FBSDID("$FreeBSD$"); 33300548Sadrian 34300548Sadrian#include <sys/param.h> 35300548Sadrian#include <sys/kernel.h> 36300548Sadrian 37300548Sadrian#include "chipc_private.h" 38300548Sadrian#include "chipcvar.h" 39300548Sadrian 40300548Sadrian/** 41302189Slandonf * Return a human-readable name for the given flash @p type. 42302189Slandonf */ 43302189Slandonfconst char * 44302189Slandonfchipc_flash_name(chipc_flash type) 45302189Slandonf{ 46302189Slandonf switch (type) { 47302189Slandonf case CHIPC_PFLASH_CFI: 48302189Slandonf return ("CFI Flash"); 49302189Slandonf 50302189Slandonf case CHIPC_SFLASH_ST: 51302189Slandonf case CHIPC_SFLASH_AT: 52302189Slandonf return ("SPI Flash"); 53302189Slandonf 54302189Slandonf case CHIPC_QSFLASH_ST: 55302189Slandonf case CHIPC_QSFLASH_AT: 56302189Slandonf return ("QSPI Flash"); 57302189Slandonf 58302189Slandonf case CHIPC_NFLASH: 59302189Slandonf case CHIPC_NFLASH_4706: 60302189Slandonf return ("NAND"); 61302189Slandonf 62302189Slandonf case CHIPC_FLASH_NONE: 63302189Slandonf default: 64302189Slandonf return ("unknown"); 65302189Slandonf } 66302189Slandonf} 67302189Slandonf 68302189Slandonf/** 69302189Slandonf * Return the name of the bus device class used by flash @p type, 70302189Slandonf * or NULL if @p type is unsupported. 71302189Slandonf */ 72302189Slandonfconst char * 73302189Slandonfchipc_flash_bus_name(chipc_flash type) 74302189Slandonf{ 75302189Slandonf switch (type) { 76302189Slandonf case CHIPC_PFLASH_CFI: 77302189Slandonf return ("cfi"); 78302189Slandonf 79302189Slandonf case CHIPC_SFLASH_ST: 80302189Slandonf case CHIPC_SFLASH_AT: 81302189Slandonf return ("spi"); 82302189Slandonf 83302189Slandonf case CHIPC_QSFLASH_ST: 84302189Slandonf case CHIPC_QSFLASH_AT: 85302189Slandonf /* unimplemented; spi? */ 86302189Slandonf return (NULL); 87302189Slandonf 88302189Slandonf case CHIPC_NFLASH: 89302189Slandonf case CHIPC_NFLASH_4706: 90302189Slandonf /* unimplemented; nandbus? */ 91302189Slandonf return (NULL); 92302189Slandonf 93302189Slandonf case CHIPC_FLASH_NONE: 94302189Slandonf default: 95302189Slandonf return (NULL); 96302189Slandonf } 97302189Slandonf} 98302189Slandonf 99302189Slandonf/** 100302189Slandonf * Return the name of the flash device class for SPI flash @p type, 101302189Slandonf * or NULL if @p type does not use SPI, or is unsupported. 102302189Slandonf */ 103302189Slandonfconst char * 104302189Slandonfchipc_sflash_device_name(chipc_flash type) 105302189Slandonf{ 106302189Slandonf switch (type) { 107302189Slandonf case CHIPC_SFLASH_ST: 108302189Slandonf return ("mx25l"); 109302189Slandonf 110302189Slandonf case CHIPC_SFLASH_AT: 111302189Slandonf return ("at45d"); 112302189Slandonf 113302189Slandonf case CHIPC_QSFLASH_ST: 114302189Slandonf case CHIPC_QSFLASH_AT: 115302189Slandonf /* unimplemented */ 116302189Slandonf return (NULL); 117302189Slandonf 118302189Slandonf case CHIPC_PFLASH_CFI: 119302189Slandonf case CHIPC_NFLASH: 120302189Slandonf case CHIPC_NFLASH_4706: 121302189Slandonf case CHIPC_FLASH_NONE: 122302189Slandonf default: 123302189Slandonf return (NULL); 124302189Slandonf } 125302189Slandonf} 126302189Slandonf 127302189Slandonf/** 128300548Sadrian * Initialize child resource @p r with a virtual address, tag, and handle 129300548Sadrian * copied from @p parent, adjusted to contain only the range defined by 130300548Sadrian * @p offsize and @p size. 131300548Sadrian * 132300548Sadrian * @param r The register to be initialized. 133300548Sadrian * @param parent The parent bus resource that fully contains the subregion. 134300548Sadrian * @param offset The subregion offset within @p parent. 135300548Sadrian * @param size The subregion size. 136300548Sadrian */ 137300548Sadrianint 138300548Sadrianchipc_init_child_resource(struct resource *r, 139300548Sadrian struct resource *parent, bhnd_size_t offset, bhnd_size_t size) 140300548Sadrian{ 141300548Sadrian bus_space_handle_t bh, child_bh; 142300548Sadrian bus_space_tag_t bt; 143300548Sadrian uintptr_t vaddr; 144300548Sadrian int error; 145300548Sadrian 146300548Sadrian /* Fetch the parent resource's bus values */ 147300548Sadrian vaddr = (uintptr_t) rman_get_virtual(parent); 148300548Sadrian bt = rman_get_bustag(parent); 149300548Sadrian bh = rman_get_bushandle(parent); 150300548Sadrian 151300548Sadrian /* Configure child resource with offset-adjusted values */ 152300548Sadrian vaddr += offset; 153300548Sadrian error = bus_space_subregion(bt, bh, offset, size, &child_bh); 154300548Sadrian if (error) 155300548Sadrian return (error); 156300548Sadrian 157300548Sadrian rman_set_virtual(r, (void *) vaddr); 158300548Sadrian rman_set_bustag(r, bt); 159300548Sadrian rman_set_bushandle(r, child_bh); 160300548Sadrian 161300548Sadrian return (0); 162300548Sadrian} 163300548Sadrian 164302189Slandonf/** 165302189Slandonf * Associate a resource with a given resource ID, relative to the given 166302189Slandonf * port and region. 167302189Slandonf * 168302189Slandonf * This function behaves identically to bus_set_resource() for all resource 169302189Slandonf * types other than SYS_RES_MEMORY. 170302189Slandonf * 171302189Slandonf * For SYS_RES_MEMORY resources, the specified @p region's address and size 172302189Slandonf * will be fetched from the bhnd(4) bus, and bus_set_resource() will be called 173302189Slandonf * with @p start added the region's actual base address. 174302189Slandonf * 175302189Slandonf * To use the default region values for @p start and @p count, specify 176302189Slandonf * a @p start value of 0ul, and an end value of RMAN_MAX_END 177302189Slandonf * 178302189Slandonf * @param sc chipc driver state. 179302189Slandonf * @param child The device to set the resource on. 180302189Slandonf * @param type The resource type. 181302189Slandonf * @param rid The resource ID. 182302189Slandonf * @param start The resource start address (if SYS_RES_MEMORY, this is 183302189Slandonf * relative to @p region's base address). 184302189Slandonf * @param count The length of the resource. 185302189Slandonf * @param port The mapping port number (ignored if not SYS_RES_MEMORY). 186302189Slandonf * @param region The mapping region number (ignored if not SYS_RES_MEMORY). 187302189Slandonf */ 188302189Slandonfint 189302189Slandonfchipc_set_resource(struct chipc_softc *sc, device_t child, int type, int rid, 190302189Slandonf rman_res_t start, rman_res_t count, u_int port, u_int region) 191302189Slandonf{ 192302189Slandonf bhnd_addr_t region_addr; 193302189Slandonf bhnd_size_t region_size; 194302189Slandonf bool isdefault; 195302189Slandonf int error; 196300548Sadrian 197302189Slandonf if (type != SYS_RES_MEMORY) 198302189Slandonf return (bus_set_resource(child, type, rid, start, count)); 199302189Slandonf 200302189Slandonf isdefault = RMAN_IS_DEFAULT_RANGE(start, count); 201302189Slandonf 202302189Slandonf /* Fetch region address and size */ 203302189Slandonf error = bhnd_get_region_addr(sc->dev, BHND_PORT_DEVICE, port, 204302189Slandonf region, ®ion_addr, ®ion_size); 205302189Slandonf if (error) { 206302189Slandonf device_printf(sc->dev, 207302189Slandonf "lookup of %s%u.%u failed: %d\n", 208302189Slandonf bhnd_port_type_name(BHND_PORT_DEVICE), port, region, error); 209302189Slandonf return (error); 210302189Slandonf } 211302189Slandonf 212302189Slandonf /* Populate defaults */ 213302189Slandonf if (isdefault) { 214302189Slandonf start = 0; 215302189Slandonf count = region_size; 216302189Slandonf } 217302189Slandonf 218302189Slandonf /* Verify requested range is mappable */ 219302189Slandonf if (start > region_size || region_size - start < count) { 220302189Slandonf device_printf(sc->dev, 221302189Slandonf "%s%u.%u region cannot map requested range %#jx+%#jx\n", 222302189Slandonf bhnd_port_type_name(BHND_PORT_DEVICE), port, region, start, 223302189Slandonf count); 224302189Slandonf return (ERANGE); 225302189Slandonf } 226302189Slandonf 227302189Slandonf return (bus_set_resource(child, type, rid, region_addr + start, count)); 228302189Slandonf} 229302189Slandonf 230302189Slandonf 231300548Sadrian/* 232300548Sadrian * Print a capability structure. 233300548Sadrian */ 234300548Sadrianvoid 235300548Sadrianchipc_print_caps(device_t dev, struct chipc_caps *caps) 236300548Sadrian{ 237300548Sadrian#define CC_TFS(_flag) (caps->_flag ? "yes" : "no") 238300548Sadrian 239300548Sadrian device_printf(dev, "MIPSEB: %-3s | BP64: %s\n", 240300548Sadrian CC_TFS(mipseb), CC_TFS(backplane_64)); 241300548Sadrian device_printf(dev, "UARTs: %-3hhu | UGPIO: %s\n", 242300548Sadrian caps->num_uarts, CC_TFS(uart_gpio)); 243300548Sadrian // XXX: hitting a kvprintf bug with '%#02x' not prefixing '0x' in 244300548Sadrian // some cases, and not apply the field width in others 245300548Sadrian device_printf(dev, "UARTClk: 0x%02x | Flash: %u\n", 246300548Sadrian caps->uart_clock, caps->flash_type); 247300548Sadrian device_printf(dev, "SPROM: %-3s | OTP: %s\n", 248300548Sadrian CC_TFS(sprom), CC_TFS(otp_size)); 249300548Sadrian device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n", 250300548Sadrian caps->cfi_width, caps->otp_size); 251300548Sadrian device_printf(dev, "ExtBus: 0x%02x | PwCtl: %s\n", 252300548Sadrian caps->extbus_type, CC_TFS(power_control)); 253300548Sadrian device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n", 254300548Sadrian caps->pll_type, CC_TFS(jtag_master)); 255300548Sadrian device_printf(dev, "PMU: %-3s | ECI: %s\n", 256300548Sadrian CC_TFS(pmu), CC_TFS(eci)); 257300548Sadrian device_printf(dev, "SECI: %-3s | GSIO: %s\n", 258300548Sadrian CC_TFS(seci), CC_TFS(gsio)); 259300548Sadrian device_printf(dev, "AOB: %-3s | BootROM: %s\n", 260300548Sadrian CC_TFS(aob), CC_TFS(boot_rom)); 261300548Sadrian 262300548Sadrian#undef CC_TFS 263300548Sadrian} 264300548Sadrian 265300548Sadrian/** 266300548Sadrian * Allocate and initialize new region record. 267300548Sadrian * 268300548Sadrian * @param sc Driver instance state. 269300548Sadrian * @param type The port type to query. 270300548Sadrian * @param port The port number to query. 271300548Sadrian * @param region The region number to query. 272300548Sadrian */ 273300548Sadrianstruct chipc_region * 274300548Sadrianchipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type, 275300548Sadrian u_int port, u_int region) 276300548Sadrian{ 277300548Sadrian struct chipc_region *cr; 278300548Sadrian int error; 279300548Sadrian 280300548Sadrian /* Don't bother allocating a chipc_region if init will fail */ 281300548Sadrian if (!bhnd_is_region_valid(sc->dev, type, port, region)) 282300548Sadrian return (NULL); 283300548Sadrian 284300548Sadrian /* Allocate and initialize region info */ 285300548Sadrian cr = malloc(sizeof(*cr), M_BHND, M_NOWAIT); 286300548Sadrian if (cr == NULL) 287300548Sadrian return (NULL); 288300548Sadrian 289300548Sadrian cr->cr_port_type = type; 290300548Sadrian cr->cr_port_num = port; 291300548Sadrian cr->cr_region_num = region; 292300548Sadrian cr->cr_res = NULL; 293300548Sadrian cr->cr_refs = 0; 294300548Sadrian cr->cr_act_refs = 0; 295300548Sadrian 296300548Sadrian error = bhnd_get_region_addr(sc->dev, type, port, region, &cr->cr_addr, 297300548Sadrian &cr->cr_count); 298300548Sadrian if (error) { 299300548Sadrian device_printf(sc->dev, 300300548Sadrian "fetching chipc region address failed: %d\n", error); 301300548Sadrian goto failed; 302300548Sadrian } 303300548Sadrian 304300548Sadrian cr->cr_end = cr->cr_addr + cr->cr_count - 1; 305300548Sadrian 306301971Slandonf /* Fetch default resource ID for this region. Not all regions have an 307301971Slandonf * assigned rid, in which case this will return -1 */ 308300548Sadrian cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region); 309301971Slandonf 310300548Sadrian return (cr); 311300548Sadrian 312300548Sadrianfailed: 313300548Sadrian device_printf(sc->dev, "chipc region alloc failed for %s%u.%u\n", 314300548Sadrian bhnd_port_type_name(type), port, region); 315300548Sadrian free(cr, M_BHND); 316300548Sadrian return (NULL); 317300548Sadrian} 318300548Sadrian 319300548Sadrian/** 320300548Sadrian * Deallocate the given region record and its associated resource, if any. 321300548Sadrian * 322300548Sadrian * @param sc Driver instance state. 323300548Sadrian * @param cr Region record to be deallocated. 324300548Sadrian */ 325300548Sadrianvoid 326300548Sadrianchipc_free_region(struct chipc_softc *sc, struct chipc_region *cr) 327300548Sadrian{ 328300548Sadrian KASSERT(cr->cr_refs == 0, 329300548Sadrian ("chipc %s%u.%u region has %u active references", 330300548Sadrian bhnd_port_type_name(cr->cr_port_type), cr->cr_port_num, 331300548Sadrian cr->cr_region_num, cr->cr_refs)); 332300548Sadrian 333300548Sadrian if (cr->cr_res != NULL) { 334301971Slandonf bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_res_rid, 335300548Sadrian cr->cr_res); 336300548Sadrian } 337300548Sadrian 338300548Sadrian free(cr, M_BHND); 339300548Sadrian} 340300548Sadrian 341300548Sadrian/** 342300548Sadrian * Locate the region mapping the given range, if any. Returns NULL if no 343300548Sadrian * valid region is found. 344300548Sadrian * 345300548Sadrian * @param sc Driver instance state. 346300548Sadrian * @param start start of address range. 347300548Sadrian * @param end end of address range. 348300548Sadrian */ 349300548Sadrianstruct chipc_region * 350300548Sadrianchipc_find_region(struct chipc_softc *sc, rman_res_t start, rman_res_t end) 351300548Sadrian{ 352300548Sadrian struct chipc_region *cr; 353300548Sadrian 354300548Sadrian if (start > end) 355300548Sadrian return (NULL); 356300548Sadrian 357300548Sadrian STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) { 358300548Sadrian if (start < cr->cr_addr || end > cr->cr_end) 359300548Sadrian continue; 360300548Sadrian 361300548Sadrian /* Found */ 362300548Sadrian return (cr); 363300548Sadrian } 364300548Sadrian 365300548Sadrian /* Not found */ 366300548Sadrian return (NULL); 367300548Sadrian} 368300548Sadrian 369300548Sadrian/** 370300548Sadrian * Locate a region mapping by its bhnd-assigned resource id (as returned by 371300548Sadrian * bhnd_get_port_rid). 372300548Sadrian * 373300548Sadrian * @param sc Driver instance state. 374300548Sadrian * @param rid Resource ID to query for. 375300548Sadrian */ 376300548Sadrianstruct chipc_region * 377300548Sadrianchipc_find_region_by_rid(struct chipc_softc *sc, int rid) 378300548Sadrian{ 379300548Sadrian struct chipc_region *cr; 380300548Sadrian int port_rid; 381300548Sadrian 382300548Sadrian STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) { 383300548Sadrian port_rid = bhnd_get_port_rid(sc->dev, cr->cr_port_type, 384300548Sadrian cr->cr_port_num, cr->cr_region_num); 385300548Sadrian if (port_rid == -1 || port_rid != rid) 386300548Sadrian continue; 387300548Sadrian 388300548Sadrian /* Found */ 389300548Sadrian return (cr); 390300548Sadrian } 391300548Sadrian 392300548Sadrian /* Not found */ 393300548Sadrian return (NULL); 394300548Sadrian} 395300548Sadrian 396300548Sadrian/** 397300548Sadrian * Retain a reference to a chipc_region, allocating and activating the 398300548Sadrian * backing resource as required. 399300548Sadrian * 400300548Sadrian * @param sc chipc driver instance state 401300548Sadrian * @param cr region to retain. 402300548Sadrian * @param flags specify RF_ALLOCATED to retain an allocation reference, 403300548Sadrian * RF_ACTIVE to retain an activation reference. 404300548Sadrian */ 405300548Sadrianint 406300548Sadrianchipc_retain_region(struct chipc_softc *sc, struct chipc_region *cr, int flags) 407300548Sadrian{ 408300548Sadrian int error; 409300548Sadrian 410300548Sadrian KASSERT(!(flags &~ (RF_ACTIVE|RF_ALLOCATED)), ("unsupported flags")); 411300548Sadrian 412300548Sadrian CHIPC_LOCK(sc); 413300548Sadrian 414300548Sadrian /* Handle allocation */ 415300548Sadrian if (flags & RF_ALLOCATED) { 416300548Sadrian /* If this is the first reference, allocate the resource */ 417300548Sadrian if (cr->cr_refs == 0) { 418300548Sadrian KASSERT(cr->cr_res == NULL, 419300548Sadrian ("non-NULL resource has refcount")); 420300548Sadrian 421301971Slandonf /* Fetch initial resource ID */ 422301971Slandonf if ((cr->cr_res_rid = cr->cr_rid) == -1) { 423301971Slandonf CHIPC_UNLOCK(sc); 424301971Slandonf return (EINVAL); 425301971Slandonf } 426301971Slandonf 427301971Slandonf /* Allocate resource */ 428300548Sadrian cr->cr_res = bhnd_alloc_resource(sc->dev, 429301971Slandonf SYS_RES_MEMORY, &cr->cr_res_rid, cr->cr_addr, 430300548Sadrian cr->cr_end, cr->cr_count, 0); 431300548Sadrian if (cr->cr_res == NULL) { 432300548Sadrian CHIPC_UNLOCK(sc); 433300548Sadrian return (ENXIO); 434300548Sadrian } 435300548Sadrian } 436300548Sadrian 437300548Sadrian /* Increment allocation refcount */ 438300548Sadrian cr->cr_refs++; 439300548Sadrian } 440300548Sadrian 441300548Sadrian 442300548Sadrian /* Handle activation */ 443300548Sadrian if (flags & RF_ACTIVE) { 444300548Sadrian KASSERT(cr->cr_refs > 0, 445300548Sadrian ("cannot activate unallocated resource")); 446300548Sadrian 447300548Sadrian /* If this is the first reference, activate the resource */ 448300548Sadrian if (cr->cr_act_refs == 0) { 449300548Sadrian error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY, 450301971Slandonf cr->cr_res_rid, cr->cr_res); 451300548Sadrian if (error) { 452300548Sadrian /* Drop any allocation reference acquired 453300548Sadrian * above */ 454300548Sadrian CHIPC_UNLOCK(sc); 455300548Sadrian chipc_release_region(sc, cr, 456300548Sadrian flags &~ RF_ACTIVE); 457300548Sadrian return (error); 458300548Sadrian } 459300548Sadrian } 460300548Sadrian 461300548Sadrian /* Increment activation refcount */ 462300548Sadrian cr->cr_act_refs++; 463300548Sadrian } 464300548Sadrian 465300548Sadrian CHIPC_UNLOCK(sc); 466300548Sadrian return (0); 467300548Sadrian} 468300548Sadrian 469300548Sadrian/** 470300548Sadrian * Release a reference to a chipc_region, deactivating and releasing the 471300548Sadrian * backing resource if the reference count hits zero. 472300548Sadrian * 473300548Sadrian * @param sc chipc driver instance state 474300548Sadrian * @param cr region to retain. 475300548Sadrian * @param flags specify RF_ALLOCATED to release an allocation reference, 476300548Sadrian * RF_ACTIVE to release an activation reference. 477300548Sadrian */ 478300548Sadrianint 479300548Sadrianchipc_release_region(struct chipc_softc *sc, struct chipc_region *cr, 480300548Sadrian int flags) 481300548Sadrian{ 482300548Sadrian int error; 483300548Sadrian 484300548Sadrian CHIPC_LOCK(sc); 485300548Sadrian error = 0; 486300548Sadrian 487301971Slandonf KASSERT(cr->cr_res != NULL, ("release on NULL region resource")); 488301971Slandonf 489300548Sadrian if (flags & RF_ACTIVE) { 490300548Sadrian KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released")); 491300548Sadrian KASSERT(cr->cr_act_refs <= cr->cr_refs, 492300548Sadrian ("RF_ALLOCATED released with RF_ACTIVE held")); 493300548Sadrian 494300548Sadrian /* If this is the last reference, deactivate the resource */ 495300548Sadrian if (cr->cr_act_refs == 1) { 496300548Sadrian error = bhnd_deactivate_resource(sc->dev, 497301971Slandonf SYS_RES_MEMORY, cr->cr_res_rid, cr->cr_res); 498300548Sadrian if (error) 499300548Sadrian goto done; 500300548Sadrian } 501300548Sadrian 502300548Sadrian /* Drop our activation refcount */ 503300548Sadrian cr->cr_act_refs--; 504300548Sadrian } 505300548Sadrian 506300548Sadrian if (flags & RF_ALLOCATED) { 507300548Sadrian KASSERT(cr->cr_refs > 0, ("overrelease of refs")); 508300548Sadrian /* If this is the last reference, release the resource */ 509300548Sadrian if (cr->cr_refs == 1) { 510301971Slandonf error = bhnd_release_resource(sc->dev, SYS_RES_MEMORY, 511301971Slandonf cr->cr_res_rid, cr->cr_res); 512300548Sadrian if (error) 513300548Sadrian goto done; 514300548Sadrian 515300548Sadrian cr->cr_res = NULL; 516300548Sadrian } 517300548Sadrian 518300548Sadrian /* Drop our allocation refcount */ 519300548Sadrian cr->cr_refs--; 520300548Sadrian } 521300548Sadrian 522300548Sadriandone: 523300548Sadrian CHIPC_UNLOCK(sc); 524300548Sadrian return (error); 525300548Sadrian} 526