drm/msm: move msm property dirty list to atomic state
Move the tracking for DRM property dirty into the atomic
state rather than keeping it with the DRM objects themselves.
This avoids a race condition between asynchronous worker
threads and property sets from future commits.
CRs-Fixed: 2062084
Change-Id: Ie33de972ad81a44e323975548d88a9d9c2a8d850
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index f2996dd..d1991a4 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -21,8 +21,6 @@
uint32_t blob_count,
uint32_t state_size)
{
- int i;
-
/* prevent access if any of these are NULL */
if (!base || !dev || !property_array || !property_data) {
property_count = 0;
@@ -60,10 +58,6 @@
0,
sizeof(struct msm_property_data) *
property_count);
- INIT_LIST_HEAD(&info->dirty_list);
-
- for (i = 0; i < property_count; ++i)
- INIT_LIST_HEAD(&property_data[i].dirty_node);
}
}
@@ -72,9 +66,6 @@
if (!info)
return;
- /* reset dirty list */
- INIT_LIST_HEAD(&info->dirty_list);
-
/* free state cache */
while (info->state_cache_size > 0)
kfree(info->state_cache[--(info->state_cache_size)]);
@@ -82,24 +73,25 @@
mutex_destroy(&info->property_lock);
}
-int msm_property_pop_dirty(struct msm_property_info *info)
+int msm_property_pop_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state)
{
struct list_head *item;
int rc = 0;
- if (!info) {
- DRM_ERROR("invalid info\n");
+ if (!info || !property_state || !property_state->values) {
+ DRM_ERROR("invalid argument(s)\n");
return -EINVAL;
}
mutex_lock(&info->property_lock);
- if (list_empty(&info->dirty_list)) {
+ if (list_empty(&property_state->dirty_list)) {
rc = -EAGAIN;
} else {
- item = info->dirty_list.next;
+ item = property_state->dirty_list.next;
list_del_init(item);
- rc = container_of(item, struct msm_property_data, dirty_node)
- - info->property_data;
+ rc = container_of(item, struct msm_property_value, dirty_node)
+ - property_state->values;
DRM_DEBUG_KMS("property %d dirty\n", rc);
}
mutex_unlock(&info->property_lock);
@@ -112,26 +104,28 @@
* This function doesn't mutex protect the
* dirty linked list.
* @info: Pointer to property info container struct
+ * @property_state: Pointer to property state container struct
* @property_idx: Property index
*/
static void _msm_property_set_dirty_no_lock(
struct msm_property_info *info,
+ struct msm_property_state *property_state,
uint32_t property_idx)
{
- if (!info || property_idx >= info->property_count) {
- DRM_ERROR("invalid argument(s), info %pK, idx %u\n",
- info, property_idx);
+ if (!info || !property_state || !property_state->values ||
+ property_idx >= info->property_count) {
+ DRM_ERROR("invalid argument(s), idx %u\n", property_idx);
return;
}
/* avoid re-inserting if already dirty */
- if (!list_empty(&info->property_data[property_idx].dirty_node)) {
+ if (!list_empty(&property_state->values[property_idx].dirty_node)) {
DRM_DEBUG_KMS("property %u already dirty\n", property_idx);
return;
}
- list_add_tail(&info->property_data[property_idx].dirty_node,
- &info->dirty_list);
+ list_add_tail(&property_state->values[property_idx].dirty_node,
+ &property_state->dirty_list);
}
/**
@@ -371,35 +365,36 @@
return rc;
}
-int msm_property_set_dirty(struct msm_property_info *info, int property_idx)
+int msm_property_set_dirty(struct msm_property_info *info,
+ struct msm_property_state *property_state,
+ int property_idx)
{
- if (!info) {
- DRM_ERROR("invalid property info\n");
+ if (!info || !property_state || !property_state->values) {
+ DRM_ERROR("invalid argument(s)\n");
return -EINVAL;
}
mutex_lock(&info->property_lock);
- _msm_property_set_dirty_no_lock(info, property_idx);
+ _msm_property_set_dirty_no_lock(info, property_state, property_idx);
mutex_unlock(&info->property_lock);
return 0;
}
int msm_property_atomic_set(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property, uint64_t val)
{
struct drm_property_blob *blob;
int property_idx, rc = -EINVAL;
property_idx = msm_property_index(info, property);
- if (!info || (property_idx == -EINVAL) || !property_values) {
- DRM_DEBUG("Invalid argument(s)\n");
+ if (!info || !property_state ||
+ (property_idx == -EINVAL) || !property_state->values) {
+ DRM_DEBUG("invalid argument(s)\n");
} else {
/* extra handling for incoming properties */
mutex_lock(&info->property_lock);
if ((property->flags & DRM_MODE_PROP_BLOB) &&
- (property_idx < info->blob_count) &&
- property_blobs) {
+ (property_idx < info->blob_count)) {
/* DRM lookup also takes a reference */
blob = drm_property_lookup_blob(info->dev,
(uint32_t)val);
@@ -411,18 +406,21 @@
val = blob->base.id;
/* save blob - need to clear previous ref */
- if (property_blobs[property_idx])
+ if (property_state->values[property_idx].blob)
drm_property_unreference_blob(
- property_blobs[property_idx]);
- property_blobs[property_idx] = blob;
+ property_state->values[
+ property_idx].blob);
+ property_state->values[property_idx].blob =
+ blob;
}
}
/* update value and flag as dirty */
- if (property_values[property_idx] != val ||
+ if (property_state->values[property_idx].value != val ||
info->property_data[property_idx].force_dirty) {
- property_values[property_idx] = val;
- _msm_property_set_dirty_no_lock(info, property_idx);
+ property_state->values[property_idx].value = val;
+ _msm_property_set_dirty_no_lock(info, property_state,
+ property_idx);
DBG("%s - %lld", property->name, val);
}
@@ -434,18 +432,18 @@
}
int msm_property_atomic_get(struct msm_property_info *info,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
struct drm_property *property, uint64_t *val)
{
int property_idx, rc = -EINVAL;
property_idx = msm_property_index(info, property);
- if (!info || (property_idx == -EINVAL) || !property_values || !val) {
+ if (!info || (property_idx == -EINVAL) ||
+ !property_state->values || !val) {
DRM_DEBUG("Invalid argument(s)\n");
} else {
mutex_lock(&info->property_lock);
- *val = property_values[property_idx];
+ *val = property_state->values[property_idx].value;
mutex_unlock(&info->property_lock);
rc = 0;
}
@@ -495,8 +493,8 @@
}
void msm_property_reset_state(struct msm_property_info *info, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values)
{
uint32_t i;
@@ -508,24 +506,29 @@
if (state)
memset(state, 0, info->state_size);
+ if (property_state) {
+ property_state->property_count = info->property_count;
+ property_state->values = property_values;
+ INIT_LIST_HEAD(&property_state->dirty_list);
+ }
+
/*
* Assign default property values. This helper is mostly used
* to initialize newly created state objects.
*/
if (property_values)
- for (i = 0; i < info->property_count; ++i)
- property_values[i] =
+ for (i = 0; i < info->property_count; ++i) {
+ property_values[i].value =
info->property_data[i].default_value;
-
- if (property_blobs)
- for (i = 0; i < info->blob_count; ++i)
- property_blobs[i] = 0;
+ property_values[i].blob = NULL;
+ INIT_LIST_HEAD(&property_values[i].dirty_node);
+ }
}
void msm_property_duplicate_state(struct msm_property_info *info,
void *old_state, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state,
+ struct msm_property_value *property_values)
{
uint32_t i;
@@ -536,17 +539,24 @@
memcpy(state, old_state, info->state_size);
- if (property_blobs) {
- /* add ref count for blobs */
- for (i = 0; i < info->blob_count; ++i)
- if (property_blobs[i])
- drm_property_reference_blob(property_blobs[i]);
- }
+ if (!property_state)
+ return;
+
+ INIT_LIST_HEAD(&property_state->dirty_list);
+ property_state->values = property_values;
+
+ if (property_state->values)
+ /* add ref count for blobs and initialize dirty nodes */
+ for (i = 0; i < info->property_count; ++i) {
+ if (property_state->values[i].blob)
+ drm_property_reference_blob(
+ property_state->values[i].blob);
+ INIT_LIST_HEAD(&property_state->values[i].dirty_node);
+ }
}
void msm_property_destroy_state(struct msm_property_info *info, void *state,
- uint64_t *property_values,
- struct drm_property_blob **property_blobs)
+ struct msm_property_state *property_state)
{
uint32_t i;
@@ -554,19 +564,21 @@
DRM_ERROR("invalid argument(s)\n");
return;
}
- if (property_blobs) {
+ if (property_state && property_state->values) {
/* remove ref count for blobs */
- for (i = 0; i < info->blob_count; ++i)
- if (property_blobs[i])
+ for (i = 0; i < info->property_count; ++i)
+ if (property_state->values[i].blob) {
drm_property_unreference_blob(
- property_blobs[i]);
+ property_state->values[i].blob);
+ property_state->values[i].blob = NULL;
+ }
}
_msm_property_free_state(info, state);
}
void *msm_property_get_blob(struct msm_property_info *info,
- struct drm_property_blob **property_blobs,
+ struct msm_property_state *property_state,
size_t *byte_len,
uint32_t property_idx)
{
@@ -574,10 +586,11 @@
size_t len = 0;
void *rc = 0;
- if (!info || !property_blobs || (property_idx >= info->blob_count)) {
+ if (!info || !property_state || !property_state->values ||
+ (property_idx >= info->blob_count)) {
DRM_ERROR("invalid argument(s)\n");
} else {
- blob = property_blobs[property_idx];
+ blob = property_state->values[property_idx].blob;
if (blob) {
len = blob->length;
rc = &blob->data;
@@ -636,14 +649,15 @@
}
int msm_property_set_property(struct msm_property_info *info,
- uint64_t *property_values,
+ struct msm_property_state *property_state,
uint32_t property_idx,
uint64_t val)
{
int rc = -EINVAL;
if (!info || (property_idx >= info->property_count) ||
- property_idx < info->blob_count || !property_values) {
+ property_idx < info->blob_count ||
+ !property_state || !property_state->values) {
DRM_ERROR("invalid argument(s)\n");
} else {
struct drm_property *drm_prop;
@@ -651,8 +665,7 @@
mutex_lock(&info->property_lock);
/* update cached value */
- if (property_values)
- property_values[property_idx] = val;
+ property_state->values[property_idx].value = val;
/* update the new default value for immutables */
drm_prop = info->property_array[property_idx];