bhndb(4): Drop MIPS-incompatible __builtin_ctz dependency.

This replaces the bitfield representation of the bhndb register window
freelist with the bitstring API, eliminating a dependency on
(MIPS-unsupported) __builtin_ctz().

Approved by:	adrian (mentor)
Differential Revision:	https://reviews.freebsd.org/D7495
This commit is contained in:
Landon J. Fuller 2016-08-16 21:20:05 +00:00
parent 988fd417a0
commit 9dfeb4140c
2 changed files with 40 additions and 21 deletions

View File

@ -33,6 +33,7 @@
#define _BHND_BHNDB_PRIVATE_H_
#include <sys/param.h>
#include <sys/bitstring.h>
#include <sys/bus.h>
#include <sys/systm.h>
@ -184,21 +185,23 @@ struct bhndb_resources {
struct bhndb_dw_alloc *dw_alloc; /**< dynamic window allocation records */
size_t dwa_count; /**< number of dynamic windows available. */
uint32_t dwa_freelist; /**< dynamic window free list */
bitstr_t *dwa_freelist; /**< dynamic window free list */
bhndb_priority_t min_prio; /**< minimum resource priority required to
allocate a dynamic window */
};
/**
* Returns true if the all dynamic windows have been exhausted, false
* Returns true if the all dynamic windows are marked free, false
* otherwise.
*
* @param br The resource state to check.
*/
static inline bool
bhndb_dw_exhausted(struct bhndb_resources *br)
bhndb_dw_all_free(struct bhndb_resources *br)
{
return (br->dwa_freelist == 0);
int bit;
bit_ffs(br->dwa_freelist, br->dwa_count, &bit);
return (bit == -1);
}
/**
@ -209,12 +212,14 @@ bhndb_dw_exhausted(struct bhndb_resources *br)
static inline struct bhndb_dw_alloc *
bhndb_dw_next_free(struct bhndb_resources *br)
{
struct bhndb_dw_alloc *dw_free;
struct bhndb_dw_alloc *dw_free;
int bit;
if (bhndb_dw_exhausted(br))
bit_ffc(br->dwa_freelist, br->dwa_count, &bit);
if (bit == -1)
return (NULL);
dw_free = &br->dw_alloc[__builtin_ctz(br->dwa_freelist)];
dw_free = &br->dw_alloc[bit];
KASSERT(LIST_EMPTY(&dw_free->refs),
("free list out of sync with refs"));
@ -233,7 +238,7 @@ bhndb_dw_is_free(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa)
{
bool is_free = LIST_EMPTY(&dwa->refs);
KASSERT(is_free == ((br->dwa_freelist & (1 << dwa->rnid)) != 0),
KASSERT(is_free == !bit_test(br->dwa_freelist, dwa->rnid),
("refs out of sync with free list"));
return (is_free);

View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include "bhndb_private.h"
#include "bhndbvar.h"
@ -264,7 +265,7 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
const struct bhndb_regwin *win;
bus_size_t last_window_size;
size_t res_num;
u_int rnid;
int rnid;
int error;
bool free_parent_res;
bool free_ht_mem, free_br_mem;
@ -371,10 +372,10 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
}
/* 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,
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");
goto failed;
}
@ -385,8 +386,12 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
if (r->dw_alloc == NULL)
goto failed;
/* Initialize the dynamic window table and freelist. */
r->dwa_freelist = 0;
/* Allocate the dynamic window allocation freelist */
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;
last_window_size = 0;
for (win = cfg->register_windows;
@ -446,9 +451,6 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
goto failed;
}
/* Add to freelist */
r->dwa_freelist |= (1 << rnid);
rnid++;
}
@ -473,6 +475,9 @@ failed:
if (r->dw_alloc != NULL)
free(r->dw_alloc, M_BHND);
if (r->dwa_freelist != NULL)
free(r->dwa_freelist, M_BHND);
free (r, M_BHND);
return (NULL);
@ -491,9 +496,17 @@ bhndb_free_resources(struct bhndb_resources *br)
struct bhndb_dw_rentry *dwr, *dwr_next;
/* No window regions may still be held */
if (__builtin_popcount(br->dwa_freelist) != br->dwa_count) {
device_printf(br->dev, "leaked %llu dynamic register regions\n",
(unsigned long long) br->dwa_count - br->dwa_freelist);
if (!bhndb_dw_all_free(br)) {
for (int i = 0; i < br->dwa_count; i++) {
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. */
@ -523,6 +536,7 @@ bhndb_free_resources(struct bhndb_resources *br)
free(br->res, M_BHND);
free(br->res_spec, M_BHND);
free(br->dw_alloc, M_BHND);
free(br->dwa_freelist, M_BHND);
}
/**
@ -765,7 +779,7 @@ bhndb_dw_retain(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa,
LIST_INSERT_HEAD(&dwa->refs, rentry, dw_link);
/* Update the free list */
br->dwa_freelist &= ~(1 << (dwa->rnid));
bit_set(br->dwa_freelist, dwa->rnid);
return (0);
}
@ -794,7 +808,7 @@ bhndb_dw_release(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa,
/* If this was the last reference, update the free list */
if (LIST_EMPTY(&dwa->refs))
br->dwa_freelist |= (1 << (dwa->rnid));
bit_clear(br->dwa_freelist, dwa->rnid);
}
/**