* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ka_base_pub.h"
#include "svm_log.h"
#include "devmm_common.h"
#include "svm_res_idr.h"
void devmm_idr_init(struct svm_idr *idr, int max_id)
{
ka_base_idr_init(&idr->idr);
idr->next_id = 0;
idr->max_id = max_id;
ka_task_mutex_init(&idr->lock);
}
int devmm_idr_alloc(struct svm_idr *idr, char *ptr, int *id_out)
{
int id;
ka_task_mutex_lock(&idr->lock);
id = ka_base_idr_alloc(&idr->idr, ptr, idr->next_id, idr->max_id, KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (id < 0) {
if (idr->next_id != 0) {
id = ka_base_idr_alloc(&idr->idr, ptr, 0, idr->next_id, KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
}
if (id < 0) {
ka_task_mutex_unlock(&idr->lock);
devmm_drv_err("Idr alloc fail. (ret=%d, max_num=%d)\n", id, idr->max_id);
return id;
}
}
idr->next_id = (id + 1) % idr->max_id;
*id_out = id;
ka_task_mutex_unlock(&idr->lock);
return 0;
}
char *devmm_idr_get_and_remove(struct svm_idr *idr, int id, idr_remove_condition condition)
{
char *ptr = NULL;
ka_task_mutex_lock(&idr->lock);
ptr = ka_base_idr_find(&idr->idr, id);
if (ptr != NULL) {
if ((condition != NULL) && (condition(ptr) == false)) {
ptr = NULL;
goto find_fail;
}
ka_base_idr_remove(&idr->idr, id);
}
find_fail:
ka_task_mutex_unlock(&idr->lock);
return ptr;
}
bool devmm_idr_is_empty(struct svm_idr *idr)
{
return ka_base_idr_is_empty(&idr->idr);
}
void devmm_idr_destroy(struct svm_idr *idr, void (*free_ptr)(const void *ptr))
{
char *entry = NULL;
int id;
ka_task_mutex_lock(&idr->lock);
ka_base_idr_for_each_entry(&idr->idr, entry, id) {
if (free_ptr != NULL) {
free_ptr(entry);
entry = NULL;
}
ka_base_idr_remove(&idr->idr, id);
}
ka_base_idr_destroy(&idr->idr);
ka_task_mutex_unlock(&idr->lock);
}