mirror of
				https://github.com/riscv-software-src/opensbi
				synced 2025-11-04 05:50:22 +00:00 
			
		
		
		
	Different parts of OpenSBI require their own per-domain data so introduce domain data (or sbi_domain_data) which can be registered by any part of OpenSBI. Using the domain data, the domain framework will create a data pointer for every domain which can be used to maintain some per-domain state. Signed-off-by: Anup Patel <apatel@ventanamicro.com> Reviewed-by: Yu Chien Peter Lin <peterlin@andestech.com>
		
			
				
	
	
		
			139 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * SPDX-License-Identifier: BSD-2-Clause
 | 
						|
 *
 | 
						|
 * Copyright (c) 2024 Ventana Micro Systems Inc.
 | 
						|
 */
 | 
						|
 | 
						|
#include <sbi/sbi_bitmap.h>
 | 
						|
#include <sbi/sbi_domain.h>
 | 
						|
#include <sbi/sbi_error.h>
 | 
						|
#include <sbi/sbi_heap.h>
 | 
						|
 | 
						|
static SBI_LIST_HEAD(data_list);
 | 
						|
static DECLARE_BITMAP(data_idx_bmap, SBI_DOMAIN_MAX_DATA_PTRS);
 | 
						|
 | 
						|
void *sbi_domain_data_ptr(struct sbi_domain *dom, struct sbi_domain_data *data)
 | 
						|
{
 | 
						|
	if (dom && data && data->data_idx < SBI_DOMAIN_MAX_DATA_PTRS)
 | 
						|
		return dom->data_priv.idx_to_data_ptr[data->data_idx];
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int domain_setup_data_one(struct sbi_domain *dom,
 | 
						|
				 struct sbi_domain_data *data)
 | 
						|
{
 | 
						|
	struct sbi_domain_data_priv *priv = &dom->data_priv;
 | 
						|
	void *data_ptr;
 | 
						|
	int rc;
 | 
						|
 | 
						|
	if (priv->idx_to_data_ptr[data->data_idx])
 | 
						|
		return SBI_EALREADY;
 | 
						|
 | 
						|
	data_ptr = sbi_zalloc(data->data_size);
 | 
						|
	if (!data_ptr) {
 | 
						|
		sbi_domain_cleanup_data(dom);
 | 
						|
		return SBI_ENOMEM;
 | 
						|
	}
 | 
						|
 | 
						|
	if (data->data_setup) {
 | 
						|
		rc = data->data_setup(dom, data, data_ptr);
 | 
						|
		if (rc) {
 | 
						|
			sbi_free(data_ptr);
 | 
						|
			return rc;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	priv->idx_to_data_ptr[data->data_idx] = data_ptr;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void domain_cleanup_data_one(struct sbi_domain *dom,
 | 
						|
				    struct sbi_domain_data *data)
 | 
						|
{
 | 
						|
	struct sbi_domain_data_priv *priv = &dom->data_priv;
 | 
						|
	void *data_ptr;
 | 
						|
 | 
						|
	data_ptr = priv->idx_to_data_ptr[data->data_idx];
 | 
						|
	if (!data_ptr)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (data->data_cleanup)
 | 
						|
		data->data_cleanup(dom, data, data_ptr);
 | 
						|
 | 
						|
	sbi_free(data_ptr);
 | 
						|
	priv->idx_to_data_ptr[data->data_idx] = NULL;
 | 
						|
}
 | 
						|
 | 
						|
int sbi_domain_setup_data(struct sbi_domain *dom)
 | 
						|
{
 | 
						|
	struct sbi_domain_data *data;
 | 
						|
	int rc;
 | 
						|
 | 
						|
	if (!dom)
 | 
						|
		return SBI_EINVAL;
 | 
						|
 | 
						|
	sbi_list_for_each_entry(data, &data_list, head) {
 | 
						|
		rc = domain_setup_data_one(dom, data);
 | 
						|
		if (rc) {
 | 
						|
			sbi_domain_cleanup_data(dom);
 | 
						|
			return rc;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void sbi_domain_cleanup_data(struct sbi_domain *dom)
 | 
						|
{
 | 
						|
	struct sbi_domain_data *data;
 | 
						|
 | 
						|
	if (!dom)
 | 
						|
		return;
 | 
						|
 | 
						|
	sbi_list_for_each_entry(data, &data_list, head)
 | 
						|
		domain_cleanup_data_one(dom, data);
 | 
						|
}
 | 
						|
 | 
						|
int sbi_domain_register_data(struct sbi_domain_data *data)
 | 
						|
{
 | 
						|
	struct sbi_domain *dom;
 | 
						|
	u32 data_idx;
 | 
						|
	int rc;
 | 
						|
 | 
						|
	if (!data || !data->data_size)
 | 
						|
		return SBI_EINVAL;
 | 
						|
 | 
						|
	for (data_idx = 0; data_idx < SBI_DOMAIN_MAX_DATA_PTRS; data_idx++) {
 | 
						|
		if (!bitmap_test(data_idx_bmap, data_idx))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (SBI_DOMAIN_MAX_DATA_PTRS <= data_idx)
 | 
						|
		return SBI_ENOSPC;
 | 
						|
	bitmap_set(data_idx_bmap, data_idx, 1);
 | 
						|
 | 
						|
	data->data_idx = data_idx;
 | 
						|
	sbi_list_add_tail(&data->head, &data_list);
 | 
						|
 | 
						|
	sbi_domain_for_each(dom) {
 | 
						|
		rc = domain_setup_data_one(dom, data);
 | 
						|
		if (rc) {
 | 
						|
			sbi_domain_unregister_data(data);
 | 
						|
			return rc;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void sbi_domain_unregister_data(struct sbi_domain_data *data)
 | 
						|
{
 | 
						|
	struct sbi_domain *dom;
 | 
						|
 | 
						|
	sbi_domain_for_each(dom)
 | 
						|
		domain_cleanup_data_one(dom, data);
 | 
						|
 | 
						|
	sbi_list_del(&data->head);
 | 
						|
	bitmap_clear(data_idx_bmap, data->data_idx, 1);
 | 
						|
}
 |