// SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2023 Intel Corporation */ #define dev_fmt(fmt) … #include <asm/errno.h> #include <asm/div64.h> #include <linux/dev_printk.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/units.h> #include "adf_accel_devices.h" #include "adf_common_drv.h" #include "adf_rl_admin.h" #include "adf_rl.h" #include "adf_sysfs_rl.h" #define RL_TOKEN_GRANULARITY_PCIEIN_BUCKET … #define RL_TOKEN_GRANULARITY_PCIEOUT_BUCKET … #define RL_TOKEN_PCIE_SIZE … #define RL_TOKEN_ASYM_SIZE … #define RL_CSR_SIZE … #define RL_CAPABILITY_MASK … #define RL_CAPABILITY_VALUE … #define RL_VALIDATE_NON_ZERO(input) … #define ROOT_MASK … #define CLUSTER_MASK … #define LEAF_MASK … static int validate_user_input(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in, bool is_update) { … } static int validate_sla_id(struct adf_accel_dev *accel_dev, int sla_id) { … } /** * 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 */ static struct rl_sla *find_parent(struct adf_rl *rl_data, struct adf_rl_sla_input_data *sla_in) { … } static enum adf_cfg_service_type srv_to_cfg_svc_type(enum adf_base_services rl_srv) { … } /** * 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) { … } static bool is_service_enabled(struct adf_accel_dev *accel_dev, enum adf_base_services rl_srv) { … } /** * 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 */ static int prepare_rp_ids(struct adf_accel_dev *accel_dev, struct rl_sla *sla, const unsigned long rp_mask) { … } static void mark_rps_usage(struct rl_sla *sla, bool *rp_in_use, bool used) { … } static void assign_rps_to_leaf(struct adf_accel_dev *accel_dev, struct rl_sla *sla, bool clear) { … } static void assign_leaf_to_cluster(struct adf_accel_dev *accel_dev, struct rl_sla *sla, bool clear) { … } static void assign_cluster_to_root(struct adf_accel_dev *accel_dev, struct rl_sla *sla, bool clear) { … } static void assign_node_to_parent(struct adf_accel_dev *accel_dev, struct rl_sla *sla, bool clear_assignment) { … } /** * 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 */ static bool can_parent_afford_sla(struct adf_rl_sla_input_data *sla_in, struct rl_sla *sla_parent, u32 sla_cir, bool is_update) { … } /** * 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 */ static bool can_node_afford_update(struct adf_rl_sla_input_data *sla_in, struct rl_sla *sla) { … } static bool is_enough_budget(struct adf_rl *rl_data, struct rl_sla *sla, struct adf_rl_sla_input_data *sla_in, bool is_update) { … } static void update_budget(struct rl_sla *sla, u32 old_cir, bool is_update) { … } /** * 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 */ static int get_next_free_sla_id(struct adf_rl *rl_data) { … } /** * 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 */ static int get_next_free_node_id(struct adf_rl *rl_data, struct rl_sla *sla) { … } u32 adf_rl_calculate_slice_tokens(struct adf_accel_dev *accel_dev, u32 sla_val, enum adf_base_services svc_type) { … } u32 adf_rl_calculate_ae_cycles(struct adf_accel_dev *accel_dev, u32 sla_val, enum adf_base_services svc_type) { … } u32 adf_rl_calculate_pci_bw(struct adf_accel_dev *accel_dev, u32 sla_val, enum adf_base_services svc_type, bool is_bw_out) { … } /** * 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 */ static int add_new_sla_entry(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in, struct rl_sla **sla_out) { … } static int initialize_default_nodes(struct adf_accel_dev *accel_dev) { … } static void clear_sla(struct adf_rl *rl_data, struct rl_sla *sla) { … } static void free_all_sla(struct adf_accel_dev *accel_dev) { … } /** * 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 */ static int add_update_sla(struct adf_accel_dev *accel_dev, struct adf_rl_sla_input_data *sla_in, bool 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } int adf_rl_init(struct adf_accel_dev *accel_dev) { … } int adf_rl_start(struct adf_accel_dev *accel_dev) { … } void adf_rl_stop(struct adf_accel_dev *accel_dev) { … } void adf_rl_exit(struct adf_accel_dev *accel_dev) { … }