| /* |
| * Copyright (c) 2022-2023, Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Arm SiP services service ID manager and ID mapping table force |
| * clients and transactions. |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/drivers/sip_svc/sip_svc_proto.h> |
| #include "sip_svc_id_mgr.h" |
| |
| /** |
| * Create a id key pool using size variable 0..size-1, where we can |
| * track the allocated id. |
| */ |
| struct sip_svc_id_pool *sip_svc_id_mgr_create(uint32_t size) |
| { |
| struct sip_svc_id_pool *id_pool = NULL; |
| uint32_t mask_size = 0; |
| uint32_t i = 0; |
| |
| if (size == SIP_SVC_ID_INVALID) { |
| return NULL; |
| } |
| |
| /* Allocate memory for ID pool */ |
| id_pool = k_malloc(sizeof(struct sip_svc_id_pool)); |
| if (!id_pool) { |
| return NULL; |
| } |
| id_pool->size = size; |
| |
| id_pool->id_list = k_malloc(size * sizeof(uint32_t)); |
| if (!id_pool->id_list) { |
| k_free(id_pool); |
| return NULL; |
| } |
| |
| mask_size = size / sizeof(uint32_t); |
| if (size % sizeof(uint32_t)) { |
| mask_size++; |
| } |
| |
| id_pool->id_mask = k_malloc(mask_size * sizeof(uint32_t)); |
| if (!id_pool->id_mask) { |
| k_free(id_pool->id_list); |
| k_free(id_pool); |
| return NULL; |
| } |
| |
| /* Initialize ID */ |
| for (i = 0; i < size; i++) { |
| id_pool->id_list[i] = i; |
| } |
| |
| /* ID pool is full during initialization */ |
| id_pool->head = 0; |
| id_pool->tail = size - 1; |
| |
| /* Initialize ID in use flags */ |
| for (i = 0; i < mask_size; i++) { |
| id_pool->id_mask[i] = 0; |
| } |
| |
| return id_pool; |
| } |
| |
| /* Delete a created id pool*/ |
| void sip_svc_id_mgr_delete(struct sip_svc_id_pool *id_pool) |
| { |
| if (id_pool) { |
| k_free(id_pool->id_mask); |
| k_free(id_pool->id_list); |
| k_free(id_pool); |
| } |
| } |
| |
| /* Retrieve an id from the id pool*/ |
| uint32_t sip_svc_id_mgr_alloc(struct sip_svc_id_pool *id_pool) |
| { |
| uint32_t id; |
| uint32_t row; |
| uint32_t col; |
| |
| if (!id_pool) { |
| return SIP_SVC_ID_INVALID; |
| } |
| |
| if (id_pool->head == SIP_SVC_ID_INVALID) { |
| return SIP_SVC_ID_INVALID; |
| } |
| |
| id = id_pool->id_list[id_pool->head]; |
| |
| /* Calculate the mask bit position in id mask array*/ |
| row = id / sizeof(uint32_t); |
| col = id % sizeof(uint32_t); |
| id_pool->id_mask[row] |= (1 << col); |
| |
| if (id_pool->head == id_pool->tail) { |
| id_pool->head = SIP_SVC_ID_INVALID; |
| id_pool->tail = SIP_SVC_ID_INVALID; |
| } else { |
| id_pool->head++; |
| if (id_pool->head == id_pool->size) { |
| id_pool->head = 0; |
| } |
| } |
| |
| return id; |
| } |
| |
| /* Free the id that was allocated from the id_pool*/ |
| void sip_svc_id_mgr_free(struct sip_svc_id_pool *id_pool, uint32_t id) |
| { |
| uint32_t row; |
| uint32_t col; |
| |
| if (!id_pool) { |
| return; |
| } |
| |
| if (id >= id_pool->size) { |
| return; |
| } |
| |
| row = id / sizeof(uint32_t); |
| col = id % sizeof(uint32_t); |
| |
| /* check if the id was allocated earlier*/ |
| if (!(id_pool->id_mask[row] & (1 << col))) { |
| return; |
| } |
| |
| /* Clear the id mask bit */ |
| id_pool->id_mask[row] &= ~(1 << col); |
| |
| if (id_pool->head == SIP_SVC_ID_INVALID) { |
| id_pool->head = 0; |
| id_pool->tail = 0; |
| } else { |
| id_pool->tail++; |
| if (id_pool->tail == id_pool->size) { |
| id_pool->tail = 0; |
| } |
| if (id_pool->head == id_pool->tail) { |
| return; |
| } |
| } |
| |
| id_pool->id_list[id_pool->tail] = id; |
| } |
| |
| /* Allocate database to store values */ |
| struct sip_svc_id_map *sip_svc_id_map_create(uint32_t size) |
| { |
| struct sip_svc_id_map *id_map = NULL; |
| uint32_t items_size = (sizeof(struct sip_svc_id_map_item)) * size; |
| int i; |
| |
| id_map = k_malloc(sizeof(struct sip_svc_id_map)); |
| if (!id_map) { |
| return NULL; |
| } |
| |
| id_map->items = k_malloc(items_size); |
| if (!id_map->items) { |
| k_free(id_map); |
| return NULL; |
| } |
| |
| id_map->size = size; |
| for (i = 0; i < size; i++) { |
| id_map->items[i].id = SIP_SVC_ID_INVALID; |
| id_map->items[i].arg1 = NULL; |
| id_map->items[i].arg2 = NULL; |
| id_map->items[i].arg3 = NULL; |
| id_map->items[i].arg4 = NULL; |
| id_map->items[i].arg5 = NULL; |
| id_map->items[i].arg6 = NULL; |
| } |
| |
| return id_map; |
| } |
| |
| |
| /* Delete a created database */ |
| void sip_svc_id_map_delete(struct sip_svc_id_map *id_map) |
| { |
| if (id_map) { |
| k_free(id_map->items); |
| k_free(id_map); |
| } |
| } |
| |
| /* Retrieve index from from database with key(id)*/ |
| static int sip_svc_id_map_get_idx(struct sip_svc_id_map *id_map, uint32_t id) |
| { |
| int i; |
| |
| if (!id_map) { |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < id_map->size; i++) { |
| if (id_map->items[i].id == id) { |
| return i; |
| } |
| } |
| |
| return -EINVAL; |
| } |
| |
| /* Insert an entry into database with key as id*/ |
| int sip_svc_id_map_insert_item(struct sip_svc_id_map *id_map, uint32_t id, void *arg1, void *arg2, |
| void *arg3, void *arg4, void *arg5, void *arg6) |
| { |
| int i; |
| |
| if (!id_map) { |
| return -EINVAL; |
| } |
| |
| i = sip_svc_id_map_get_idx(id_map, SIP_SVC_ID_INVALID); |
| if (i < 0) { |
| return -EINVAL; |
| } |
| |
| id_map->items[i].id = id; |
| id_map->items[i].arg1 = arg1; |
| id_map->items[i].arg2 = arg2; |
| id_map->items[i].arg3 = arg3; |
| id_map->items[i].arg4 = arg4; |
| id_map->items[i].arg5 = arg5; |
| id_map->items[i].arg6 = arg6; |
| |
| return 0; |
| } |
| |
| /* Remove an entry with key id */ |
| int sip_svc_id_map_remove_item(struct sip_svc_id_map *id_map, uint32_t id) |
| { |
| int i; |
| |
| if (!id_map) { |
| return -EINVAL; |
| } |
| |
| i = sip_svc_id_map_get_idx(id_map, id); |
| if (i < 0) { |
| return -EINVAL; |
| } |
| |
| id_map->items[i].id = SIP_SVC_ID_INVALID; |
| id_map->items[i].arg1 = NULL; |
| id_map->items[i].arg2 = NULL; |
| id_map->items[i].arg3 = NULL; |
| id_map->items[i].arg4 = NULL; |
| id_map->items[i].arg5 = NULL; |
| id_map->items[i].arg6 = NULL; |
| |
| return 0; |
| } |
| |
| /* Query an entry from database using key id*/ |
| struct sip_svc_id_map_item *sip_svc_id_map_query_item(struct sip_svc_id_map *id_map, uint32_t id) |
| { |
| int i; |
| |
| if (!id_map) { |
| return NULL; |
| } |
| |
| i = sip_svc_id_map_get_idx(id_map, id); |
| if (i < 0) { |
| return NULL; |
| } |
| |
| return &id_map->items[i]; |
| } |