| /* Copyright (c) 2013-2016, 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_dependency_graph.h" |
| #include "ipa_rm_i.h" |
| |
| static int ipa_rm_dep_get_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; |
| } |
| |
| /** |
| * ipa_rm_dep_graph_create() - creates graph |
| * @dep_graph: [out] created dependency graph |
| * |
| * Returns: dependency graph on success, NULL on failure |
| */ |
| int ipa_rm_dep_graph_create(struct ipa_rm_dep_graph **dep_graph) |
| { |
| int result = 0; |
| |
| *dep_graph = kzalloc(sizeof(**dep_graph), GFP_KERNEL); |
| if (!*dep_graph) { |
| IPA_RM_ERR("no mem\n"); |
| result = -ENOMEM; |
| goto bail; |
| } |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_dep_graph_delete() - destroyes the graph |
| * @graph: [in] dependency graph |
| * |
| * Frees all resources. |
| */ |
| void ipa_rm_dep_graph_delete(struct ipa_rm_dep_graph *graph) |
| { |
| int resource_index; |
| |
| if (!graph) { |
| IPA_RM_ERR("invalid params\n"); |
| return; |
| } |
| for (resource_index = 0; |
| resource_index < IPA_RM_RESOURCE_MAX; |
| resource_index++) |
| kfree(graph->resource_table[resource_index]); |
| memset(graph->resource_table, 0, sizeof(graph->resource_table)); |
| } |
| |
| /** |
| * ipa_rm_dep_graph_get_resource() - provides a resource by name |
| * @graph: [in] dependency graph |
| * @name: [in] name of the resource |
| * @resource: [out] resource in case of success |
| * |
| * Returns: 0 on success, negative on failure |
| */ |
| int ipa_rm_dep_graph_get_resource( |
| struct ipa_rm_dep_graph *graph, |
| enum ipa_rm_resource_name resource_name, |
| struct ipa_rm_resource **resource) |
| { |
| int result; |
| int resource_index; |
| |
| if (!graph) { |
| result = -EINVAL; |
| goto bail; |
| } |
| resource_index = ipa_rm_dep_get_index(resource_name); |
| if (resource_index == IPA_RM_INDEX_INVALID) { |
| result = -EINVAL; |
| goto bail; |
| } |
| *resource = graph->resource_table[resource_index]; |
| if (!*resource) { |
| result = -EINVAL; |
| goto bail; |
| } |
| result = 0; |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_dep_graph_add() - adds resource to graph |
| * @graph: [in] dependency graph |
| * @resource: [in] resource to add |
| * |
| * Returns: 0 on success, negative on failure |
| */ |
| int ipa_rm_dep_graph_add(struct ipa_rm_dep_graph *graph, |
| struct ipa_rm_resource *resource) |
| { |
| int result = 0; |
| int resource_index; |
| |
| if (!graph || !resource) { |
| result = -EINVAL; |
| goto bail; |
| } |
| resource_index = ipa_rm_dep_get_index(resource->name); |
| if (resource_index == IPA_RM_INDEX_INVALID) { |
| result = -EINVAL; |
| goto bail; |
| } |
| graph->resource_table[resource_index] = resource; |
| bail: |
| return result; |
| } |
| |
| /** |
| * ipa_rm_dep_graph_remove() - removes resource from graph |
| * @graph: [in] dependency graph |
| * @resource: [in] resource to add |
| * |
| * Returns: 0 on success, negative on failure |
| */ |
| int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph, |
| enum ipa_rm_resource_name resource_name) |
| { |
| if (!graph) |
| return -EINVAL; |
| graph->resource_table[resource_name] = NULL; |
| |
| return 0; |
| } |
| |
| /** |
| * ipa_rm_dep_graph_add_dependency() - adds dependency between |
| * two nodes in graph |
| * @graph: [in] dependency graph |
| * @resource_name: [in] resource to add |
| * @depends_on_name: [in] resource to add |
| * @userspace_dep: [in] operation requested by userspace ? |
| * |
| * Returns: 0 on success, negative on failure |
| */ |
| int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph, |
| enum ipa_rm_resource_name resource_name, |
| enum ipa_rm_resource_name depends_on_name, |
| bool userspace_dep) |
| { |
| struct ipa_rm_resource *dependent = NULL; |
| struct ipa_rm_resource *dependency = NULL; |
| int result; |
| |
| if (!graph || |
| !IPA_RM_RESORCE_IS_PROD(resource_name) || |
| !IPA_RM_RESORCE_IS_CONS(depends_on_name)) { |
| IPA_RM_ERR("invalid params\n"); |
| result = -EINVAL; |
| goto bail; |
| } |
| if (ipa_rm_dep_graph_get_resource(graph, |
| resource_name, |
| &dependent)) { |
| IPA_RM_ERR("%s does not exist\n", |
| ipa_rm_resource_str(resource_name)); |
| result = -EINVAL; |
| goto bail; |
| } |
| if (ipa_rm_dep_graph_get_resource(graph, |
| depends_on_name, |
| &dependency)) { |
| IPA_RM_ERR("%s does not exist\n", |
| ipa_rm_resource_str(depends_on_name)); |
| result = -EINVAL; |
| goto bail; |
| } |
| result = ipa_rm_resource_add_dependency(dependent, dependency, |
| userspace_dep); |
| bail: |
| IPA_RM_DBG("EXIT with %d\n", result); |
| |
| return result; |
| } |
| |
| /** |
| * ipa_rm_dep_graph_delete_dependency() - deleted dependency between |
| * two nodes in graph |
| * @graph: [in] dependency graph |
| * @resource_name: [in] resource to delete |
| * @depends_on_name: [in] resource to delete |
| * @userspace_dep: [in] operation requested by userspace ? |
| * |
| * Returns: 0 on success, negative on failure |
| * |
| */ |
| int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph, |
| enum ipa_rm_resource_name resource_name, |
| enum ipa_rm_resource_name depends_on_name, |
| bool userspace_dep) |
| { |
| struct ipa_rm_resource *dependent = NULL; |
| struct ipa_rm_resource *dependency = NULL; |
| int result; |
| |
| if (!graph || |
| !IPA_RM_RESORCE_IS_PROD(resource_name) || |
| !IPA_RM_RESORCE_IS_CONS(depends_on_name)) { |
| IPA_RM_ERR("invalid params\n"); |
| result = -EINVAL; |
| goto bail; |
| } |
| |
| if (ipa_rm_dep_graph_get_resource(graph, |
| resource_name, |
| &dependent)) { |
| IPA_RM_DBG("%s does not exist\n", |
| ipa_rm_resource_str(resource_name)); |
| result = -EINVAL; |
| goto bail; |
| } |
| |
| if (ipa_rm_dep_graph_get_resource(graph, |
| depends_on_name, |
| &dependency)) { |
| IPA_RM_DBG("%s does not exist\n", |
| ipa_rm_resource_str(depends_on_name)); |
| result = -EINVAL; |
| goto bail; |
| } |
| |
| result = ipa_rm_resource_delete_dependency(dependent, dependency, |
| userspace_dep); |
| bail: |
| IPA_RM_DBG("EXIT with %d\n", result); |
| |
| return result; |
| } |