linuxkpi: Add struct xa_limit support to xarray
The `xa_alloc*()` functions family takes a `struct xa_limit` to describe the range of IDs the caller wants to allocate. We were using a single mask to qualify a maximum ID only. This commit changes that to use the same `struct xa_limit`. The logic did not change, except it now supports a minimum ID as well. The definition of `XA_LIMIT()` macro is adapted, as well as the definitions of `xa_limit_*` (only `xa_limit_32b` existed, the other two are added with this commit). The DRM generic code started to use this `struct xa_limit` in Linux 6.12. Reviewed by: bz Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D56445
This commit is contained in:
@@ -34,9 +34,6 @@
|
|||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <sys/mutex.h>
|
#include <sys/mutex.h>
|
||||||
|
|
||||||
#define XA_LIMIT(min, max) \
|
|
||||||
({ CTASSERT((min) == 0); (uint32_t)(max); })
|
|
||||||
|
|
||||||
#define XA_FLAGS_ALLOC (1U << 0)
|
#define XA_FLAGS_ALLOC (1U << 0)
|
||||||
#define XA_FLAGS_LOCK_IRQ (1U << 1)
|
#define XA_FLAGS_LOCK_IRQ (1U << 1)
|
||||||
#define XA_FLAGS_ALLOC1 (1U << 2)
|
#define XA_FLAGS_ALLOC1 (1U << 2)
|
||||||
@@ -47,8 +44,6 @@
|
|||||||
#define xa_is_err(x) \
|
#define xa_is_err(x) \
|
||||||
IS_ERR(x)
|
IS_ERR(x)
|
||||||
|
|
||||||
#define xa_limit_32b XA_LIMIT(0, 0xFFFFFFFF)
|
|
||||||
|
|
||||||
#define XA_ASSERT_LOCKED(xa) mtx_assert(&(xa)->xa_lock, MA_OWNED)
|
#define XA_ASSERT_LOCKED(xa) mtx_assert(&(xa)->xa_lock, MA_OWNED)
|
||||||
#define xa_lock(xa) mtx_lock(&(xa)->xa_lock)
|
#define xa_lock(xa) mtx_lock(&(xa)->xa_lock)
|
||||||
#define xa_unlock(xa) mtx_unlock(&(xa)->xa_lock)
|
#define xa_unlock(xa) mtx_unlock(&(xa)->xa_lock)
|
||||||
@@ -59,15 +54,26 @@ struct xarray {
|
|||||||
uint32_t xa_flags; /* see XA_FLAGS_XXX */
|
uint32_t xa_flags; /* see XA_FLAGS_XXX */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct xa_limit {
|
||||||
|
uint32_t max;
|
||||||
|
uint32_t min;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define XA_LIMIT(min_, max_) (struct xa_limit){ .min = (min_), .max = (max_) }
|
||||||
|
|
||||||
|
#define xa_limit_16b XA_LIMIT(0, USHRT_MAX)
|
||||||
|
#define xa_limit_31b XA_LIMIT(0, INT_MAX)
|
||||||
|
#define xa_limit_32b XA_LIMIT(0, UINT_MAX)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extensible arrays API implemented as a wrapper
|
* Extensible arrays API implemented as a wrapper
|
||||||
* around the radix tree implementation.
|
* around the radix tree implementation.
|
||||||
*/
|
*/
|
||||||
void *xa_erase(struct xarray *, uint32_t);
|
void *xa_erase(struct xarray *, uint32_t);
|
||||||
void *xa_load(struct xarray *, uint32_t);
|
void *xa_load(struct xarray *, uint32_t);
|
||||||
int xa_alloc(struct xarray *, uint32_t *, void *, uint32_t, gfp_t);
|
int xa_alloc(struct xarray *, uint32_t *, void *, struct xa_limit, gfp_t);
|
||||||
int xa_alloc_cyclic(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
|
int xa_alloc_cyclic(struct xarray *, uint32_t *, void *, struct xa_limit, uint32_t *, gfp_t);
|
||||||
int xa_alloc_cyclic_irq(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
|
int xa_alloc_cyclic_irq(struct xarray *, uint32_t *, void *, struct xa_limit, uint32_t *, gfp_t);
|
||||||
int xa_insert(struct xarray *, uint32_t, void *, gfp_t);
|
int xa_insert(struct xarray *, uint32_t, void *, gfp_t);
|
||||||
void *xa_store(struct xarray *, uint32_t, void *, gfp_t);
|
void *xa_store(struct xarray *, uint32_t, void *, gfp_t);
|
||||||
void xa_init_flags(struct xarray *, uint32_t);
|
void xa_init_flags(struct xarray *, uint32_t);
|
||||||
@@ -83,8 +89,8 @@ void *xa_next(struct xarray *, unsigned long *, bool);
|
|||||||
* Unlocked version of functions above.
|
* Unlocked version of functions above.
|
||||||
*/
|
*/
|
||||||
void *__xa_erase(struct xarray *, uint32_t);
|
void *__xa_erase(struct xarray *, uint32_t);
|
||||||
int __xa_alloc(struct xarray *, uint32_t *, void *, uint32_t, gfp_t);
|
int __xa_alloc(struct xarray *, uint32_t *, void *, struct xa_limit, gfp_t);
|
||||||
int __xa_alloc_cyclic(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
|
int __xa_alloc_cyclic(struct xarray *, uint32_t *, void *, struct xa_limit, uint32_t *, gfp_t);
|
||||||
int __xa_insert(struct xarray *, uint32_t, void *, gfp_t);
|
int __xa_insert(struct xarray *, uint32_t, void *, gfp_t);
|
||||||
void *__xa_store(struct xarray *, uint32_t, void *, gfp_t);
|
void *__xa_store(struct xarray *, uint32_t, void *, gfp_t);
|
||||||
bool __xa_empty(struct xarray *);
|
bool __xa_empty(struct xarray *);
|
||||||
|
|||||||
@@ -115,19 +115,16 @@ xa_vm_wait_locked(struct xarray *xa)
|
|||||||
* available to complete the radix tree insertion.
|
* available to complete the radix tree insertion.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
__xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gfp)
|
__xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, struct xa_limit limit, gfp_t gfp)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
XA_ASSERT_LOCKED(xa);
|
XA_ASSERT_LOCKED(xa);
|
||||||
|
|
||||||
/* mask should allow to allocate at least one item */
|
MPASS(limit.max > limit.min);
|
||||||
MPASS(mask > ((xa->xa_flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0));
|
|
||||||
|
|
||||||
/* mask can be any power of two value minus one */
|
|
||||||
MPASS((mask & (mask + 1)) == 0);
|
|
||||||
|
|
||||||
*pindex = (xa->xa_flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0;
|
*pindex = (xa->xa_flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0;
|
||||||
|
*pindex = MAX(*pindex, limit.min);
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
ptr = NULL_VALUE;
|
ptr = NULL_VALUE;
|
||||||
retry:
|
retry:
|
||||||
@@ -135,7 +132,7 @@ __xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t
|
|||||||
|
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
case -EEXIST:
|
case -EEXIST:
|
||||||
if (likely(*pindex != mask)) {
|
if (likely(*pindex < limit.max)) {
|
||||||
(*pindex)++;
|
(*pindex)++;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
@@ -154,7 +151,7 @@ __xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gfp)
|
xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, struct xa_limit limit, gfp_t gfp)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@@ -162,7 +159,7 @@ xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gf
|
|||||||
ptr = NULL_VALUE;
|
ptr = NULL_VALUE;
|
||||||
|
|
||||||
xa_lock(xa);
|
xa_lock(xa);
|
||||||
retval = __xa_alloc(xa, pindex, ptr, mask, gfp);
|
retval = __xa_alloc(xa, pindex, ptr, limit, gfp);
|
||||||
xa_unlock(xa);
|
xa_unlock(xa);
|
||||||
|
|
||||||
return (retval);
|
return (retval);
|
||||||
@@ -175,7 +172,7 @@ xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gf
|
|||||||
* beginning of the array. If the xarray is full -ENOMEM is returned.
|
* beginning of the array. If the xarray is full -ENOMEM is returned.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
__xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
|
__xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, struct xa_limit limit,
|
||||||
uint32_t *pnext_index, gfp_t gfp)
|
uint32_t *pnext_index, gfp_t gfp)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
@@ -183,13 +180,10 @@ __xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
|
|||||||
|
|
||||||
XA_ASSERT_LOCKED(xa);
|
XA_ASSERT_LOCKED(xa);
|
||||||
|
|
||||||
/* mask should allow to allocate at least one item */
|
MPASS(limit.max > limit.min);
|
||||||
MPASS(mask > ((xa->xa_flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0));
|
|
||||||
|
|
||||||
/* mask can be any power of two value minus one */
|
|
||||||
MPASS((mask & (mask + 1)) == 0);
|
|
||||||
|
|
||||||
*pnext_index = (xa->xa_flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0;
|
*pnext_index = (xa->xa_flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0;
|
||||||
|
*pnext_index = MAX(*pnext_index, limit.min);
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
ptr = NULL_VALUE;
|
ptr = NULL_VALUE;
|
||||||
retry:
|
retry:
|
||||||
@@ -197,14 +191,15 @@ __xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
|
|||||||
|
|
||||||
switch (retval) {
|
switch (retval) {
|
||||||
case -EEXIST:
|
case -EEXIST:
|
||||||
if (unlikely(*pnext_index == mask) && !timeout--) {
|
if (unlikely(*pnext_index == limit.max) && !timeout--) {
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(*pnext_index)++;
|
(*pnext_index)++;
|
||||||
(*pnext_index) &= mask;
|
if (*pnext_index > limit.max) {
|
||||||
if (*pnext_index == 0 && (xa->xa_flags & XA_FLAGS_ALLOC1) != 0)
|
*pnext_index = (xa->xa_flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0;
|
||||||
(*pnext_index)++;
|
*pnext_index = MAX(*pnext_index, limit.min);
|
||||||
|
}
|
||||||
goto retry;
|
goto retry;
|
||||||
case -ENOMEM:
|
case -ENOMEM:
|
||||||
if (likely(gfp & M_WAITOK)) {
|
if (likely(gfp & M_WAITOK)) {
|
||||||
@@ -221,13 +216,13 @@ __xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
|
xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, struct xa_limit limit,
|
||||||
uint32_t *pnext_index, gfp_t gfp)
|
uint32_t *pnext_index, gfp_t gfp)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
xa_lock(xa);
|
xa_lock(xa);
|
||||||
retval = __xa_alloc_cyclic(xa, pindex, ptr, mask, pnext_index, gfp);
|
retval = __xa_alloc_cyclic(xa, pindex, ptr, limit, pnext_index, gfp);
|
||||||
xa_unlock(xa);
|
xa_unlock(xa);
|
||||||
|
|
||||||
return (retval);
|
return (retval);
|
||||||
@@ -235,12 +230,12 @@ xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
|
|||||||
|
|
||||||
int
|
int
|
||||||
xa_alloc_cyclic_irq(struct xarray *xa, uint32_t *pindex, void *ptr,
|
xa_alloc_cyclic_irq(struct xarray *xa, uint32_t *pindex, void *ptr,
|
||||||
uint32_t mask, uint32_t *pnext_index, gfp_t gfp)
|
struct xa_limit limit, uint32_t *pnext_index, gfp_t gfp)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
xa_lock_irq(xa);
|
xa_lock_irq(xa);
|
||||||
retval = __xa_alloc_cyclic(xa, pindex, ptr, mask, pnext_index, gfp);
|
retval = __xa_alloc_cyclic(xa, pindex, ptr, limit, pnext_index, gfp);
|
||||||
xa_unlock_irq(xa);
|
xa_unlock_irq(xa);
|
||||||
|
|
||||||
return (retval);
|
return (retval);
|
||||||
|
|||||||
Reference in New Issue
Block a user