drm/msm/sde: add cache for released plane states
Reduce kmalloc/kfree activity as states are duplicated/destroyed.
Change-Id: I7be4039dadf23578d440e5c35b789cc9ba6f0a14
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index be0181a..07d4492 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -28,11 +28,15 @@
#define SDE_NAME_SIZE 12
+#define SDE_STATE_CACHE_SIZE 2
+
struct sde_plane {
struct drm_plane base;
int mmu_id;
+ struct mutex lock;
+
enum sde_sspp pipe;
uint32_t features; /* capabilities from catalog */
uint32_t nformats;
@@ -54,6 +58,10 @@
/* cache property default values (for reset) */
uint64_t property_defaults[PLANE_PROP_COUNT];
+ /* cache for unused plane state structures */
+ struct sde_plane_state *state_cache[SDE_STATE_CACHE_SIZE];
+ int state_cache_size;
+
/* debugfs related stuff */
struct dentry *debugfs_root;
struct sde_debugfs_regset32 debugfs_src;
@@ -1022,19 +1030,22 @@
struct drm_plane_state *state, struct drm_property *property,
uint64_t val)
{
+ struct sde_plane *psde;
struct sde_plane_state *pstate;
struct drm_property_blob *blob, **pr_blob;
int idx, ret = -EINVAL;
- DBG("");
-
idx = _sde_plane_get_property_index(plane, property);
if (!state) {
DRM_ERROR("Invalid state\n");
- } else if (idx < PLANE_PROP_COUNT) {
- DBG("Set property %d <= %d", idx, (int)val);
+ } else if (idx >= PLANE_PROP_COUNT) {
+ DRM_ERROR("Invalid property\n");
+ } else {
+ psde = to_sde_plane(plane);
pstate = to_sde_plane_state(state);
+ DBG("%s: %d <= %d", psde->pipe_name, idx, (int)val);
+
/* extra handling for incoming properties */
if ((property->flags & DRM_MODE_PROP_BLOB) &&
(idx < PLANE_PROP_BLOBCOUNT)) {
@@ -1100,6 +1111,48 @@
return ret;
}
+static struct sde_plane_state *sde_plane_alloc_state(struct drm_plane *plane)
+{
+ struct sde_plane *psde;
+ struct sde_plane_state *pstate;
+
+ if (!plane)
+ return NULL;
+
+ psde = to_sde_plane(plane);
+ pstate = NULL;
+
+ mutex_lock(&psde->lock);
+ if (psde->state_cache_size)
+ pstate = psde->state_cache[--(psde->state_cache_size)];
+ mutex_unlock(&psde->lock);
+
+ if (!pstate)
+ pstate = kmalloc(sizeof(struct sde_plane_state), GFP_KERNEL);
+
+ return pstate;
+}
+
+static void sde_plane_free_state(struct drm_plane *plane,
+ struct sde_plane_state *pstate)
+{
+ struct sde_plane *psde;
+
+ if (!plane || !pstate)
+ return;
+
+ psde = to_sde_plane(plane);
+
+ mutex_lock(&psde->lock);
+ if (psde->state_cache_size < SDE_STATE_CACHE_SIZE) {
+ psde->state_cache[(psde->state_cache_size)++] = pstate;
+ mutex_unlock(&psde->lock);
+ } else {
+ mutex_unlock(&psde->lock);
+ kfree(pstate);
+ }
+}
+
static void sde_plane_destroy(struct drm_plane *plane)
{
struct sde_plane *psde;
@@ -1111,6 +1164,8 @@
debugfs_remove_recursive(psde->debugfs_root);
+ mutex_destroy(&psde->lock);
+
drm_plane_helper_disable(plane);
/* this will destroy the states as well */
@@ -1119,6 +1174,10 @@
if (psde->pipe_hw)
sde_hw_sspp_destroy(psde->pipe_hw);
+ /* free state cache */
+ while (psde->state_cache_size > 0)
+ kfree(psde->state_cache[--(psde->state_cache_size)]);
+
kfree(psde);
}
}
@@ -1129,19 +1188,19 @@
struct sde_plane_state *pstate;
int i;
- DBG("");
-
if (!plane || !state) {
DRM_ERROR("Invalid plane/state\n");
return;
}
+ pstate = to_sde_plane_state(state);
+
+ DBG("");
+
/* remove ref count for frame buffers */
if (state->fb)
drm_framebuffer_unreference(state->fb);
- pstate = to_sde_plane_state(state);
-
/* remove ref count for fence */
if (pstate->sync_fence)
sde_sync_put(pstate->sync_fence);
@@ -1151,46 +1210,50 @@
if (pstate->property_blobs[i])
drm_property_unreference_blob(
pstate->property_blobs[i]);
- kfree(pstate);
+ sde_plane_free_state(plane, pstate);
}
static struct drm_plane_state *
sde_plane_duplicate_state(struct drm_plane *plane)
{
struct sde_plane_state *pstate;
+ struct sde_plane_state *old_state;
int i;
- if (WARN_ON(!plane->state))
+ if (!plane || !plane->state)
return NULL;
- pstate = kmemdup(to_sde_plane_state(plane->state),
- sizeof(*pstate), GFP_KERNEL);
+ old_state = to_sde_plane_state(plane->state);
+ pstate = sde_plane_alloc_state(plane);
DBG("");
- if (pstate) {
- /* add ref count for frame buffer */
- if (pstate->base.fb)
- drm_framebuffer_reference(pstate->base.fb);
+ if (!pstate)
+ return NULL;
- /* add ref count for fence */
- if (pstate->sync_fence) {
- pstate->sync_fence = 0;
- _sde_plane_update_sync_fence(plane, pstate, pstate->
- property_values[PLANE_PROP_SYNC_FENCE]);
- }
+ memcpy(pstate, old_state, sizeof(*pstate));
- /* add ref count for blobs */
- for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
- if (pstate->property_blobs[i])
- drm_property_reference_blob(
- pstate->property_blobs[i]);
+ /* add ref count for frame buffer */
+ if (pstate->base.fb)
+ drm_framebuffer_reference(pstate->base.fb);
- pstate->mode_changed = false;
- pstate->pending = false;
+ /* add ref count for fence */
+ if (pstate->sync_fence) {
+ pstate->sync_fence = 0;
+ _sde_plane_update_sync_fence(plane, pstate, pstate->
+ property_values[PLANE_PROP_SYNC_FENCE]);
}
- return pstate ? &pstate->base : NULL;
+ /* add ref count for blobs */
+ for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
+ if (pstate->property_blobs[i])
+ drm_property_reference_blob(
+ pstate->property_blobs[i]);
+
+ pstate->mode_changed = false;
+ pstate->pending = false;
+
+ return &pstate->base;
}
static void sde_plane_reset(struct drm_plane *plane)
@@ -1199,26 +1262,28 @@
struct sde_plane_state *pstate;
int i;
- DBG("");
-
if (!plane) {
DRM_ERROR("Invalid plane\n");
return;
}
+ psde = to_sde_plane(plane);
+ DBG("%s", psde->pipe_name);
+
/* remove previous state, if present */
if (plane->state)
sde_plane_destroy_state(plane, plane->state);
plane->state = 0;
- pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+ pstate = sde_plane_alloc_state(plane);
if (!pstate) {
- DRM_ERROR("Failed to re-allocate plane state\n");
+ DRM_ERROR("Failed to (re)allocate plane state\n");
return;
}
+ memset(pstate, 0, sizeof(*pstate));
+
/* assign default property values */
- psde = to_sde_plane(plane);
for (i = 0; i < PLANE_PROP_COUNT; ++i)
pstate->property_values[i] = psde->property_defaults[i];
@@ -1391,6 +1456,8 @@
/* save user friendly pipe name for later */
snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
+ mutex_init(&psde->lock);
+
_sde_plane_init_debugfs(psde, kms);
DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);