Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/bhnd/bhndb/bhndb_subr.c
Show All 26 Lines | |||||
* THE POSSIBILITY OF SUCH DAMAGES. | * THE POSSIBILITY OF SUCH DAMAGES. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/limits.h> | |||||
#include "bhndb_private.h" | #include "bhndb_private.h" | ||||
#include "bhndbvar.h" | #include "bhndbvar.h" | ||||
/** | /** | ||||
* Attach a BHND bridge device to @p parent. | * Attach a BHND bridge device to @p parent. | ||||
* | * | ||||
* @param parent A parent PCI device. | * @param parent A parent PCI device. | ||||
▲ Show 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | |||||
struct bhndb_resources * | struct bhndb_resources * | ||||
bhndb_alloc_resources(device_t dev, device_t parent_dev, | bhndb_alloc_resources(device_t dev, device_t parent_dev, | ||||
const struct bhndb_hwcfg *cfg) | const struct bhndb_hwcfg *cfg) | ||||
{ | { | ||||
struct bhndb_resources *r; | struct bhndb_resources *r; | ||||
const struct bhndb_regwin *win; | const struct bhndb_regwin *win; | ||||
bus_size_t last_window_size; | bus_size_t last_window_size; | ||||
size_t res_num; | size_t res_num; | ||||
u_int rnid; | int rnid; | ||||
int error; | int error; | ||||
bool free_parent_res; | bool free_parent_res; | ||||
bool free_ht_mem, free_br_mem; | bool free_ht_mem, free_br_mem; | ||||
free_parent_res = false; | free_parent_res = false; | ||||
free_ht_mem = false; | free_ht_mem = false; | ||||
free_br_mem = false; | free_br_mem = false; | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | if (error) { | ||||
device_printf(r->dev, | device_printf(r->dev, | ||||
"could not register host memory region with " | "could not register host memory region with " | ||||
"ht_mem_rman: %d\n", error); | "ht_mem_rman: %d\n", error); | ||||
goto failed; | goto failed; | ||||
} | } | ||||
} | } | ||||
/* Fetch the dynamic regwin count and verify that it does not exceed | /* Fetch the dynamic regwin count and verify that it does not exceed | ||||
* what is representable via our freelist bitmask. */ | * what is representable via our freelist bitstring. */ | ||||
r->dwa_count = bhndb_regwin_count(cfg->register_windows, | r->dwa_count = bhndb_regwin_count(cfg->register_windows, | ||||
BHNDB_REGWIN_T_DYN); | BHNDB_REGWIN_T_DYN); | ||||
if (r->dwa_count >= (8 * sizeof(r->dwa_freelist))) { | if (r->dwa_count >= INT_MAX) { | ||||
device_printf(r->dev, "max dynamic regwin count exceeded\n"); | device_printf(r->dev, "max dynamic regwin count exceeded\n"); | ||||
goto failed; | goto failed; | ||||
} | } | ||||
/* Allocate the dynamic window allocation table. */ | /* Allocate the dynamic window allocation table. */ | ||||
r->dw_alloc = malloc(sizeof(r->dw_alloc[0]) * r->dwa_count, M_BHND, | r->dw_alloc = malloc(sizeof(r->dw_alloc[0]) * r->dwa_count, M_BHND, | ||||
M_NOWAIT); | M_NOWAIT); | ||||
if (r->dw_alloc == NULL) | if (r->dw_alloc == NULL) | ||||
goto failed; | goto failed; | ||||
/* Initialize the dynamic window table and freelist. */ | /* Allocate the dynamic window allocation freelist */ | ||||
r->dwa_freelist = 0; | r->dwa_freelist = bit_alloc(r->dwa_count, M_BHND, M_NOWAIT); | ||||
if (r->dwa_freelist == NULL) | |||||
goto failed; | |||||
/* Initialize the dynamic window table */ | |||||
rnid = 0; | rnid = 0; | ||||
last_window_size = 0; | last_window_size = 0; | ||||
for (win = cfg->register_windows; | for (win = cfg->register_windows; | ||||
win->win_type != BHNDB_REGWIN_T_INVALID; win++) | win->win_type != BHNDB_REGWIN_T_INVALID; win++) | ||||
{ | { | ||||
struct bhndb_dw_alloc *dwa; | struct bhndb_dw_alloc *dwa; | ||||
/* Skip non-DYN windows */ | /* Skip non-DYN windows */ | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (rman_get_size(dwa->parent_res) < win->win_offset + | ||||
rman_get_rid(dwa->parent_res), | rman_get_rid(dwa->parent_res), | ||||
(unsigned long long) win->win_offset, | (unsigned long long) win->win_offset, | ||||
(unsigned long long) win->win_size); | (unsigned long long) win->win_size); | ||||
error = EINVAL; | error = EINVAL; | ||||
goto failed; | goto failed; | ||||
} | } | ||||
/* Add to freelist */ | |||||
r->dwa_freelist |= (1 << rnid); | |||||
rnid++; | rnid++; | ||||
} | } | ||||
return (r); | return (r); | ||||
failed: | failed: | ||||
if (free_parent_res) | if (free_parent_res) | ||||
bus_release_resources(r->parent_dev, r->res_spec, r->res); | bus_release_resources(r->parent_dev, r->res_spec, r->res); | ||||
if (free_ht_mem) | if (free_ht_mem) | ||||
rman_fini(&r->ht_mem_rman); | rman_fini(&r->ht_mem_rman); | ||||
if (free_br_mem) | if (free_br_mem) | ||||
rman_fini(&r->br_mem_rman); | rman_fini(&r->br_mem_rman); | ||||
if (r->res != NULL) | if (r->res != NULL) | ||||
free(r->res, M_BHND); | free(r->res, M_BHND); | ||||
if (r->res_spec != NULL) | if (r->res_spec != NULL) | ||||
free(r->res_spec, M_BHND); | free(r->res_spec, M_BHND); | ||||
if (r->dw_alloc != NULL) | if (r->dw_alloc != NULL) | ||||
free(r->dw_alloc, M_BHND); | free(r->dw_alloc, M_BHND); | ||||
if (r->dwa_freelist != NULL) | |||||
free(r->dwa_freelist, M_BHND); | |||||
free (r, M_BHND); | free (r, M_BHND); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/** | /** | ||||
* Deallocate the given bridge resource structure and any associated resources. | * Deallocate the given bridge resource structure and any associated resources. | ||||
* | * | ||||
* @param br Resource state to be deallocated. | * @param br Resource state to be deallocated. | ||||
*/ | */ | ||||
void | void | ||||
bhndb_free_resources(struct bhndb_resources *br) | bhndb_free_resources(struct bhndb_resources *br) | ||||
{ | { | ||||
struct bhndb_region *region, *r_next; | struct bhndb_region *region, *r_next; | ||||
struct bhndb_dw_alloc *dwa; | struct bhndb_dw_alloc *dwa; | ||||
struct bhndb_dw_rentry *dwr, *dwr_next; | struct bhndb_dw_rentry *dwr, *dwr_next; | ||||
/* No window regions may still be held */ | /* No window regions may still be held */ | ||||
if (__builtin_popcount(br->dwa_freelist) != br->dwa_count) { | if (!bhndb_dw_all_free(br)) { | ||||
device_printf(br->dev, "leaked %llu dynamic register regions\n", | for (int i = 0; i < br->dwa_count; i++) { | ||||
(unsigned long long) br->dwa_count - br->dwa_freelist); | dwa = &br->dw_alloc[i]; | ||||
/* Skip free dynamic windows */ | |||||
if (bhndb_dw_is_free(br, dwa)) | |||||
continue; | |||||
device_printf(br->dev, | |||||
"leaked dynamic register window %d\n", dwa->rnid); | |||||
} | } | ||||
} | |||||
/* Release resources allocated through our parent. */ | /* Release resources allocated through our parent. */ | ||||
bus_release_resources(br->parent_dev, br->res_spec, br->res); | bus_release_resources(br->parent_dev, br->res_spec, br->res); | ||||
/* Clean up resource reservations */ | /* Clean up resource reservations */ | ||||
for (size_t i = 0; i < br->dwa_count; i++) { | for (size_t i = 0; i < br->dwa_count; i++) { | ||||
dwa = &br->dw_alloc[i]; | dwa = &br->dw_alloc[i]; | ||||
Show All 12 Lines | bhndb_free_resources(struct bhndb_resources *br) | ||||
/* Release our resource managers */ | /* Release our resource managers */ | ||||
rman_fini(&br->ht_mem_rman); | rman_fini(&br->ht_mem_rman); | ||||
rman_fini(&br->br_mem_rman); | rman_fini(&br->br_mem_rman); | ||||
/* Free backing resource state structures */ | /* Free backing resource state structures */ | ||||
free(br->res, M_BHND); | free(br->res, M_BHND); | ||||
free(br->res_spec, M_BHND); | free(br->res_spec, M_BHND); | ||||
free(br->dw_alloc, M_BHND); | free(br->dw_alloc, M_BHND); | ||||
free(br->dwa_freelist, M_BHND); | |||||
} | } | ||||
/** | /** | ||||
* Add a bus region entry to @p r for the given base @p addr and @p size. | * Add a bus region entry to @p r for the given base @p addr and @p size. | ||||
* | * | ||||
* @param br The resource state to which the bus region entry will be added. | * @param br The resource state to which the bus region entry will be added. | ||||
* @param addr The base address of this region. | * @param addr The base address of this region. | ||||
* @param size The size of this region. | * @param size The size of this region. | ||||
▲ Show 20 Lines • Show All 226 Lines • ▼ Show 20 Lines | bhndb_dw_retain(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa, | ||||
rentry = malloc(sizeof(*rentry), M_BHND, M_NOWAIT); | rentry = malloc(sizeof(*rentry), M_BHND, M_NOWAIT); | ||||
if (rentry == NULL) | if (rentry == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
rentry->dw_res = res; | rentry->dw_res = res; | ||||
LIST_INSERT_HEAD(&dwa->refs, rentry, dw_link); | LIST_INSERT_HEAD(&dwa->refs, rentry, dw_link); | ||||
/* Update the free list */ | /* Update the free list */ | ||||
br->dwa_freelist &= ~(1 << (dwa->rnid)); | bit_set(br->dwa_freelist, dwa->rnid); | ||||
return (0); | return (0); | ||||
} | } | ||||
/** | /** | ||||
* Release a reference to @p dwa previously retained by @p res. If the | * Release a reference to @p dwa previously retained by @p res. If the | ||||
* reference count of @p dwa reaches zero, it will be added to the | * reference count of @p dwa reaches zero, it will be added to the | ||||
* free list. | * free list. | ||||
Show All 12 Lines | bhndb_dw_release(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa, | ||||
rentry = bhndb_dw_find_resource_entry(dwa, r); | rentry = bhndb_dw_find_resource_entry(dwa, r); | ||||
KASSERT(rentry != NULL, ("over release of resource entry")); | KASSERT(rentry != NULL, ("over release of resource entry")); | ||||
LIST_REMOVE(rentry, dw_link); | LIST_REMOVE(rentry, dw_link); | ||||
free(rentry, M_BHND); | free(rentry, M_BHND); | ||||
/* If this was the last reference, update the free list */ | /* If this was the last reference, update the free list */ | ||||
if (LIST_EMPTY(&dwa->refs)) | if (LIST_EMPTY(&dwa->refs)) | ||||
br->dwa_freelist |= (1 << (dwa->rnid)); | bit_clear(br->dwa_freelist, dwa->rnid); | ||||
} | } | ||||
/** | /** | ||||
* Attempt to set (or reset) the target address of @p dwa to map @p size bytes | * Attempt to set (or reset) the target address of @p dwa to map @p size bytes | ||||
* at @p addr. | * at @p addr. | ||||
* | * | ||||
* This will apply any necessary window alignment and verify that | * This will apply any necessary window alignment and verify that | ||||
* the window is capable of mapping the requested range prior to modifying | * the window is capable of mapping the requested range prior to modifying | ||||
▲ Show 20 Lines • Show All 227 Lines • Show Last 20 Lines |