| /* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 and |
| * only version 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <linux/slab.h> |
| #include "ipa_rm_i.h" |
| |
| /** |
| * ipa_rm_peers_list_get_resource_index() - resource name to index |
| * of this resource in corresponding peers list |
| * @resource_name: [in] resource name |
| * |
| * Returns: resource index mapping, IPA_RM_INDEX_INVALID |
| * in case provided resource name isn't contained in enum |
| * ipa_rm_resource_name. |
| * |
| */ |
| static int ipa_rm_peers_list_get_resource_index( |
| enum ipa_rm_resource_name resource_name) |
| { |
| int resource_index = IPA_RM_INDEX_INVALID; |
| |
| if (IPA_RM_RESORCE_IS_PROD(resource_name)) |
| resource_index = ipa_rm_prod_index(resource_name); |
| else if (IPA_RM_RESORCE_IS_CONS(resource_name)) { |
| resource_index = ipa_rm_cons_index(resource_name); |
| } |
| |
| return resource_index; |
| } |
| |
| static bool ipa_rm_peers_list_check_index(int index, |
| struct ipa_rm_peers_list *peers_list) |
| { |
| return !(index > peers_list->max_peers || index < 0); |
| } |
| |
| /** |
| * ipa_rm_peers_list_create() - creates the peers list |
| * |
| * @max_peers: maximum number of peers in new list |
| * @peers_list: [out] newly created peers list |
| * |
| * Returns: 0 in case of SUCCESS, negative otherwise |
| */ |
| int ipa_rm_peers_list_create(int max_peers, |
| struct ipa_rm_peers_list **peers_list) |
| { |
| int result; |
| |
| *peers_list = kzalloc(sizeof(**peers_list), GFP_ATOMIC); |
| if (!*peers_list) { |
| IPA_RM_ERR("no mem\n"); |
| result = -ENOMEM; |
| goto bail; |
| } |
| |
| (*peers_list)->max_peers = max_peers; |
| (*peers_list)->peers = kzalloc((*peers_list)->max_peers * |
| sizeof(*((*peers_list)->peers)), GFP_ATOMIC); |
| if (!((*peers_list)->peers)) { |
| IPA_RM_ERR("no mem\n"); |
| result = -ENOMEM; |
| goto list_alloc_fail; |
| } |
| |
| return 0; |
| |
| list_alloc_fail: |
| kfree(*peers_list); |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_peers_list_delete() - deletes the peers list |
| * |
| * @peers_list: peers list |
| * |
| */ |
| void ipa_rm_peers_list_delete(struct ipa_rm_peers_list *peers_list) |
| { |
| if (peers_list) { |
| kfree(peers_list->peers); |
| kfree(peers_list); |
| } |
| } |
| |
| /** |
| * ipa_rm_peers_list_remove_peer() - removes peer from the list |
| * |
| * @peers_list: peers list |
| * @resource_name: name of the resource to remove |
| * |
| */ |
| void ipa_rm_peers_list_remove_peer( |
| struct ipa_rm_peers_list *peers_list, |
| enum ipa_rm_resource_name resource_name) |
| { |
| if (!peers_list) |
| return; |
| |
| peers_list->peers[ipa_rm_peers_list_get_resource_index( |
| resource_name)].resource = NULL; |
| peers_list->peers[ipa_rm_peers_list_get_resource_index( |
| resource_name)].userspace_dep = false; |
| peers_list->peers_count--; |
| } |
| |
| /** |
| * ipa_rm_peers_list_add_peer() - adds peer to the list |
| * |
| * @peers_list: peers list |
| * @resource: resource to add |
| * |
| */ |
| void ipa_rm_peers_list_add_peer( |
| struct ipa_rm_peers_list *peers_list, |
| struct ipa_rm_resource *resource, |
| bool userspace_dep) |
| { |
| if (!peers_list || !resource) |
| return; |
| |
| peers_list->peers[ipa_rm_peers_list_get_resource_index( |
| resource->name)].resource = resource; |
| peers_list->peers[ipa_rm_peers_list_get_resource_index( |
| resource->name)].userspace_dep = userspace_dep; |
| peers_list->peers_count++; |
| } |
| |
| /** |
| * ipa_rm_peers_list_is_empty() - checks |
| * if resource peers list is empty |
| * |
| * @peers_list: peers list |
| * |
| * Returns: true if the list is empty, false otherwise |
| */ |
| bool ipa_rm_peers_list_is_empty(struct ipa_rm_peers_list *peers_list) |
| { |
| bool result = true; |
| |
| if (!peers_list) |
| goto bail; |
| |
| if (peers_list->peers_count > 0) |
| result = false; |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_peers_list_has_last_peer() - checks |
| * if resource peers list has exactly one peer |
| * |
| * @peers_list: peers list |
| * |
| * Returns: true if the list has exactly one peer, false otherwise |
| */ |
| bool ipa_rm_peers_list_has_last_peer( |
| struct ipa_rm_peers_list *peers_list) |
| { |
| bool result = false; |
| |
| if (!peers_list) |
| goto bail; |
| |
| if (peers_list->peers_count == 1) |
| result = true; |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_peers_list_check_dependency() - check dependency |
| * between 2 peer lists |
| * @resource_peers: first peers list |
| * @resource_name: first peers list resource name |
| * @depends_on_peers: second peers list |
| * @depends_on_name: second peers list resource name |
| * @userspace_dep: [out] dependency was created by userspace |
| * |
| * Returns: true if there is dependency, false otherwise |
| * |
| */ |
| bool ipa_rm_peers_list_check_dependency( |
| struct ipa_rm_peers_list *resource_peers, |
| enum ipa_rm_resource_name resource_name, |
| struct ipa_rm_peers_list *depends_on_peers, |
| enum ipa_rm_resource_name depends_on_name, |
| bool *userspace_dep) |
| { |
| bool result = false; |
| int resource_index; |
| |
| if (!resource_peers || !depends_on_peers || !userspace_dep) |
| return result; |
| |
| resource_index = ipa_rm_peers_list_get_resource_index(depends_on_name); |
| if (resource_peers->peers[resource_index].resource != NULL) { |
| result = true; |
| *userspace_dep = resource_peers->peers[resource_index]. |
| userspace_dep; |
| } |
| |
| resource_index = ipa_rm_peers_list_get_resource_index(resource_name); |
| if (depends_on_peers->peers[resource_index].resource != NULL) { |
| result = true; |
| *userspace_dep = depends_on_peers->peers[resource_index]. |
| userspace_dep; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * ipa_rm_peers_list_get_resource() - get resource by |
| * resource index |
| * @resource_index: resource index |
| * @resource_peers: peers list |
| * |
| * Returns: the resource if found, NULL otherwise |
| */ |
| struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index, |
| struct ipa_rm_peers_list *resource_peers) |
| { |
| struct ipa_rm_resource *result = NULL; |
| |
| if (!ipa_rm_peers_list_check_index(resource_index, resource_peers)) |
| goto bail; |
| |
| result = resource_peers->peers[resource_index].resource; |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_peers_list_get_userspace_dep() - returns whether resource dependency |
| * was added by userspace |
| * @resource_index: resource index |
| * @resource_peers: peers list |
| * |
| * Returns: true if dependency was added by userspace, false by kernel |
| */ |
| bool ipa_rm_peers_list_get_userspace_dep(int resource_index, |
| struct ipa_rm_peers_list *resource_peers) |
| { |
| bool result = false; |
| |
| if (!ipa_rm_peers_list_check_index(resource_index, resource_peers)) |
| goto bail; |
| |
| result = resource_peers->peers[resource_index].userspace_dep; |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_peers_list_get_size() - get peers list sise |
| * |
| * @peers_list: peers list |
| * |
| * Returns: the size of the peers list |
| */ |
| int ipa_rm_peers_list_get_size(struct ipa_rm_peers_list *peers_list) |
| { |
| return peers_list->max_peers; |
| } |