staticint validate_sla_id(struct adf_accel_dev *accel_dev, int sla_id)
{ struct rl_sla *sla;
if (sla_id <= RL_SLA_EMPTY_ID || sla_id >= RL_NODES_CNT_MAX) {
dev_notice(&GET_DEV(accel_dev), "Provided ID is out of bounds\n"); return -EINVAL;
}
sla = accel_dev->rate_limiting->sla[sla_id];
if (!sla) {
dev_notice(&GET_DEV(accel_dev), "SLA with provided ID does not exist\n"); return -EINVAL;
}
if (sla->type != RL_LEAF) {
dev_notice(&GET_DEV(accel_dev), "This ID is reserved for internal use\n"); return -EINVAL;
}
return 0;
}
/** * find_parent() - Find the parent for a new SLA * @rl_data: pointer to ratelimiting data * @sla_in: pointer to user input data for a new SLA * * Function returns a pointer to the parent SLA. If the parent ID is provided * as input in the user data, then such ID is validated and the parent SLA * is returned. * Otherwise, it returns the default parent SLA (root or cluster) for * the new object. * * Return: * * Pointer to the parent SLA object * * NULL - when parent cannot be found
*/ staticstruct rl_sla *find_parent(struct adf_rl *rl_data, struct adf_rl_sla_input_data *sla_in)
{ int input_parent_id = sla_in->parent_id; struct rl_sla *root = NULL; struct rl_sla *parent_sla; int i;
if (sla_in->type == RL_ROOT) return NULL;
if (input_parent_id > RL_PARENT_DEFAULT_ID) {
parent_sla = rl_data->sla[input_parent_id]; /* * SLA can be a parent if it has the same service as the child * and its type is higher in the hierarchy, * for example the parent type of a LEAF must be a CLUSTER.
*/ if (parent_sla && parent_sla->srv == sla_in->srv &&
parent_sla->type == sla_in->type - 1) return parent_sla;
return NULL;
}
/* If input_parent_id is not valid, get root for this service type. */ for (i = 0; i < RL_ROOT_MAX; i++) { if (rl_data->root[i] && rl_data->root[i]->srv == sla_in->srv) {
root = rl_data->root[i]; break;
}
}
if (!root) return NULL;
/* * If the type of this SLA is cluster, then return the root. * Otherwise, find the default (i.e. first) cluster for this service.
*/ if (sla_in->type == RL_CLUSTER) return root;
for (i = 0; i < RL_CLUSTER_MAX; i++) { if (rl_data->cluster[i] && rl_data->cluster[i]->parent == root) return rl_data->cluster[i];
}
return NULL;
}
/** * adf_rl_get_sla_arr_of_type() - Returns a pointer to SLA type specific array * @rl_data: pointer to ratelimiting data * @type: SLA type * @sla_arr: pointer to variable where requested pointer will be stored * * Return: Max number of elements allowed for the returned array
*/
u32 adf_rl_get_sla_arr_of_type(struct adf_rl *rl_data, enum rl_node_type type, struct rl_sla ***sla_arr)
{ switch (type) { case RL_LEAF:
*sla_arr = rl_data->leaf; return RL_LEAF_MAX; case RL_CLUSTER:
*sla_arr = rl_data->cluster; return RL_CLUSTER_MAX; case RL_ROOT:
*sla_arr = rl_data->root; return RL_ROOT_MAX; default:
*sla_arr = NULL; return 0;
}
}
/** * prepare_rp_ids() - Creates an array of ring pair IDs from bitmask * @accel_dev: pointer to acceleration device structure * @sla: SLA object data where result will be written * @rp_mask: bitmask of ring pair IDs * * Function tries to convert provided bitmap to an array of IDs. It checks if * RPs aren't in use, are assigned to SLA service or if a number of provided * IDs is not too big. If successful, writes the result into the field * sla->ring_pairs_cnt. * * Return: * * 0 - ok * * -EINVAL - ring pairs array cannot be created from provided mask
*/ staticint prepare_rp_ids(struct adf_accel_dev *accel_dev, struct rl_sla *sla, constunsignedlong rp_mask)
{ enum adf_cfg_service_type arb_srv = adf_srv_to_cfg_svc_type(sla->srv);
u16 rps_per_bundle = GET_HW_DATA(accel_dev)->num_banks_per_vf; bool *rp_in_use = accel_dev->rate_limiting->rp_in_use;
size_t rp_cnt_max = ARRAY_SIZE(sla->ring_pairs_ids);
u16 rp_id_max = GET_HW_DATA(accel_dev)->num_banks;
u16 cnt = 0;
u16 rp_id;
for_each_set_bit(rp_id, &rp_mask, rp_id_max) { if (cnt >= rp_cnt_max) {
dev_notice(&GET_DEV(accel_dev), "Assigned more ring pairs than supported"); return -EINVAL;
}
if (rp_in_use[rp_id]) {
dev_notice(&GET_DEV(accel_dev), "RP %u already assigned to other SLA", rp_id); return -EINVAL;
}
if (GET_SRV_TYPE(accel_dev, rp_id % rps_per_bundle) != arb_srv) {
dev_notice(&GET_DEV(accel_dev), "RP %u does not support SLA service", rp_id); return -EINVAL;
}
/** * can_parent_afford_sla() - Verifies if parent allows to create an SLA * @sla_in: pointer to user input data for a new SLA * @sla_parent: pointer to parent SLA object * @sla_cir: current child CIR value (only for update) * @is_update: request is a update * * Algorithm verifies if parent has enough remaining budget to take assignment * of a child with provided parameters. In update case current CIR value must be * returned to budget first. * PIR value cannot exceed the PIR assigned to parent. * * Return: * * true - SLA can be created * * false - SLA cannot be created
*/ staticbool can_parent_afford_sla(struct adf_rl_sla_input_data *sla_in, struct rl_sla *sla_parent, u32 sla_cir, bool is_update)
{
u32 rem_cir = sla_parent->rem_cir;
if (is_update)
rem_cir += sla_cir;
if (sla_in->cir > rem_cir || sla_in->pir > sla_parent->pir) returnfalse;
returntrue;
}
/** * can_node_afford_update() - Verifies if SLA can be updated with input data * @sla_in: pointer to user input data for a new SLA * @sla: pointer to SLA object selected for update * * Algorithm verifies if a new CIR value is big enough to satisfy currently * assigned child SLAs and if PIR can be updated * * Return: * * true - SLA can be updated * * false - SLA cannot be updated
*/ staticbool can_node_afford_update(struct adf_rl_sla_input_data *sla_in, struct rl_sla *sla)
{
u32 cir_in_use = sla->cir - sla->rem_cir;
/* new CIR cannot be smaller then currently consumed value */ if (cir_in_use > sla_in->cir) returnfalse;
/* PIR of root/cluster cannot be reduced in node with assigned children */ if (sla_in->pir < sla->pir && sla->type != RL_LEAF && cir_in_use > 0) returnfalse;
if (sla_in->cir > max_val || sla_in->pir > max_val)
ret = false;
switch (sla->type) { case RL_LEAF:
ret &= can_parent_afford_sla(sla_in, parent, sla->cir,
is_update); break; case RL_CLUSTER:
ret &= can_parent_afford_sla(sla_in, parent, sla->cir,
is_update);
if (is_update)
ret &= can_node_afford_update(sla_in, sla);
break; case RL_ROOT: if (is_update)
ret &= can_node_afford_update(sla_in, sla);
break; default:
ret = false; break;
}
return ret;
}
staticvoid update_budget(struct rl_sla *sla, u32 old_cir, bool is_update)
{ switch (sla->type) { case RL_LEAF: if (is_update)
sla->parent->rem_cir += old_cir;
/** * get_next_free_sla_id() - finds next free ID in the SLA array * @rl_data: Pointer to ratelimiting data structure * * Return: * * 0 : RL_NODES_CNT_MAX - correct ID * * -ENOSPC - all SLA slots are in use
*/ staticint get_next_free_sla_id(struct adf_rl *rl_data)
{ int i = 0;
while (i < RL_NODES_CNT_MAX && rl_data->sla[i++])
;
if (i == RL_NODES_CNT_MAX) return -ENOSPC;
return i - 1;
}
/** * get_next_free_node_id() - finds next free ID in the array of that node type * @rl_data: Pointer to ratelimiting data structure * @sla: Pointer to SLA object for which the ID is searched * * Return: * * 0 : RL_[NODE_TYPE]_MAX - correct ID * * -ENOSPC - all slots of that type are in use
*/ staticint get_next_free_node_id(struct adf_rl *rl_data, struct rl_sla *sla)
{ struct adf_hw_device_data *hw_device = GET_HW_DATA(rl_data->accel_dev); int max_id, i, step, rp_per_leaf; struct rl_sla **sla_list;
/** * add_new_sla_entry() - creates a new SLA object and fills it with user data * @accel_dev: pointer to acceleration device structure * @sla_in: pointer to user input data for a new SLA * @sla_out: Pointer to variable that will contain the address of a new * SLA object if the operation succeeds * * Return: * * 0 - ok * * -ENOMEM - memory allocation failed * * -EINVAL - invalid user input * * -ENOSPC - all available SLAs are in use
*/ staticint add_new_sla_entry(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in, struct rl_sla **sla_out)
{ struct adf_rl *rl_data = accel_dev->rate_limiting; struct rl_sla *sla; int ret = 0;
sla = kzalloc(sizeof(*sla), GFP_KERNEL); if (!sla) {
ret = -ENOMEM; goto ret_err;
}
*sla_out = sla;
if (!adf_is_service_enabled(accel_dev, sla_in->srv)) {
dev_notice(&GET_DEV(accel_dev), "Provided service is not enabled\n");
ret = -EINVAL; goto ret_err;
}
sla->srv = sla_in->srv;
sla->type = sla_in->type;
ret = get_next_free_node_id(rl_data, sla); if (ret < 0) {
dev_notice(&GET_DEV(accel_dev), "Exceeded number of available nodes for that service\n"); goto ret_err;
}
sla->node_id = ret;
ret = get_next_free_sla_id(rl_data); if (ret < 0) {
dev_notice(&GET_DEV(accel_dev), "Allocated maximum SLAs number\n"); goto ret_err;
}
sla->sla_id = ret;
sla->parent = find_parent(rl_data, sla_in); if (!sla->parent && sla->type != RL_ROOT) { if (sla_in->parent_id != RL_PARENT_DEFAULT_ID)
dev_notice(&GET_DEV(accel_dev), "Provided parent ID does not exist or cannot be parent for this SLA."); else
dev_notice(&GET_DEV(accel_dev), "Unable to find parent node for this service. Is service enabled?");
ret = -EINVAL; goto ret_err;
}
if (sla->type == RL_LEAF) {
ret = prepare_rp_ids(accel_dev, sla, sla_in->rp_mask); if (!sla->ring_pairs_cnt || ret) {
dev_notice(&GET_DEV(accel_dev), "Unable to find ring pairs to assign to the leaf"); if (!ret)
ret = -EINVAL;
goto ret_err;
}
}
return 0;
ret_err:
kfree(sla);
*sla_out = NULL;
return ret;
}
staticint initialize_default_nodes(struct adf_accel_dev *accel_dev)
{ struct adf_rl *rl_data = accel_dev->rate_limiting; struct adf_rl_hw_data *device_data = rl_data->device_data; struct adf_rl_sla_input_data sla_in = { }; int ret = 0; int i;
/* Init root for each enabled service */
sla_in.type = RL_ROOT;
sla_in.parent_id = RL_PARENT_DEFAULT_ID;
for (i = 0; i < SVC_BASE_COUNT; i++) { if (!adf_is_service_enabled(accel_dev, i)) continue;
/** * add_update_sla() - handles the creation and the update of an SLA * @accel_dev: pointer to acceleration device structure * @sla_in: pointer to user input data for a new/updated SLA * @is_update: flag to indicate if this is an update or an add operation * * Return: * * 0 - ok * * -ENOMEM - memory allocation failed * * -EINVAL - user input data cannot be used to create SLA * * -ENOSPC - all available SLAs are in use
*/ staticint add_update_sla(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in, bool is_update)
{ struct adf_rl *rl_data = accel_dev->rate_limiting; struct rl_sla **sla_type_arr = NULL; struct rl_sla *sla = NULL;
u32 old_cir = 0; int ret;
if (!sla_in) {
dev_warn(&GET_DEV(accel_dev), "SLA input data pointer is missing\n"); return -EFAULT;
}
mutex_lock(&rl_data->rl_lock);
/* Input validation */
ret = validate_user_input(accel_dev, sla_in, is_update); if (ret) goto ret_err;
if (is_update) {
ret = validate_sla_id(accel_dev, sla_in->sla_id); if (ret) goto ret_err;
sla = rl_data->sla[sla_in->sla_id];
old_cir = sla->cir;
} else {
ret = add_new_sla_entry(accel_dev, sla_in, &sla); if (ret) goto ret_err;
}
if (!is_enough_budget(rl_data, sla, sla_in, is_update)) {
dev_notice(&GET_DEV(accel_dev), "Input value exceeds the remaining budget%s\n",
is_update ? " or more budget is already in use" : "");
ret = -EINVAL; goto ret_err;
}
sla->cir = sla_in->cir;
sla->pir = sla_in->pir;
/* Apply SLA */
assign_node_to_parent(accel_dev, sla, false);
ret = adf_rl_send_admin_add_update_msg(accel_dev, sla, is_update); if (ret) {
dev_notice(&GET_DEV(accel_dev), "Failed to apply an SLA\n"); goto ret_err;
}
update_budget(sla, old_cir, is_update);
/** * adf_rl_add_sla() - handles the creation of an SLA * @accel_dev: pointer to acceleration device structure * @sla_in: pointer to user input data required to add an SLA * * Return: * * 0 - ok * * -ENOMEM - memory allocation failed * * -EINVAL - invalid user input * * -ENOSPC - all available SLAs are in use
*/ int adf_rl_add_sla(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in)
{ return add_update_sla(accel_dev, sla_in, false);
}
/** * adf_rl_update_sla() - handles the update of an SLA * @accel_dev: pointer to acceleration device structure * @sla_in: pointer to user input data required to update an SLA * * Return: * * 0 - ok * * -EINVAL - user input data cannot be used to update SLA
*/ int adf_rl_update_sla(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in)
{ return add_update_sla(accel_dev, sla_in, true);
}
/** * adf_rl_get_sla() - returns an existing SLA data * @accel_dev: pointer to acceleration device structure * @sla_in: pointer to user data where SLA info will be stored * * The sla_id for which data are requested should be set in sla_id structure * * Return: * * 0 - ok * * -EINVAL - provided sla_id does not exist
*/ int adf_rl_get_sla(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in)
{ struct rl_sla *sla; int ret, i;
ret = validate_sla_id(accel_dev, sla_in->sla_id); if (ret) return ret;
for (i = 0; i < sla->ring_pairs_cnt; i++)
sla_in->rp_mask |= BIT(sla->ring_pairs_ids[i]);
return 0;
}
/** * adf_rl_get_capability_remaining() - returns the remaining SLA value (CIR) for * selected service or provided sla_id * @accel_dev: pointer to acceleration device structure * @srv: service ID for which capability is requested * @sla_id: ID of the cluster or root to which we want assign a new SLA * * Check if the provided SLA id is valid. If it is and the service matches * the requested service and the type is cluster or root, return the remaining * capability. * If the provided ID does not match the service or type, return the remaining * capacity of the default cluster for that service. * * Return: * * Positive value - correct remaining value * * -EINVAL - algorithm cannot find a remaining value for provided data
*/ int adf_rl_get_capability_remaining(struct adf_accel_dev *accel_dev, enum adf_base_services srv, int sla_id)
{ struct adf_rl *rl_data = accel_dev->rate_limiting; struct rl_sla *sla = NULL; int i;
/** * adf_rl_remove_sla() - removes provided sla_id * @accel_dev: pointer to acceleration device structure * @sla_id: ID of the cluster or root to which we want assign an new SLA * * Return: * * 0 - ok * * -EINVAL - wrong sla_id or it still have assigned children
*/ int adf_rl_remove_sla(struct adf_accel_dev *accel_dev, u32 sla_id)
{ struct adf_rl *rl_data = accel_dev->rate_limiting; struct rl_sla *sla; int ret = 0;
mutex_lock(&rl_data->rl_lock);
ret = validate_sla_id(accel_dev, sla_id); if (ret) goto err_ret;
sla = rl_data->sla[sla_id];
if (sla->type < RL_LEAF && sla->rem_cir != sla->cir) {
dev_notice(&GET_DEV(accel_dev), "To remove parent SLA all its children must be removed first");
ret = -EINVAL; goto err_ret;
}
/** * adf_rl_remove_sla_all() - removes all SLAs from device * @accel_dev: pointer to acceleration device structure * @incl_default: set to true if default SLAs also should be removed
*/ void adf_rl_remove_sla_all(struct adf_accel_dev *accel_dev, bool incl_default)
{ struct adf_rl *rl_data = accel_dev->rate_limiting; int end_type = incl_default ? RL_ROOT : RL_LEAF; struct rl_sla **sla_type_arr = NULL;
u32 max_id; int i, j;
mutex_lock(&rl_data->rl_lock);
/* Unregister and remove all SLAs */ for (j = RL_LEAF; j >= end_type; j--) {
max_id = adf_rl_get_sla_arr_of_type(rl_data, j, &sla_type_arr);
for (i = 0; i < max_id; i++) { if (!sla_type_arr[i]) continue;
clear_sla(rl_data, sla_type_arr[i]);
}
}
mutex_unlock(&rl_data->rl_lock);
}
int adf_rl_init(struct adf_accel_dev *accel_dev)
{ struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); struct adf_rl_hw_data *rl_hw_data = &hw_data->rl_data; struct adf_rl *rl; int ret = 0;
if (!accel_dev->rate_limiting) {
ret = -EOPNOTSUPP; goto ret_err;
}
if ((fw_caps & RL_CAPABILITY_MASK) != RL_CAPABILITY_VALUE) {
dev_info(&GET_DEV(accel_dev), "feature not supported by FW\n");
ret = -EOPNOTSUPP; goto ret_free;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.