summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorSkylar Chang <chiaweic@codeaurora.org>2016-06-14 18:49:20 -0700
committerKyle Yan <kyan@codeaurora.org>2016-06-22 14:44:45 -0700
commit15dd3b14deac7ee565e3eb5a3e40d35a790dc92c (patch)
treedead00fc3544452a094459346f33a52f51ad669b /drivers/platform
parentea6de85a0be106308347090b50e9da9363a0e8ca (diff)
msm: ipa: fix delete dependency race condition
IPA RM dependencies are added both by kernel drivers and by userspace application (IPACM), depending on the use case. On rare condition, a race is possible between adding the dependency and deleting it, which results in a bad state of the dependency graph. This change makes sure that dependency is deleted only if it was added by the same entity. CRs-Fixed: 1027773 Change-Id: I9253469887b8913f6f2c513a6c7043ed60400b8a Acked-by Ady Abraham <adya@qti.qualcomm.com> Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/msm/ipa/ipa_rm.c144
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_dependency_graph.c16
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_dependency_graph.h8
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_i.h6
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_peers_list.c58
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_peers_list.h17
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_resource.c57
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_resource.h6
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c8
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c8
10 files changed, 253 insertions, 75 deletions
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index d0bde0e9654b..a9813311f156 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -172,19 +172,9 @@ bail:
}
EXPORT_SYMBOL(ipa_rm_delete_resource);
-/**
- * ipa_rm_add_dependency() - create dependency
- * between 2 resources
- * @resource_name: name of dependent resource
- * @depends_on_name: name of its dependency
- *
- * Returns: 0 on success, negative on failure
- *
- * Side effects: IPA_RM_RESORCE_GRANTED could be generated
- * in case client registered with IPA RM
- */
-int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
- enum ipa_rm_resource_name depends_on_name)
+static int _ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name,
+ bool userspace_dep)
{
unsigned long flags;
int result;
@@ -200,29 +190,53 @@ int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
result = ipa_rm_dep_graph_add_dependency(
ipa_rm_ctx->dep_graph,
resource_name,
- depends_on_name);
+ depends_on_name,
+ userspace_dep);
spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags);
IPA_RM_DBG("EXIT with %d\n", result);
return result;
}
+
+/**
+ * ipa_rm_add_dependency() - create dependency between 2 resources
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
+ */
+int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return _ipa_rm_add_dependency(resource_name, depends_on_name, false);
+}
EXPORT_SYMBOL(ipa_rm_add_dependency);
/**
- * ipa_rm_add_dependency_sync() - Create a dependency between 2 resources
- * in a synchronized fashion. In case a producer resource is in GRANTED state
- * and the newly added consumer resource is in RELEASED state, the consumer
- * entity will be requested and the function will block until the consumer
- * is granted.
+ * ipa_rm_add_dependency_from_ioctl() - create dependency between 2 resources
* @resource_name: name of dependent resource
* @depends_on_name: name of its dependency
*
+ * This function is expected to be called from IOCTL and the dependency will be
+ * marked as is was added by the userspace.
+ *
* Returns: 0 on success, negative on failure
*
- * Side effects: May block. See documentation above.
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
*/
-int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name,
- enum ipa_rm_resource_name depends_on_name)
+int ipa_rm_add_dependency_from_ioctl(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return _ipa_rm_add_dependency(resource_name, depends_on_name, true);
+}
+
+static int _ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name,
+ bool userspsace_dep)
{
int result;
struct ipa_rm_resource *consumer;
@@ -240,7 +254,8 @@ int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name,
result = ipa_rm_dep_graph_add_dependency(
ipa_rm_ctx->dep_graph,
resource_name,
- depends_on_name);
+ depends_on_name,
+ userspsace_dep);
spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags);
if (result == -EINPROGRESS) {
ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph,
@@ -268,21 +283,54 @@ int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name,
return result;
}
+/**
+ * ipa_rm_add_dependency_sync() - Create a dependency between 2 resources
+ * in a synchronized fashion. In case a producer resource is in GRANTED state
+ * and the newly added consumer resource is in RELEASED state, the consumer
+ * entity will be requested and the function will block until the consumer
+ * is granted.
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * This function is expected to be called from IOCTL and the dependency will be
+ * marked as is was added by the userspace.
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: May block. See documentation above.
+ */
+int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return _ipa_rm_add_dependency_sync(resource_name, depends_on_name,
+ false);
+}
EXPORT_SYMBOL(ipa_rm_add_dependency_sync);
/**
- * ipa_rm_delete_dependency() - create dependency
- * between 2 resources
+ * ipa_rm_add_dependency_sync_from_ioctl() - Create a dependency between 2
+ * resources in a synchronized fashion. In case a producer resource is in
+ * GRANTED state and the newly added consumer resource is in RELEASED state,
+ * the consumer entity will be requested and the function will block until
+ * the consumer is granted.
* @resource_name: name of dependent resource
* @depends_on_name: name of its dependency
*
* Returns: 0 on success, negative on failure
*
- * Side effects: IPA_RM_RESORCE_GRANTED could be generated
- * in case client registered with IPA RM
+ * Side effects: May block. See documentation above.
*/
-int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
- enum ipa_rm_resource_name depends_on_name)
+int ipa_rm_add_dependency_sync_from_ioctl(
+ enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return _ipa_rm_add_dependency_sync(resource_name, depends_on_name,
+ true);
+}
+
+static int _ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name,
+ bool userspace_dep)
{
unsigned long flags;
int result;
@@ -298,15 +346,51 @@ int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
result = ipa_rm_dep_graph_delete_dependency(
ipa_rm_ctx->dep_graph,
resource_name,
- depends_on_name);
+ depends_on_name,
+ userspace_dep);
spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags);
IPA_RM_DBG("EXIT with %d\n", result);
return result;
}
+
+/**
+ * ipa_rm_delete_dependency() - delete dependency between 2 resources
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
+ */
+int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return _ipa_rm_delete_dependency(resource_name, depends_on_name, false);
+}
EXPORT_SYMBOL(ipa_rm_delete_dependency);
/**
+ * ipa_rm_delete_dependency_fron_ioctl() - delete dependency between 2 resources
+ * @resource_name: name of dependent resource
+ * @depends_on_name: name of its dependency
+ *
+ * This function is expected to be called from IOCTL and the dependency will be
+ * marked as is was added by the userspace.
+ *
+ * Returns: 0 on success, negative on failure
+ *
+ * Side effects: IPA_RM_RESORCE_GRANTED could be generated
+ * in case client registered with IPA RM
+ */
+int ipa_rm_delete_dependency_from_ioctl(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name)
+{
+ return _ipa_rm_delete_dependency(resource_name, depends_on_name, true);
+}
+
+/**
* ipa_rm_request_resource() - request resource
* @resource_name: [in] name of the requested resource
*
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
index fd437b0c8775..54cad888cb7f 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* 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
@@ -152,12 +152,14 @@ int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *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)
+ enum ipa_rm_resource_name depends_on_name,
+ bool userspace_dep)
{
struct ipa_rm_resource *dependent = NULL;
struct ipa_rm_resource *dependency = NULL;
@@ -186,7 +188,8 @@ int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph,
result = -EINVAL;
goto bail;
}
- result = ipa_rm_resource_add_dependency(dependent, dependency);
+ result = ipa_rm_resource_add_dependency(dependent, dependency,
+ userspace_dep);
bail:
IPA_RM_DBG("EXIT with %d\n", result);
@@ -199,13 +202,15 @@ bail:
* @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)
+ enum ipa_rm_resource_name depends_on_name,
+ bool userspace_dep)
{
struct ipa_rm_resource *dependent = NULL;
struct ipa_rm_resource *dependency = NULL;
@@ -237,7 +242,8 @@ int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph,
goto bail;
}
- result = ipa_rm_resource_delete_dependency(dependent, dependency);
+ result = ipa_rm_resource_delete_dependency(dependent, dependency,
+ userspace_dep);
bail:
IPA_RM_DBG("EXIT with %d\n", result);
diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
index b76c6636f873..e322d813e4ea 100644
--- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
+++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* 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
@@ -38,10 +38,12 @@ int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph,
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);
+ enum ipa_rm_resource_name depends_on_name,
+ bool userspsace_dep);
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);
+ enum ipa_rm_resource_name depends_on_name,
+ bool userspsace_dep);
#endif /* _IPA_RM_DEPENDENCY_GRAPH_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h
index e0c1582e8543..eb86c54d7382 100644
--- a/drivers/platform/msm/ipa/ipa_rm_i.h
+++ b/drivers/platform/msm/ipa/ipa_rm_i.h
@@ -146,6 +146,12 @@ int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name);
void delayed_release_work_func(struct work_struct *work);
+int ipa_rm_add_dependency_from_ioctl(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name);
+
+int ipa_rm_delete_dependency_from_ioctl(enum ipa_rm_resource_name resource_name,
+ enum ipa_rm_resource_name depends_on_name);
+
void ipa_rm_exit(void);
#endif /* _IPA_RM_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
index 51ad9530f6ee..fe8e781c4db0 100644
--- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c
@@ -68,7 +68,7 @@ int ipa_rm_peers_list_create(int max_peers,
(*peers_list)->max_peers = max_peers;
(*peers_list)->peers = kzalloc((*peers_list)->max_peers *
- sizeof(struct ipa_rm_resource *), GFP_ATOMIC);
+ sizeof(*((*peers_list)->peers)), GFP_ATOMIC);
if (!((*peers_list)->peers)) {
IPA_RM_ERR("no mem\n");
result = -ENOMEM;
@@ -112,7 +112,9 @@ void ipa_rm_peers_list_remove_peer(
return;
peers_list->peers[ipa_rm_peers_list_get_resource_index(
- resource_name)] = NULL;
+ resource_name)].resource = NULL;
+ peers_list->peers[ipa_rm_peers_list_get_resource_index(
+ resource_name)].userspace_dep = false;
peers_list->peers_count--;
}
@@ -125,14 +127,16 @@ void ipa_rm_peers_list_remove_peer(
*/
void ipa_rm_peers_list_add_peer(
struct ipa_rm_peers_list *peers_list,
- struct ipa_rm_resource *resource)
+ 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->name)].resource = resource;
+ peers_list->peers[ipa_rm_peers_list_get_resource_index(
+ resource->name)].userspace_dep = userspace_dep;
peers_list->peers_count++;
}
@@ -186,6 +190,7 @@ bail:
* @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
*
@@ -194,20 +199,28 @@ 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)
+ enum ipa_rm_resource_name depends_on_name,
+ bool *userspace_dep)
{
bool result = false;
+ int resource_index;
- if (!resource_peers || !depends_on_peers)
+ if (!resource_peers || !depends_on_peers || !userspace_dep)
return result;
- if (resource_peers->peers[ipa_rm_peers_list_get_resource_index(
- depends_on_name)] != NULL)
+ 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;
+ }
- if (depends_on_peers->peers[ipa_rm_peers_list_get_resource_index(
- resource_name)] != NULL)
+ 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;
}
@@ -228,7 +241,28 @@ struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index,
if (!ipa_rm_peers_list_check_index(resource_index, resource_peers))
goto bail;
- result = resource_peers->peers[resource_index];
+ 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;
}
diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.h b/drivers/platform/msm/ipa/ipa_rm_peers_list.h
index b41de0aa3167..cf1c157174dc 100644
--- a/drivers/platform/msm/ipa/ipa_rm_peers_list.h
+++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* 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
@@ -15,6 +15,11 @@
#include "ipa_rm_resource.h"
+struct ipa_rm_resource_peer {
+ struct ipa_rm_resource *resource;
+ bool userspace_dep;
+};
+
/**
* struct ipa_rm_peers_list - IPA RM resource peers list
* @peers: the list of references to resources dependent on this resource
@@ -23,7 +28,7 @@
* @peers_count: actual number of peers for this resource
*/
struct ipa_rm_peers_list {
- struct ipa_rm_resource **peers;
+ struct ipa_rm_resource_peer *peers;
int max_peers;
int peers_count;
};
@@ -36,14 +41,18 @@ void ipa_rm_peers_list_remove_peer(
enum ipa_rm_resource_name resource_name);
void ipa_rm_peers_list_add_peer(
struct ipa_rm_peers_list *peers_list,
- struct ipa_rm_resource *resource);
+ struct ipa_rm_resource *resource,
+ bool userspace_dep);
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);
+ enum ipa_rm_resource_name depends_on_name,
+ bool *userspace_dep);
struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index,
struct ipa_rm_peers_list *peers_list);
+bool ipa_rm_peers_list_get_userspace_dep(int resource_index,
+ struct ipa_rm_peers_list *resource_peers);
int ipa_rm_peers_list_get_size(struct ipa_rm_peers_list *peers_list);
bool ipa_rm_peers_list_is_empty(struct ipa_rm_peers_list *peers_list);
bool ipa_rm_peers_list_has_last_peer(
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index 597598df6997..cc00f8cf7fb6 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -446,6 +446,7 @@ int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
int peers_index;
int result = 0;
int list_size;
+ bool userspace_dep;
if (!resource) {
IPA_RM_ERR("invalid params\n");
@@ -464,10 +465,16 @@ int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
consumer = ipa_rm_peers_list_get_resource(
peers_index,
resource->peers_list);
- if (consumer)
+ if (consumer) {
+ userspace_dep =
+ ipa_rm_peers_list_get_userspace_dep(
+ peers_index,
+ resource->peers_list);
ipa_rm_resource_delete_dependency(
resource,
- consumer);
+ consumer,
+ userspace_dep);
+ }
}
}
@@ -483,10 +490,16 @@ int ipa_rm_resource_delete(struct ipa_rm_resource *resource)
producer = ipa_rm_peers_list_get_resource(
peers_index,
resource->peers_list);
- if (producer)
+ if (producer) {
+ userspace_dep =
+ ipa_rm_peers_list_get_userspace_dep(
+ peers_index,
+ resource->peers_list);
ipa_rm_resource_delete_dependency(
producer,
- resource);
+ resource,
+ userspace_dep);
+ }
}
}
}
@@ -598,10 +611,12 @@ bail:
* Returns: 0 on success, negative on failure
*/
int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
- struct ipa_rm_resource *depends_on)
+ struct ipa_rm_resource *depends_on,
+ bool userspace_dep)
{
int result = 0;
int consumer_result;
+ bool add_dep_by_userspace;
if (!resource || !depends_on) {
IPA_RM_ERR("invalid params\n");
@@ -611,13 +626,17 @@ int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
if (ipa_rm_peers_list_check_dependency(resource->peers_list,
resource->name,
depends_on->peers_list,
- depends_on->name)) {
- IPA_RM_ERR("dependency already exists\n");
+ depends_on->name,
+ &add_dep_by_userspace)) {
+ IPA_RM_ERR("dependency already exists, added by %s\n",
+ add_dep_by_userspace ? "userspace" : "kernel");
return -EEXIST;
}
- ipa_rm_peers_list_add_peer(resource->peers_list, depends_on);
- ipa_rm_peers_list_add_peer(depends_on->peers_list, resource);
+ ipa_rm_peers_list_add_peer(resource->peers_list, depends_on,
+ userspace_dep);
+ ipa_rm_peers_list_add_peer(depends_on->peers_list, resource,
+ userspace_dep);
IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name),
resource->state);
@@ -671,12 +690,14 @@ bail:
* will be sent to the RM client
*/
int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
- struct ipa_rm_resource *depends_on)
+ struct ipa_rm_resource *depends_on,
+ bool userspace_dep)
{
int result = 0;
bool state_changed = false;
bool release_consumer = false;
enum ipa_rm_event evt;
+ bool add_dep_by_userspace;
if (!resource || !depends_on) {
IPA_RM_ERR("invalid params\n");
@@ -686,10 +707,24 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
if (!ipa_rm_peers_list_check_dependency(resource->peers_list,
resource->name,
depends_on->peers_list,
- depends_on->name)) {
+ depends_on->name,
+ &add_dep_by_userspace)) {
IPA_RM_ERR("dependency does not exist\n");
return -EINVAL;
}
+
+ /*
+ * to avoid race conditions between kernel and userspace
+ * need to check that the dependency was added by same entity
+ */
+ if (add_dep_by_userspace != userspace_dep) {
+ IPA_RM_DBG("dependency was added by %s\n",
+ add_dep_by_userspace ? "userspace" : "kernel");
+ IPA_RM_DBG("ignore request to delete dependency by %s\n",
+ userspace_dep ? "userspace" : "kernel");
+ return 0;
+ }
+
IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name),
resource->state);
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h
index 26573e243b4e..5c3a0190753f 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.h
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.h
@@ -116,10 +116,12 @@ int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer,
struct ipa_rm_register_params *reg_params);
int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource,
- struct ipa_rm_resource *depends_on);
+ struct ipa_rm_resource *depends_on,
+ bool userspace_dep);
int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource,
- struct ipa_rm_resource *depends_on);
+ struct ipa_rm_resource *depends_on,
+ bool userspace_dep);
int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index ae9e2b5a109d..1f9fd7a38a37 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1116,8 +1116,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- retval = ipa_rm_add_dependency(rm_depend.resource_name,
- rm_depend.depends_on_name);
+ retval = ipa_rm_add_dependency_from_ioctl(
+ rm_depend.resource_name, rm_depend.depends_on_name);
break;
case IPA_IOC_RM_DEL_DEPENDENCY:
if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
@@ -1125,8 +1125,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- retval = ipa_rm_delete_dependency(rm_depend.resource_name,
- rm_depend.depends_on_name);
+ retval = ipa_rm_delete_dependency_from_ioctl(
+ rm_depend.resource_name, rm_depend.depends_on_name);
break;
case IPA_IOC_GENERATE_FLT_EQ:
{
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 7acf07acb8c1..747ae3d82b68 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -1196,8 +1196,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- retval = ipa_rm_add_dependency(rm_depend.resource_name,
- rm_depend.depends_on_name);
+ retval = ipa_rm_add_dependency_from_ioctl(
+ rm_depend.resource_name, rm_depend.depends_on_name);
break;
case IPA_IOC_RM_DEL_DEPENDENCY:
if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
@@ -1205,8 +1205,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
}
- retval = ipa_rm_delete_dependency(rm_depend.resource_name,
- rm_depend.depends_on_name);
+ retval = ipa_rm_delete_dependency_from_ioctl(
+ rm_depend.resource_name, rm_depend.depends_on_name);
break;
case IPA_IOC_GENERATE_FLT_EQ:
{