Loading drivers/gpu/drm/msm/sde/sde_crtc.c +390 −3 Original line number Diff line number Diff line Loading @@ -117,6 +117,374 @@ static inline int _sde_crtc_power_enable(struct sde_crtc *sde_crtc, bool enable) enable); } /** * _sde_crtc_rp_to_crtc - get crtc from resource pool object * @rp: Pointer to resource pool * return: Pointer to drm crtc if success; null otherwise */ static struct drm_crtc *_sde_crtc_rp_to_crtc(struct sde_crtc_respool *rp) { if (!rp) return NULL; return container_of(rp, struct sde_crtc_state, rp)->base.crtc; } /** * _sde_crtc_rp_reclaim - reclaim unused, or all if forced, resources in pool * @rp: Pointer to resource pool * @force: True to reclaim all resources; otherwise, reclaim only unused ones * return: None */ static void _sde_crtc_rp_reclaim(struct sde_crtc_respool *rp, bool force) { struct sde_crtc_res *res, *next; struct drm_crtc *crtc; crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } SDE_DEBUG("crtc%d.%u %s\n", crtc->base.id, rp->sequence_id, force ? "destroy" : "free_unused"); list_for_each_entry_safe(res, next, &rp->res_list, list) { if (!force && !(res->flags & SDE_CRTC_RES_FLAG_FREE)) continue; SDE_DEBUG("crtc%d.%u reclaim res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); list_del(&res->list); if (res->ops.put) res->ops.put(res->val); kfree(res); } } /** * _sde_crtc_rp_free_unused - free unused resource in pool * @rp: Pointer to resource pool * return: none */ static void _sde_crtc_rp_free_unused(struct sde_crtc_respool *rp) { _sde_crtc_rp_reclaim(rp, false); } /** * _sde_crtc_rp_destroy - destroy resource pool * @rp: Pointer to resource pool * return: None */ static void _sde_crtc_rp_destroy(struct sde_crtc_respool *rp) { _sde_crtc_rp_reclaim(rp, true); } /** * _sde_crtc_hw_blk_get - get callback for hardware block * @val: Resource handle * @type: Resource type * @tag: Search tag for given resource * return: Resource handle */ static void *_sde_crtc_hw_blk_get(void *val, u32 type, u64 tag) { SDE_DEBUG("res:%d/0x%llx/%pK\n", type, tag, val); return sde_hw_blk_get(val, type, tag); } /** * _sde_crtc_hw_blk_put - put callback for hardware block * @val: Resource handle * return: None */ static void _sde_crtc_hw_blk_put(void *val) { SDE_DEBUG("res://%pK\n", val); sde_hw_blk_put(val); } /** * _sde_crtc_rp_duplicate - duplicate resource pool and reset reference count * @rp: Pointer to original resource pool * @dup_rp: Pointer to duplicated resource pool * return: None */ static void _sde_crtc_rp_duplicate(struct sde_crtc_respool *rp, struct sde_crtc_respool *dup_rp) { struct sde_crtc_res *res, *dup_res; struct drm_crtc *crtc; if (!rp || !dup_rp) { SDE_ERROR("invalid resource pool\n"); return; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } SDE_DEBUG("crtc%d.%u duplicate\n", crtc->base.id, rp->sequence_id); dup_rp->sequence_id = rp->sequence_id + 1; INIT_LIST_HEAD(&dup_rp->res_list); dup_rp->ops = rp->ops; list_for_each_entry(res, &rp->res_list, list) { dup_res = kzalloc(sizeof(struct sde_crtc_res), GFP_KERNEL); if (!dup_res) return; INIT_LIST_HEAD(&dup_res->list); atomic_set(&dup_res->refcount, 0); dup_res->type = res->type; dup_res->tag = res->tag; dup_res->val = res->val; dup_res->ops = res->ops; dup_res->flags = SDE_CRTC_RES_FLAG_FREE; SDE_DEBUG("crtc%d.%u dup res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, dup_rp->sequence_id, dup_res->type, dup_res->tag, dup_res->val, atomic_read(&dup_res->refcount)); list_add_tail(&dup_res->list, &dup_rp->res_list); if (dup_res->ops.get) dup_res->ops.get(dup_res->val, 0, -1); } } /** * _sde_crtc_rp_reset - reset resource pool after allocation * @rp: Pointer to original resource pool * return: None */ static void _sde_crtc_rp_reset(struct sde_crtc_respool *rp) { if (!rp) { SDE_ERROR("invalid resource pool\n"); return; } rp->sequence_id = 0; INIT_LIST_HEAD(&rp->res_list); rp->ops.get = _sde_crtc_hw_blk_get; rp->ops.put = _sde_crtc_hw_blk_put; } /** * _sde_crtc_rp_add - add given resource to resource pool * @rp: Pointer to original resource pool * @type: Resource type * @tag: Search tag for given resource * @val: Resource handle * @ops: Resource callback operations * return: 0 if success; error code otherwise */ static int _sde_crtc_rp_add(struct sde_crtc_respool *rp, u32 type, u64 tag, void *val, struct sde_crtc_res_ops *ops) { struct sde_crtc_res *res; struct drm_crtc *crtc; if (!rp || !ops) { SDE_ERROR("invalid resource pool/ops\n"); return -EINVAL; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return -EINVAL; } list_for_each_entry(res, &rp->res_list, list) { if (res->type != type || res->tag != tag) continue; SDE_ERROR("crtc%d.%u already exist res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); return -EEXIST; } res = kzalloc(sizeof(struct sde_crtc_res), GFP_KERNEL); if (!res) return -ENOMEM; INIT_LIST_HEAD(&res->list); atomic_set(&res->refcount, 1); res->type = type; res->tag = tag; res->val = val; res->ops = *ops; list_add_tail(&res->list, &rp->res_list); SDE_DEBUG("crtc%d.%u added res:0x%x/0x%llx\n", crtc->base.id, rp->sequence_id, type, tag); return 0; } /** * _sde_crtc_rp_get - lookup the resource from given resource pool and obtain * if available; otherwise, obtain resource from global pool * @rp: Pointer to original resource pool * @type: Resource type * @tag: Search tag for given resource * return: Resource handle if success; pointer error or null otherwise */ static void *_sde_crtc_rp_get(struct sde_crtc_respool *rp, u32 type, u64 tag) { struct sde_crtc_res *res; void *val = NULL; int rc; struct drm_crtc *crtc; if (!rp) { SDE_ERROR("invalid resource pool\n"); return NULL; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return NULL; } list_for_each_entry(res, &rp->res_list, list) { if (res->type != type || res->tag != tag) continue; SDE_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); atomic_inc(&res->refcount); res->flags &= ~SDE_CRTC_RES_FLAG_FREE; return res->val; } list_for_each_entry(res, &rp->res_list, list) { if (res->type != type || !(res->flags & SDE_CRTC_RES_FLAG_FREE)) continue; SDE_DEBUG("crtc%d.%u retag res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); atomic_inc(&res->refcount); res->tag = tag; res->flags &= ~SDE_CRTC_RES_FLAG_FREE; return res->val; } if (rp->ops.get) val = rp->ops.get(NULL, type, -1); if (IS_ERR_OR_NULL(val)) { SDE_ERROR("crtc%d.%u failed to get res:0x%x//\n", crtc->base.id, rp->sequence_id, type); return NULL; } rc = _sde_crtc_rp_add(rp, type, tag, val, &rp->ops); if (rc) { SDE_ERROR("crtc%d.%u failed to add res:0x%x/0x%llx\n", crtc->base.id, rp->sequence_id, type, tag); if (rp->ops.put) rp->ops.put(val); val = NULL; } return val; } /** * _sde_crtc_rp_put - return given resource to resource pool * @rp: Pointer to original resource pool * @type: Resource type * @tag: Search tag for given resource * return: None */ static void _sde_crtc_rp_put(struct sde_crtc_respool *rp, u32 type, u64 tag) { struct sde_crtc_res *res, *next; struct drm_crtc *crtc; if (!rp) { SDE_ERROR("invalid resource pool\n"); return; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } list_for_each_entry_safe(res, next, &rp->res_list, list) { if (res->type != type || res->tag != tag) continue; SDE_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); if (res->flags & SDE_CRTC_RES_FLAG_FREE) SDE_ERROR( "crtc%d.%u already free res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); else if (atomic_dec_return(&res->refcount) == 0) res->flags |= SDE_CRTC_RES_FLAG_FREE; return; } SDE_ERROR("crtc%d.%u not found res:0x%x/0x%llx\n", crtc->base.id, rp->sequence_id, type, tag); } int sde_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, void *val, struct sde_crtc_res_ops *ops) { struct sde_crtc_respool *rp; if (!state) { SDE_ERROR("invalid parameters\n"); return -EINVAL; } rp = &to_sde_crtc_state(state)->rp; return _sde_crtc_rp_add(rp, type, tag, val, ops); } void *sde_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag) { struct sde_crtc_respool *rp; void *val; if (!state) { SDE_ERROR("invalid parameters\n"); return NULL; } rp = &to_sde_crtc_state(state)->rp; val = _sde_crtc_rp_get(rp, type, tag); if (IS_ERR(val)) { SDE_ERROR("failed to get res type:0x%x:0x%llx\n", type, tag); return NULL; } return val; } void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag) { struct sde_crtc_respool *rp; if (!state) { SDE_ERROR("invalid parameters\n"); return; } rp = &to_sde_crtc_state(state)->rp; _sde_crtc_rp_put(rp, type, tag); } static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) { if (!sde_crtc) Loading Loading @@ -1071,6 +1439,8 @@ static void sde_crtc_destroy_state(struct drm_crtc *crtc, SDE_DEBUG("crtc%d\n", crtc->base.id); _sde_crtc_rp_destroy(&cstate->rp); __drm_atomic_helper_crtc_destroy_state(state); /* destroy value helper */ Loading Loading @@ -1262,6 +1632,8 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) /* duplicate base helper */ __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); _sde_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp); return &cstate->base; } Loading Loading @@ -1304,6 +1676,8 @@ static void sde_crtc_reset(struct drm_crtc *crtc) _sde_crtc_set_input_fence_timeout(cstate); _sde_crtc_rp_reset(&cstate->rp); cstate->base.crtc = crtc; crtc->state = &cstate->base; } Loading Loading @@ -1487,14 +1861,15 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, return -EINVAL; } sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(state); if (!state->enable || !state->active) { SDE_DEBUG("crtc%d -> enable %d, active %d, skip atomic_check\n", crtc->base.id, state->enable, state->active); return 0; goto end; } sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(state); mode = &state->adjusted_mode; SDE_DEBUG("%s: check", sde_crtc->name); Loading Loading @@ -1702,6 +2077,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, end: _sde_crtc_rp_free_unused(&cstate->rp); return rc; } Loading Loading @@ -1907,6 +2283,9 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, } if (ret) DRM_ERROR("failed to set the property\n"); SDE_DEBUG("crtc%d %s[%d] <= 0x%llx ret=%d\n", crtc->base.id, property->name, property->base.id, val, ret); } return ret; Loading Loading @@ -2209,6 +2588,7 @@ static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v) { struct drm_crtc *crtc = (struct drm_crtc *) s->private; struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state); struct sde_crtc_res *res; seq_printf(s, "num_connectors: %d\n", cstate->num_connectors); seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc)); Loading @@ -2218,6 +2598,13 @@ static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v) seq_printf(s, "max_per_pipe_ib: %llu\n", cstate->cur_perf.max_per_pipe_ib); seq_printf(s, "rp.%d: ", cstate->rp.sequence_id); list_for_each_entry(res, &cstate->rp.res_list, list) seq_printf(s, "0x%x/0x%llx/%pK/%d ", res->type, res->tag, res->val, atomic_read(&res->refcount)); seq_puts(s, "\n"); return 0; } DEFINE_SDE_DEBUGFS_SEQ_FOPS(sde_crtc_debugfs_state); Loading drivers/gpu/drm/msm/sde/sde_crtc.h +83 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "sde_fence.h" #include "sde_kms.h" #include "sde_core_perf.h" #include "sde_hw_blk.h" #define SDE_CRTC_NAME_SIZE 12 Loading Loading @@ -190,6 +191,56 @@ struct sde_crtc { #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) /** * struct sde_crtc_res_ops - common operations for crtc resources * @get: get given resource * @put: put given resource */ struct sde_crtc_res_ops { void *(*get)(void *val, u32 type, u64 tag); void (*put)(void *val); }; /* crtc resource type (0x0-0xffff reserved for hw block type */ #define SDE_CRTC_RES_ROT_OUT_FBO 0x10000 #define SDE_CRTC_RES_ROT_OUT_FB 0x10001 #define SDE_CRTC_RES_ROT_PLANE 0x10002 #define SDE_CRTC_RES_ROT_IN_FB 0x10003 #define SDE_CRTC_RES_FLAG_FREE BIT(0) /** * struct sde_crtc_res - definition of crtc resources * @list: list of crtc resource * @type: crtc resource type * @tag: unique identifier per type * @refcount: reference/usage count * @ops: callback operations * @val: resource handle associated with type/tag * @flags: customization flags */ struct sde_crtc_res { struct list_head list; u32 type; u64 tag; atomic_t refcount; struct sde_crtc_res_ops ops; void *val; u32 flags; }; /** * sde_crtc_respool - crtc resource pool * @sequence_id: sequence identifier, incremented per state duplication * @res_list: list of resource managed by this resource pool * @ops: resource operations for parent resource pool */ struct sde_crtc_respool { u32 sequence_id; struct list_head res_list; struct sde_crtc_res_ops ops; }; /** * struct sde_crtc_state - sde container for atomic crtc state * @base: Base drm crtc state structure Loading Loading @@ -226,6 +277,8 @@ struct sde_crtc_state { struct sde_core_perf_params new_perf; struct sde_ctl_sbuf_cfg sbuf_cfg; u64 sbuf_prefill_line; struct sde_crtc_respool rp; }; #define to_sde_crtc_state(x) \ Loading Loading @@ -370,4 +423,34 @@ static inline bool sde_crtc_is_enabled(struct drm_crtc *crtc) int sde_crtc_event_queue(struct drm_crtc *crtc, void (*func)(struct drm_crtc *crtc, void *usr), void *usr); /** * sde_crtc_res_add - add given resource to resource pool in crtc state * @state: Pointer to drm crtc state * @type: Resource type * @tag: Search tag for given resource * @val: Resource handle * @ops: Resource callback operations * return: 0 if success; error code otherwise */ int sde_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, void *val, struct sde_crtc_res_ops *ops); /** * sde_crtc_res_get - get given resource from resource pool in crtc state * @state: Pointer to drm crtc state * @type: Resource type * @tag: Search tag for given resource * return: Resource handle if success; pointer error or null otherwise */ void *sde_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag); /** * sde_crtc_res_put - return given resource to resource pool in crtc state * @state: Pointer to drm crtc state * @type: Resource type * @tag: Search tag for given resource * return: None */ void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag); #endif /* _SDE_CRTC_H_ */ drivers/gpu/drm/msm/sde/sde_hw_blk.c +28 −140 Original line number Diff line number Diff line Loading @@ -29,9 +29,11 @@ static LIST_HEAD(sde_hw_blk_list); * sde_hw_blk_init - initialize hw block object * @type: hw block type - enum sde_hw_blk_type * @id: instance id of the hw block * @ops: Pointer to block operations * return: 0 if success; error code otherwise */ int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id) int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id, struct sde_hw_blk_ops *ops) { if (!hw_blk) { pr_err("invalid parameters\n"); Loading @@ -42,7 +44,9 @@ int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id) hw_blk->type = type; hw_blk->id = id; atomic_set(&hw_blk->refcount, 0); INIT_LIST_HEAD(&hw_blk->attach_list); if (ops) hw_blk->ops = *ops; mutex_lock(&sde_hw_blk_lock); list_add(&hw_blk->list, &sde_hw_blk_list); Loading @@ -58,8 +62,6 @@ int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id) */ void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk) { struct sde_hw_blk_attachment *curr, *next; if (!hw_blk) { pr_err("invalid parameters\n"); return; Loading @@ -69,14 +71,6 @@ void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk) pr_err("hw_blk:%d.%d invalid refcount\n", hw_blk->type, hw_blk->id); list_for_each_entry_safe(curr, next, &hw_blk->attach_list, list) { pr_err("hw_blk:%d.%d tag:0x%x/0x%llx still attached\n", hw_blk->type, hw_blk->id, curr->tag, (u64) curr->value); list_del_init(&curr->list); kfree(curr); } mutex_lock(&sde_hw_blk_lock); list_del(&hw_blk->list); mutex_unlock(&sde_hw_blk_lock); Loading @@ -92,6 +86,7 @@ void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk) struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id) { struct sde_hw_blk *curr; int rc, refcount; if (!hw_blk) { mutex_lock(&sde_hw_blk_lock); Loading @@ -108,16 +103,28 @@ struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id) mutex_unlock(&sde_hw_blk_lock); } if (hw_blk) { int refcount = atomic_inc_return(&hw_blk->refcount); if (!hw_blk) { pr_debug("no hw_blk:%d\n", type); return NULL; } refcount = atomic_inc_return(&hw_blk->refcount); pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id, refcount); } else { pr_err("no hw_blk:%d\n", type); if (refcount == 1 && hw_blk->ops.start) { rc = hw_blk->ops.start(hw_blk); if (rc) { pr_err("failed to start hw_blk:%d rc:%d\n", type, rc); goto error_start; } } pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id, refcount); return hw_blk; error_start: sde_hw_blk_put(hw_blk); return ERR_PTR(rc); } /** Loading @@ -125,11 +132,8 @@ struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id) * @hw_blk: hw block to be freed * @free_blk: function to be called when reference count goes to zero */ void sde_hw_blk_put(struct sde_hw_blk *hw_blk, void (*free_blk)(struct sde_hw_blk *)) void sde_hw_blk_put(struct sde_hw_blk *hw_blk) { struct sde_hw_blk_attachment *curr, *next; if (!hw_blk) { pr_err("invalid parameters\n"); return; Loading @@ -146,122 +150,6 @@ void sde_hw_blk_put(struct sde_hw_blk *hw_blk, if (atomic_dec_return(&hw_blk->refcount)) return; if (free_blk) free_blk(hw_blk); /* report any residual attachments */ list_for_each_entry_safe(curr, next, &hw_blk->attach_list, list) { pr_err("hw_blk:%d.%d tag:0x%x/0x%llx still attached\n", hw_blk->type, hw_blk->id, curr->tag, (u64) curr->value); list_del_init(&curr->list); kfree(curr); } } /** * sde_hw_blk_lookup_blk - lookup hardware block that matches tag/value/type * tuple and increment reference count * @tag: search tag * @value: value associated with search tag * @type: hardware block type * return: Pointer to hardware block */ struct sde_hw_blk *sde_hw_blk_lookup_blk(u32 tag, void *value, u32 type) { struct sde_hw_blk *hw_blk = NULL, *curr; struct sde_hw_blk_attachment *attach; pr_debug("hw_blk:%d tag:0x%x/0x%llx\n", type, tag, (u64) value); mutex_lock(&sde_hw_blk_lock); list_for_each_entry(curr, &sde_hw_blk_list, list) { if ((curr->type != type) || !atomic_read(&curr->refcount)) continue; list_for_each_entry(attach, &curr->attach_list, list) { if ((attach->tag != tag) || (attach->value != value)) continue; hw_blk = curr; break; } if (hw_blk) break; } mutex_unlock(&sde_hw_blk_lock); if (hw_blk) sde_hw_blk_get(hw_blk, 0, -1); return hw_blk; } /** * sde_hw_blk_attach - attach given tag/value pair to hardware block * and increment reference count * @hw_blk: Pointer hardware block * @tag: search tag * @value: value associated with search tag * return: 0 if success; error code otherwise */ int sde_hw_blk_attach(struct sde_hw_blk *hw_blk, u32 tag, void *value) { struct sde_hw_blk_attachment *attach; if (!hw_blk) { pr_err("invalid parameters\n"); return -EINVAL; } pr_debug("hw_blk:%d.%d tag:0x%x/0x%llx\n", hw_blk->type, hw_blk->id, tag, (u64) value); attach = kzalloc(sizeof(struct sde_hw_blk_attachment), GFP_KERNEL); if (!attach) return -ENOMEM; INIT_LIST_HEAD(&attach->list); attach->tag = tag; attach->value = value; /* always add to the front so latest shows up first in search */ list_add(&attach->list, &hw_blk->attach_list); sde_hw_blk_get(hw_blk, 0, -1); return 0; } /** * sde_hw_blk_detach - detach given tag/value pair from hardware block * and decrement reference count * @hw_blk: Pointer hardware block * @tag: search tag * @value: value associated with search tag * return: none */ void sde_hw_blk_detach(struct sde_hw_blk *hw_blk, u32 tag, void *value) { struct sde_hw_blk_attachment *curr, *next; if (!hw_blk) { pr_err("invalid parameters\n"); return; } pr_debug("hw_blk:%d.%d tag:0x%x/0x%llx\n", hw_blk->type, hw_blk->id, tag, (u64) value); list_for_each_entry_safe(curr, next, &hw_blk->attach_list, list) { if ((curr->tag != tag) || (curr->value != value)) continue; list_del_init(&curr->list); kfree(curr); sde_hw_blk_put(hw_blk, NULL); return; } pr_err("hw_blk:%d.%d tag:0x%x/0x%llx not found\n", hw_blk->type, hw_blk->id, tag, (u64) value); if (hw_blk->ops.stop) hw_blk->ops.stop(hw_blk); } drivers/gpu/drm/msm/sde/sde_hw_blk.h +12 −46 Original line number Diff line number Diff line Loading @@ -17,16 +17,16 @@ #include <linux/list.h> #include <linux/atomic.h> struct sde_hw_blk; /** * struct sde_hw_blk_attachment - hardware block attachment * @list: list of attachment * @tag: search tag * @value: value associated with the given tag * struct sde_hw_blk_ops - common hardware block operations * @start: start operation on first get * @stop: stop operation on last put */ struct sde_hw_blk_attachment { struct list_head list; u32 tag; void *value; struct sde_hw_blk_ops { int (*start)(struct sde_hw_blk *); void (*stop)(struct sde_hw_blk *); }; /** Loading @@ -35,53 +35,19 @@ struct sde_hw_blk_attachment { * @type: hardware block type * @id: instance id * @refcount: reference/usage count * @attachment_list: list of attachment */ struct sde_hw_blk { struct list_head list; u32 type; int id; atomic_t refcount; struct list_head attach_list; struct sde_hw_blk_ops ops; }; int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id); int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id, struct sde_hw_blk_ops *ops); void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk); struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id); void sde_hw_blk_put(struct sde_hw_blk *hw_blk, void (*blk_free)(struct sde_hw_blk *)); struct sde_hw_blk *sde_hw_blk_lookup_blk(u32 tag, void *value, u32 type); int sde_hw_blk_attach(struct sde_hw_blk *hw_blk, u32 tag, void *value); void sde_hw_blk_detach(struct sde_hw_blk *hw_blk, u32 tag, void *value); /** * sde_hw_blk_lookup_value - return value associated with the given tag * @hw_blk: Pointer to hardware block * @tag: tag to find * @idx: index if more than one value found, with 0 being first * return: value associated with the given tag */ static inline void *sde_hw_blk_lookup_value(struct sde_hw_blk *hw_blk, u32 tag, u32 idx) { struct sde_hw_blk_attachment *attach; if (!hw_blk) return NULL; list_for_each_entry(attach, &hw_blk->attach_list, list) { if (attach->tag != tag) continue; if (idx == 0) return attach->value; idx--; } return NULL; } void sde_hw_blk_put(struct sde_hw_blk *hw_blk); #endif /*_SDE_HW_BLK_H */ drivers/gpu/drm/msm/sde/sde_hw_rot.c +40 −43 Original line number Diff line number Diff line Loading @@ -792,6 +792,42 @@ static void _setup_rot_ops(struct sde_hw_rot_ops *ops, unsigned long features) ops->get_cache_size = sde_hw_rot_get_cache_size; } /** * sde_hw_rot_blk_stop - stop rotator block * @hw_blk: Pointer to base hardware block * return: none */ static void sde_hw_rot_blk_stop(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); sde_hw_rot_stop(hw_rot); } /** * sde_hw_rot_blk_start - art rotator block * @hw_blk: Pointer to base hardware block * return: 0 if success; error code otherwise */ static int sde_hw_rot_blk_start(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); int rc = 0; SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); rc = sde_hw_rot_start(hw_rot); return rc; } static struct sde_hw_blk_ops sde_hw_rot_ops = { .start = sde_hw_rot_blk_start, .stop = sde_hw_rot_blk_stop, }; /** * sde_hw_rot_init - create/initialize given rotator instance * @idx: index of given rotator Loading Loading @@ -823,7 +859,8 @@ struct sde_hw_rot *sde_hw_rot_init(enum sde_rot idx, c->caps = cfg; _setup_rot_ops(&c->ops, c->caps->features); rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx); rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx, &sde_hw_rot_ops); if (rc) { SDE_ERROR("failed to init hw blk %d\n", rc); goto blk_init_error; Loading @@ -850,57 +887,17 @@ void sde_hw_rot_destroy(struct sde_hw_rot *hw_rot) kfree(hw_rot); } /** * sde_hw_rot_blk_stop - stop rotator block * @hw_blk: Pointer to base hardware block * return: none */ static void sde_hw_rot_blk_stop(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); sde_hw_rot_stop(hw_rot); } /** * sde_hw_rot_blk_start - art rotator block * @hw_blk: Pointer to base hardware block * return: 0 if success; error code otherwise */ static int sde_hw_rot_blk_start(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); int rc = 0; SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); rc = sde_hw_rot_start(hw_rot); return rc; } struct sde_hw_rot *sde_hw_rot_get(struct sde_hw_rot *hw_rot) { struct sde_hw_blk *hw_blk = sde_hw_blk_get(hw_rot ? &hw_rot->base : NULL, SDE_HW_BLK_ROT, -1); int rc = 0; if (!hw_rot && hw_blk) rc = sde_hw_rot_blk_start(hw_blk); if (rc) { sde_hw_blk_put(hw_blk, NULL); return NULL; } return hw_blk ? to_sde_hw_rot(hw_blk) : NULL; return IS_ERR_OR_NULL(hw_blk) ? NULL : to_sde_hw_rot(hw_blk); } void sde_hw_rot_put(struct sde_hw_rot *hw_rot) { struct sde_hw_blk *hw_blk = hw_rot ? &hw_rot->base : NULL; sde_hw_blk_put(hw_blk, sde_hw_rot_blk_stop); sde_hw_blk_put(hw_blk); } Loading
drivers/gpu/drm/msm/sde/sde_crtc.c +390 −3 Original line number Diff line number Diff line Loading @@ -117,6 +117,374 @@ static inline int _sde_crtc_power_enable(struct sde_crtc *sde_crtc, bool enable) enable); } /** * _sde_crtc_rp_to_crtc - get crtc from resource pool object * @rp: Pointer to resource pool * return: Pointer to drm crtc if success; null otherwise */ static struct drm_crtc *_sde_crtc_rp_to_crtc(struct sde_crtc_respool *rp) { if (!rp) return NULL; return container_of(rp, struct sde_crtc_state, rp)->base.crtc; } /** * _sde_crtc_rp_reclaim - reclaim unused, or all if forced, resources in pool * @rp: Pointer to resource pool * @force: True to reclaim all resources; otherwise, reclaim only unused ones * return: None */ static void _sde_crtc_rp_reclaim(struct sde_crtc_respool *rp, bool force) { struct sde_crtc_res *res, *next; struct drm_crtc *crtc; crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } SDE_DEBUG("crtc%d.%u %s\n", crtc->base.id, rp->sequence_id, force ? "destroy" : "free_unused"); list_for_each_entry_safe(res, next, &rp->res_list, list) { if (!force && !(res->flags & SDE_CRTC_RES_FLAG_FREE)) continue; SDE_DEBUG("crtc%d.%u reclaim res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); list_del(&res->list); if (res->ops.put) res->ops.put(res->val); kfree(res); } } /** * _sde_crtc_rp_free_unused - free unused resource in pool * @rp: Pointer to resource pool * return: none */ static void _sde_crtc_rp_free_unused(struct sde_crtc_respool *rp) { _sde_crtc_rp_reclaim(rp, false); } /** * _sde_crtc_rp_destroy - destroy resource pool * @rp: Pointer to resource pool * return: None */ static void _sde_crtc_rp_destroy(struct sde_crtc_respool *rp) { _sde_crtc_rp_reclaim(rp, true); } /** * _sde_crtc_hw_blk_get - get callback for hardware block * @val: Resource handle * @type: Resource type * @tag: Search tag for given resource * return: Resource handle */ static void *_sde_crtc_hw_blk_get(void *val, u32 type, u64 tag) { SDE_DEBUG("res:%d/0x%llx/%pK\n", type, tag, val); return sde_hw_blk_get(val, type, tag); } /** * _sde_crtc_hw_blk_put - put callback for hardware block * @val: Resource handle * return: None */ static void _sde_crtc_hw_blk_put(void *val) { SDE_DEBUG("res://%pK\n", val); sde_hw_blk_put(val); } /** * _sde_crtc_rp_duplicate - duplicate resource pool and reset reference count * @rp: Pointer to original resource pool * @dup_rp: Pointer to duplicated resource pool * return: None */ static void _sde_crtc_rp_duplicate(struct sde_crtc_respool *rp, struct sde_crtc_respool *dup_rp) { struct sde_crtc_res *res, *dup_res; struct drm_crtc *crtc; if (!rp || !dup_rp) { SDE_ERROR("invalid resource pool\n"); return; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } SDE_DEBUG("crtc%d.%u duplicate\n", crtc->base.id, rp->sequence_id); dup_rp->sequence_id = rp->sequence_id + 1; INIT_LIST_HEAD(&dup_rp->res_list); dup_rp->ops = rp->ops; list_for_each_entry(res, &rp->res_list, list) { dup_res = kzalloc(sizeof(struct sde_crtc_res), GFP_KERNEL); if (!dup_res) return; INIT_LIST_HEAD(&dup_res->list); atomic_set(&dup_res->refcount, 0); dup_res->type = res->type; dup_res->tag = res->tag; dup_res->val = res->val; dup_res->ops = res->ops; dup_res->flags = SDE_CRTC_RES_FLAG_FREE; SDE_DEBUG("crtc%d.%u dup res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, dup_rp->sequence_id, dup_res->type, dup_res->tag, dup_res->val, atomic_read(&dup_res->refcount)); list_add_tail(&dup_res->list, &dup_rp->res_list); if (dup_res->ops.get) dup_res->ops.get(dup_res->val, 0, -1); } } /** * _sde_crtc_rp_reset - reset resource pool after allocation * @rp: Pointer to original resource pool * return: None */ static void _sde_crtc_rp_reset(struct sde_crtc_respool *rp) { if (!rp) { SDE_ERROR("invalid resource pool\n"); return; } rp->sequence_id = 0; INIT_LIST_HEAD(&rp->res_list); rp->ops.get = _sde_crtc_hw_blk_get; rp->ops.put = _sde_crtc_hw_blk_put; } /** * _sde_crtc_rp_add - add given resource to resource pool * @rp: Pointer to original resource pool * @type: Resource type * @tag: Search tag for given resource * @val: Resource handle * @ops: Resource callback operations * return: 0 if success; error code otherwise */ static int _sde_crtc_rp_add(struct sde_crtc_respool *rp, u32 type, u64 tag, void *val, struct sde_crtc_res_ops *ops) { struct sde_crtc_res *res; struct drm_crtc *crtc; if (!rp || !ops) { SDE_ERROR("invalid resource pool/ops\n"); return -EINVAL; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return -EINVAL; } list_for_each_entry(res, &rp->res_list, list) { if (res->type != type || res->tag != tag) continue; SDE_ERROR("crtc%d.%u already exist res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); return -EEXIST; } res = kzalloc(sizeof(struct sde_crtc_res), GFP_KERNEL); if (!res) return -ENOMEM; INIT_LIST_HEAD(&res->list); atomic_set(&res->refcount, 1); res->type = type; res->tag = tag; res->val = val; res->ops = *ops; list_add_tail(&res->list, &rp->res_list); SDE_DEBUG("crtc%d.%u added res:0x%x/0x%llx\n", crtc->base.id, rp->sequence_id, type, tag); return 0; } /** * _sde_crtc_rp_get - lookup the resource from given resource pool and obtain * if available; otherwise, obtain resource from global pool * @rp: Pointer to original resource pool * @type: Resource type * @tag: Search tag for given resource * return: Resource handle if success; pointer error or null otherwise */ static void *_sde_crtc_rp_get(struct sde_crtc_respool *rp, u32 type, u64 tag) { struct sde_crtc_res *res; void *val = NULL; int rc; struct drm_crtc *crtc; if (!rp) { SDE_ERROR("invalid resource pool\n"); return NULL; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return NULL; } list_for_each_entry(res, &rp->res_list, list) { if (res->type != type || res->tag != tag) continue; SDE_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); atomic_inc(&res->refcount); res->flags &= ~SDE_CRTC_RES_FLAG_FREE; return res->val; } list_for_each_entry(res, &rp->res_list, list) { if (res->type != type || !(res->flags & SDE_CRTC_RES_FLAG_FREE)) continue; SDE_DEBUG("crtc%d.%u retag res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); atomic_inc(&res->refcount); res->tag = tag; res->flags &= ~SDE_CRTC_RES_FLAG_FREE; return res->val; } if (rp->ops.get) val = rp->ops.get(NULL, type, -1); if (IS_ERR_OR_NULL(val)) { SDE_ERROR("crtc%d.%u failed to get res:0x%x//\n", crtc->base.id, rp->sequence_id, type); return NULL; } rc = _sde_crtc_rp_add(rp, type, tag, val, &rp->ops); if (rc) { SDE_ERROR("crtc%d.%u failed to add res:0x%x/0x%llx\n", crtc->base.id, rp->sequence_id, type, tag); if (rp->ops.put) rp->ops.put(val); val = NULL; } return val; } /** * _sde_crtc_rp_put - return given resource to resource pool * @rp: Pointer to original resource pool * @type: Resource type * @tag: Search tag for given resource * return: None */ static void _sde_crtc_rp_put(struct sde_crtc_respool *rp, u32 type, u64 tag) { struct sde_crtc_res *res, *next; struct drm_crtc *crtc; if (!rp) { SDE_ERROR("invalid resource pool\n"); return; } crtc = _sde_crtc_rp_to_crtc(rp); if (!crtc) { SDE_ERROR("invalid crtc\n"); return; } list_for_each_entry_safe(res, next, &rp->res_list, list) { if (res->type != type || res->tag != tag) continue; SDE_DEBUG("crtc%d.%u found res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); if (res->flags & SDE_CRTC_RES_FLAG_FREE) SDE_ERROR( "crtc%d.%u already free res:0x%x/0x%llx/%pK/%d\n", crtc->base.id, rp->sequence_id, res->type, res->tag, res->val, atomic_read(&res->refcount)); else if (atomic_dec_return(&res->refcount) == 0) res->flags |= SDE_CRTC_RES_FLAG_FREE; return; } SDE_ERROR("crtc%d.%u not found res:0x%x/0x%llx\n", crtc->base.id, rp->sequence_id, type, tag); } int sde_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, void *val, struct sde_crtc_res_ops *ops) { struct sde_crtc_respool *rp; if (!state) { SDE_ERROR("invalid parameters\n"); return -EINVAL; } rp = &to_sde_crtc_state(state)->rp; return _sde_crtc_rp_add(rp, type, tag, val, ops); } void *sde_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag) { struct sde_crtc_respool *rp; void *val; if (!state) { SDE_ERROR("invalid parameters\n"); return NULL; } rp = &to_sde_crtc_state(state)->rp; val = _sde_crtc_rp_get(rp, type, tag); if (IS_ERR(val)) { SDE_ERROR("failed to get res type:0x%x:0x%llx\n", type, tag); return NULL; } return val; } void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag) { struct sde_crtc_respool *rp; if (!state) { SDE_ERROR("invalid parameters\n"); return; } rp = &to_sde_crtc_state(state)->rp; _sde_crtc_rp_put(rp, type, tag); } static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) { if (!sde_crtc) Loading Loading @@ -1071,6 +1439,8 @@ static void sde_crtc_destroy_state(struct drm_crtc *crtc, SDE_DEBUG("crtc%d\n", crtc->base.id); _sde_crtc_rp_destroy(&cstate->rp); __drm_atomic_helper_crtc_destroy_state(state); /* destroy value helper */ Loading Loading @@ -1262,6 +1632,8 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) /* duplicate base helper */ __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); _sde_crtc_rp_duplicate(&old_cstate->rp, &cstate->rp); return &cstate->base; } Loading Loading @@ -1304,6 +1676,8 @@ static void sde_crtc_reset(struct drm_crtc *crtc) _sde_crtc_set_input_fence_timeout(cstate); _sde_crtc_rp_reset(&cstate->rp); cstate->base.crtc = crtc; crtc->state = &cstate->base; } Loading Loading @@ -1487,14 +1861,15 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, return -EINVAL; } sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(state); if (!state->enable || !state->active) { SDE_DEBUG("crtc%d -> enable %d, active %d, skip atomic_check\n", crtc->base.id, state->enable, state->active); return 0; goto end; } sde_crtc = to_sde_crtc(crtc); cstate = to_sde_crtc_state(state); mode = &state->adjusted_mode; SDE_DEBUG("%s: check", sde_crtc->name); Loading Loading @@ -1702,6 +2077,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc, end: _sde_crtc_rp_free_unused(&cstate->rp); return rc; } Loading Loading @@ -1907,6 +2283,9 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, } if (ret) DRM_ERROR("failed to set the property\n"); SDE_DEBUG("crtc%d %s[%d] <= 0x%llx ret=%d\n", crtc->base.id, property->name, property->base.id, val, ret); } return ret; Loading Loading @@ -2209,6 +2588,7 @@ static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v) { struct drm_crtc *crtc = (struct drm_crtc *) s->private; struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state); struct sde_crtc_res *res; seq_printf(s, "num_connectors: %d\n", cstate->num_connectors); seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc)); Loading @@ -2218,6 +2598,13 @@ static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v) seq_printf(s, "max_per_pipe_ib: %llu\n", cstate->cur_perf.max_per_pipe_ib); seq_printf(s, "rp.%d: ", cstate->rp.sequence_id); list_for_each_entry(res, &cstate->rp.res_list, list) seq_printf(s, "0x%x/0x%llx/%pK/%d ", res->type, res->tag, res->val, atomic_read(&res->refcount)); seq_puts(s, "\n"); return 0; } DEFINE_SDE_DEBUGFS_SEQ_FOPS(sde_crtc_debugfs_state); Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +83 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include "sde_fence.h" #include "sde_kms.h" #include "sde_core_perf.h" #include "sde_hw_blk.h" #define SDE_CRTC_NAME_SIZE 12 Loading Loading @@ -190,6 +191,56 @@ struct sde_crtc { #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) /** * struct sde_crtc_res_ops - common operations for crtc resources * @get: get given resource * @put: put given resource */ struct sde_crtc_res_ops { void *(*get)(void *val, u32 type, u64 tag); void (*put)(void *val); }; /* crtc resource type (0x0-0xffff reserved for hw block type */ #define SDE_CRTC_RES_ROT_OUT_FBO 0x10000 #define SDE_CRTC_RES_ROT_OUT_FB 0x10001 #define SDE_CRTC_RES_ROT_PLANE 0x10002 #define SDE_CRTC_RES_ROT_IN_FB 0x10003 #define SDE_CRTC_RES_FLAG_FREE BIT(0) /** * struct sde_crtc_res - definition of crtc resources * @list: list of crtc resource * @type: crtc resource type * @tag: unique identifier per type * @refcount: reference/usage count * @ops: callback operations * @val: resource handle associated with type/tag * @flags: customization flags */ struct sde_crtc_res { struct list_head list; u32 type; u64 tag; atomic_t refcount; struct sde_crtc_res_ops ops; void *val; u32 flags; }; /** * sde_crtc_respool - crtc resource pool * @sequence_id: sequence identifier, incremented per state duplication * @res_list: list of resource managed by this resource pool * @ops: resource operations for parent resource pool */ struct sde_crtc_respool { u32 sequence_id; struct list_head res_list; struct sde_crtc_res_ops ops; }; /** * struct sde_crtc_state - sde container for atomic crtc state * @base: Base drm crtc state structure Loading Loading @@ -226,6 +277,8 @@ struct sde_crtc_state { struct sde_core_perf_params new_perf; struct sde_ctl_sbuf_cfg sbuf_cfg; u64 sbuf_prefill_line; struct sde_crtc_respool rp; }; #define to_sde_crtc_state(x) \ Loading Loading @@ -370,4 +423,34 @@ static inline bool sde_crtc_is_enabled(struct drm_crtc *crtc) int sde_crtc_event_queue(struct drm_crtc *crtc, void (*func)(struct drm_crtc *crtc, void *usr), void *usr); /** * sde_crtc_res_add - add given resource to resource pool in crtc state * @state: Pointer to drm crtc state * @type: Resource type * @tag: Search tag for given resource * @val: Resource handle * @ops: Resource callback operations * return: 0 if success; error code otherwise */ int sde_crtc_res_add(struct drm_crtc_state *state, u32 type, u64 tag, void *val, struct sde_crtc_res_ops *ops); /** * sde_crtc_res_get - get given resource from resource pool in crtc state * @state: Pointer to drm crtc state * @type: Resource type * @tag: Search tag for given resource * return: Resource handle if success; pointer error or null otherwise */ void *sde_crtc_res_get(struct drm_crtc_state *state, u32 type, u64 tag); /** * sde_crtc_res_put - return given resource to resource pool in crtc state * @state: Pointer to drm crtc state * @type: Resource type * @tag: Search tag for given resource * return: None */ void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag); #endif /* _SDE_CRTC_H_ */
drivers/gpu/drm/msm/sde/sde_hw_blk.c +28 −140 Original line number Diff line number Diff line Loading @@ -29,9 +29,11 @@ static LIST_HEAD(sde_hw_blk_list); * sde_hw_blk_init - initialize hw block object * @type: hw block type - enum sde_hw_blk_type * @id: instance id of the hw block * @ops: Pointer to block operations * return: 0 if success; error code otherwise */ int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id) int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id, struct sde_hw_blk_ops *ops) { if (!hw_blk) { pr_err("invalid parameters\n"); Loading @@ -42,7 +44,9 @@ int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id) hw_blk->type = type; hw_blk->id = id; atomic_set(&hw_blk->refcount, 0); INIT_LIST_HEAD(&hw_blk->attach_list); if (ops) hw_blk->ops = *ops; mutex_lock(&sde_hw_blk_lock); list_add(&hw_blk->list, &sde_hw_blk_list); Loading @@ -58,8 +62,6 @@ int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id) */ void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk) { struct sde_hw_blk_attachment *curr, *next; if (!hw_blk) { pr_err("invalid parameters\n"); return; Loading @@ -69,14 +71,6 @@ void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk) pr_err("hw_blk:%d.%d invalid refcount\n", hw_blk->type, hw_blk->id); list_for_each_entry_safe(curr, next, &hw_blk->attach_list, list) { pr_err("hw_blk:%d.%d tag:0x%x/0x%llx still attached\n", hw_blk->type, hw_blk->id, curr->tag, (u64) curr->value); list_del_init(&curr->list); kfree(curr); } mutex_lock(&sde_hw_blk_lock); list_del(&hw_blk->list); mutex_unlock(&sde_hw_blk_lock); Loading @@ -92,6 +86,7 @@ void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk) struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id) { struct sde_hw_blk *curr; int rc, refcount; if (!hw_blk) { mutex_lock(&sde_hw_blk_lock); Loading @@ -108,16 +103,28 @@ struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id) mutex_unlock(&sde_hw_blk_lock); } if (hw_blk) { int refcount = atomic_inc_return(&hw_blk->refcount); if (!hw_blk) { pr_debug("no hw_blk:%d\n", type); return NULL; } refcount = atomic_inc_return(&hw_blk->refcount); pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id, refcount); } else { pr_err("no hw_blk:%d\n", type); if (refcount == 1 && hw_blk->ops.start) { rc = hw_blk->ops.start(hw_blk); if (rc) { pr_err("failed to start hw_blk:%d rc:%d\n", type, rc); goto error_start; } } pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id, refcount); return hw_blk; error_start: sde_hw_blk_put(hw_blk); return ERR_PTR(rc); } /** Loading @@ -125,11 +132,8 @@ struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id) * @hw_blk: hw block to be freed * @free_blk: function to be called when reference count goes to zero */ void sde_hw_blk_put(struct sde_hw_blk *hw_blk, void (*free_blk)(struct sde_hw_blk *)) void sde_hw_blk_put(struct sde_hw_blk *hw_blk) { struct sde_hw_blk_attachment *curr, *next; if (!hw_blk) { pr_err("invalid parameters\n"); return; Loading @@ -146,122 +150,6 @@ void sde_hw_blk_put(struct sde_hw_blk *hw_blk, if (atomic_dec_return(&hw_blk->refcount)) return; if (free_blk) free_blk(hw_blk); /* report any residual attachments */ list_for_each_entry_safe(curr, next, &hw_blk->attach_list, list) { pr_err("hw_blk:%d.%d tag:0x%x/0x%llx still attached\n", hw_blk->type, hw_blk->id, curr->tag, (u64) curr->value); list_del_init(&curr->list); kfree(curr); } } /** * sde_hw_blk_lookup_blk - lookup hardware block that matches tag/value/type * tuple and increment reference count * @tag: search tag * @value: value associated with search tag * @type: hardware block type * return: Pointer to hardware block */ struct sde_hw_blk *sde_hw_blk_lookup_blk(u32 tag, void *value, u32 type) { struct sde_hw_blk *hw_blk = NULL, *curr; struct sde_hw_blk_attachment *attach; pr_debug("hw_blk:%d tag:0x%x/0x%llx\n", type, tag, (u64) value); mutex_lock(&sde_hw_blk_lock); list_for_each_entry(curr, &sde_hw_blk_list, list) { if ((curr->type != type) || !atomic_read(&curr->refcount)) continue; list_for_each_entry(attach, &curr->attach_list, list) { if ((attach->tag != tag) || (attach->value != value)) continue; hw_blk = curr; break; } if (hw_blk) break; } mutex_unlock(&sde_hw_blk_lock); if (hw_blk) sde_hw_blk_get(hw_blk, 0, -1); return hw_blk; } /** * sde_hw_blk_attach - attach given tag/value pair to hardware block * and increment reference count * @hw_blk: Pointer hardware block * @tag: search tag * @value: value associated with search tag * return: 0 if success; error code otherwise */ int sde_hw_blk_attach(struct sde_hw_blk *hw_blk, u32 tag, void *value) { struct sde_hw_blk_attachment *attach; if (!hw_blk) { pr_err("invalid parameters\n"); return -EINVAL; } pr_debug("hw_blk:%d.%d tag:0x%x/0x%llx\n", hw_blk->type, hw_blk->id, tag, (u64) value); attach = kzalloc(sizeof(struct sde_hw_blk_attachment), GFP_KERNEL); if (!attach) return -ENOMEM; INIT_LIST_HEAD(&attach->list); attach->tag = tag; attach->value = value; /* always add to the front so latest shows up first in search */ list_add(&attach->list, &hw_blk->attach_list); sde_hw_blk_get(hw_blk, 0, -1); return 0; } /** * sde_hw_blk_detach - detach given tag/value pair from hardware block * and decrement reference count * @hw_blk: Pointer hardware block * @tag: search tag * @value: value associated with search tag * return: none */ void sde_hw_blk_detach(struct sde_hw_blk *hw_blk, u32 tag, void *value) { struct sde_hw_blk_attachment *curr, *next; if (!hw_blk) { pr_err("invalid parameters\n"); return; } pr_debug("hw_blk:%d.%d tag:0x%x/0x%llx\n", hw_blk->type, hw_blk->id, tag, (u64) value); list_for_each_entry_safe(curr, next, &hw_blk->attach_list, list) { if ((curr->tag != tag) || (curr->value != value)) continue; list_del_init(&curr->list); kfree(curr); sde_hw_blk_put(hw_blk, NULL); return; } pr_err("hw_blk:%d.%d tag:0x%x/0x%llx not found\n", hw_blk->type, hw_blk->id, tag, (u64) value); if (hw_blk->ops.stop) hw_blk->ops.stop(hw_blk); }
drivers/gpu/drm/msm/sde/sde_hw_blk.h +12 −46 Original line number Diff line number Diff line Loading @@ -17,16 +17,16 @@ #include <linux/list.h> #include <linux/atomic.h> struct sde_hw_blk; /** * struct sde_hw_blk_attachment - hardware block attachment * @list: list of attachment * @tag: search tag * @value: value associated with the given tag * struct sde_hw_blk_ops - common hardware block operations * @start: start operation on first get * @stop: stop operation on last put */ struct sde_hw_blk_attachment { struct list_head list; u32 tag; void *value; struct sde_hw_blk_ops { int (*start)(struct sde_hw_blk *); void (*stop)(struct sde_hw_blk *); }; /** Loading @@ -35,53 +35,19 @@ struct sde_hw_blk_attachment { * @type: hardware block type * @id: instance id * @refcount: reference/usage count * @attachment_list: list of attachment */ struct sde_hw_blk { struct list_head list; u32 type; int id; atomic_t refcount; struct list_head attach_list; struct sde_hw_blk_ops ops; }; int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id); int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id, struct sde_hw_blk_ops *ops); void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk); struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id); void sde_hw_blk_put(struct sde_hw_blk *hw_blk, void (*blk_free)(struct sde_hw_blk *)); struct sde_hw_blk *sde_hw_blk_lookup_blk(u32 tag, void *value, u32 type); int sde_hw_blk_attach(struct sde_hw_blk *hw_blk, u32 tag, void *value); void sde_hw_blk_detach(struct sde_hw_blk *hw_blk, u32 tag, void *value); /** * sde_hw_blk_lookup_value - return value associated with the given tag * @hw_blk: Pointer to hardware block * @tag: tag to find * @idx: index if more than one value found, with 0 being first * return: value associated with the given tag */ static inline void *sde_hw_blk_lookup_value(struct sde_hw_blk *hw_blk, u32 tag, u32 idx) { struct sde_hw_blk_attachment *attach; if (!hw_blk) return NULL; list_for_each_entry(attach, &hw_blk->attach_list, list) { if (attach->tag != tag) continue; if (idx == 0) return attach->value; idx--; } return NULL; } void sde_hw_blk_put(struct sde_hw_blk *hw_blk); #endif /*_SDE_HW_BLK_H */
drivers/gpu/drm/msm/sde/sde_hw_rot.c +40 −43 Original line number Diff line number Diff line Loading @@ -792,6 +792,42 @@ static void _setup_rot_ops(struct sde_hw_rot_ops *ops, unsigned long features) ops->get_cache_size = sde_hw_rot_get_cache_size; } /** * sde_hw_rot_blk_stop - stop rotator block * @hw_blk: Pointer to base hardware block * return: none */ static void sde_hw_rot_blk_stop(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); sde_hw_rot_stop(hw_rot); } /** * sde_hw_rot_blk_start - art rotator block * @hw_blk: Pointer to base hardware block * return: 0 if success; error code otherwise */ static int sde_hw_rot_blk_start(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); int rc = 0; SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); rc = sde_hw_rot_start(hw_rot); return rc; } static struct sde_hw_blk_ops sde_hw_rot_ops = { .start = sde_hw_rot_blk_start, .stop = sde_hw_rot_blk_stop, }; /** * sde_hw_rot_init - create/initialize given rotator instance * @idx: index of given rotator Loading Loading @@ -823,7 +859,8 @@ struct sde_hw_rot *sde_hw_rot_init(enum sde_rot idx, c->caps = cfg; _setup_rot_ops(&c->ops, c->caps->features); rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx); rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_ROT, idx, &sde_hw_rot_ops); if (rc) { SDE_ERROR("failed to init hw blk %d\n", rc); goto blk_init_error; Loading @@ -850,57 +887,17 @@ void sde_hw_rot_destroy(struct sde_hw_rot *hw_rot) kfree(hw_rot); } /** * sde_hw_rot_blk_stop - stop rotator block * @hw_blk: Pointer to base hardware block * return: none */ static void sde_hw_rot_blk_stop(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); sde_hw_rot_stop(hw_rot); } /** * sde_hw_rot_blk_start - art rotator block * @hw_blk: Pointer to base hardware block * return: 0 if success; error code otherwise */ static int sde_hw_rot_blk_start(struct sde_hw_blk *hw_blk) { struct sde_hw_rot *hw_rot = to_sde_hw_rot(hw_blk); int rc = 0; SDE_DEBUG("type:%d id:%d\n", hw_blk->type, hw_blk->id); rc = sde_hw_rot_start(hw_rot); return rc; } struct sde_hw_rot *sde_hw_rot_get(struct sde_hw_rot *hw_rot) { struct sde_hw_blk *hw_blk = sde_hw_blk_get(hw_rot ? &hw_rot->base : NULL, SDE_HW_BLK_ROT, -1); int rc = 0; if (!hw_rot && hw_blk) rc = sde_hw_rot_blk_start(hw_blk); if (rc) { sde_hw_blk_put(hw_blk, NULL); return NULL; } return hw_blk ? to_sde_hw_rot(hw_blk) : NULL; return IS_ERR_OR_NULL(hw_blk) ? NULL : to_sde_hw_rot(hw_blk); } void sde_hw_rot_put(struct sde_hw_rot *hw_rot) { struct sde_hw_blk *hw_blk = hw_rot ? &hw_rot->base : NULL; sde_hw_blk_put(hw_blk, sde_hw_rot_blk_stop); sde_hw_blk_put(hw_blk); }