/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2024 Ventana Micro Systems Inc. */ #include #include #include #include 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); }