diff --git a/msm/sde/sde_fence.c b/msm/sde/sde_fence.c index bc1d6874ab..6c09aa1d67 100644 --- a/msm/sde/sde_fence.c +++ b/msm/sde/sde_fence.c @@ -63,12 +63,18 @@ enum sde_hw_fence_clients { * This 'hw_fence_data_dpu_client' must be used for HW that does not support dpu-signal. */ struct sde_hw_fence_data hw_fence_data_no_dpu[SDE_HW_FENCE_CLIENT_MAX] = { - {SDE_HW_FENCE_CLIENT_CTL_0, HW_FENCE_CLIENT_ID_CTL0, NULL, {0}, 8, 14, {2, 3}, 0, 8, 8}, - {SDE_HW_FENCE_CLIENT_CTL_1, HW_FENCE_CLIENT_ID_CTL1, NULL, {0}, 8, 15, {4, 5}, 0, 8, 8}, - {SDE_HW_FENCE_CLIENT_CTL_2, HW_FENCE_CLIENT_ID_CTL2, NULL, {0}, 8, 16, {6, 7}, 0, 8, 8}, - {SDE_HW_FENCE_CLIENT_CTL_3, HW_FENCE_CLIENT_ID_CTL3, NULL, {0}, 8, 17, {8, 9}, 0, 8, 8}, - {SDE_HW_FENCE_CLIENT_CTL_4, HW_FENCE_CLIENT_ID_CTL4, NULL, {0}, 8, 18, {10, 11}, 0, 8, 8}, - {SDE_HW_FENCE_CLIENT_CTL_5, HW_FENCE_CLIENT_ID_CTL5, NULL, {0}, 8, 19, {12, 13}, 0, 8, 8} + {SDE_HW_FENCE_CLIENT_CTL_0, HW_FENCE_CLIENT_ID_CTL0, NULL, {0}, 8, 14, {2, 3}, 0, 8, 8, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_1, HW_FENCE_CLIENT_ID_CTL1, NULL, {0}, 8, 15, {4, 5}, 0, 8, 8, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_2, HW_FENCE_CLIENT_ID_CTL2, NULL, {0}, 8, 16, {6, 7}, 0, 8, 8, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_3, HW_FENCE_CLIENT_ID_CTL3, NULL, {0}, 8, 17, {8, 9}, 0, 8, 8, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_4, HW_FENCE_CLIENT_ID_CTL4, NULL, {0}, 8, 18, {10, 11}, 0, 8, 8, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_5, HW_FENCE_CLIENT_ID_CTL5, NULL, {0}, 8, 19, {12, 13}, 0, 8, 8, + 0, 0} }; /** @@ -79,12 +85,18 @@ struct sde_hw_fence_data hw_fence_data_no_dpu[SDE_HW_FENCE_CLIENT_MAX] = { * This 'hw_fence_data_dpu_client' must be used for HW that supports dpu-signal */ struct sde_hw_fence_data hw_fence_data_dpu_client[SDE_HW_FENCE_CLIENT_MAX] = { - {SDE_HW_FENCE_CLIENT_CTL_0, HW_FENCE_CLIENT_ID_CTL0, NULL, {0}, 8, 0, {0, 6}, 0, 8, 25}, - {SDE_HW_FENCE_CLIENT_CTL_1, HW_FENCE_CLIENT_ID_CTL1, NULL, {0}, 8, 1, {1, 7}, 0, 8, 25}, - {SDE_HW_FENCE_CLIENT_CTL_2, HW_FENCE_CLIENT_ID_CTL2, NULL, {0}, 8, 2, {2, 8}, 0, 8, 25}, - {SDE_HW_FENCE_CLIENT_CTL_3, HW_FENCE_CLIENT_ID_CTL3, NULL, {0}, 8, 3, {3, 9}, 0, 8, 25}, - {SDE_HW_FENCE_CLIENT_CTL_4, HW_FENCE_CLIENT_ID_CTL4, NULL, {0}, 8, 4, {4, 10}, 0, 8, 25}, - {SDE_HW_FENCE_CLIENT_CTL_5, HW_FENCE_CLIENT_ID_CTL5, NULL, {0}, 8, 5, {5, 11}, 0, 8, 25} + {SDE_HW_FENCE_CLIENT_CTL_0, HW_FENCE_CLIENT_ID_CTL0, NULL, {0}, 8, 0, {0, 6}, 0, 8, 25, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_1, HW_FENCE_CLIENT_ID_CTL1, NULL, {0}, 8, 1, {1, 7}, 0, 8, 25, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_2, HW_FENCE_CLIENT_ID_CTL2, NULL, {0}, 8, 2, {2, 8}, 0, 8, 25, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_3, HW_FENCE_CLIENT_ID_CTL3, NULL, {0}, 8, 3, {3, 9}, 0, 8, 25, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_4, HW_FENCE_CLIENT_ID_CTL4, NULL, {0}, 8, 4, {4, 10}, 0, 8, 25, + 0, 0}, + {SDE_HW_FENCE_CLIENT_CTL_5, HW_FENCE_CLIENT_ID_CTL5, NULL, {0}, 8, 5, {5, 11}, 0, 8, 25, + 0, 0} }; int sde_hw_fence_init(struct sde_hw_ctl *hw_ctl, bool use_dpu_ipcc) @@ -117,6 +129,9 @@ int sde_hw_fence_init(struct sde_hw_ctl *hw_ctl, bool use_dpu_ipcc) SDE_DEBUG("hwfence register ctl:%d client:%d\n", ctl_id, hwfence_data->hw_fence_client_id); hwfence_data->hw_fence_handle = msm_hw_fence_register(hwfence_data->hw_fence_client_id, &hwfence_data->mem_descriptor); + + hwfence_data->dma_context = dma_fence_context_alloc(1); + if (IS_ERR_OR_NULL(hwfence_data->hw_fence_handle)) { hwfence_data->hw_fence_handle = NULL; @@ -216,12 +231,29 @@ static inline char *_get_client_id_name(int hw_fence_client_id) return "unknown"; } +static void _cleanup_fences_refcount(struct dma_fence **fences, u32 num_fences) +{ + int i; + + for (i = 0; i < num_fences; i++) + dma_fence_put(fences[i]); +} + int sde_fence_register_hw_fences_wait(struct sde_hw_ctl *hw_ctl, struct dma_fence **fences, u32 num_fences) { struct sde_hw_fence_data *data; - int i, ret; + int i, j, ret; int ctl_id; + struct dma_fence_array *temp_array = NULL; + struct dma_fence *base_fence; + struct dma_fence **hw_fences; + u32 num_hw_fences; + struct dma_fence **fence_list; + struct dma_fence_array *array = NULL; + int array_childs = 0; + int array_count = 0; + int fence_list_index = 0; if (!hw_ctl) { SDE_ERROR("wrong ctl\n"); @@ -239,14 +271,73 @@ int sde_fence_register_hw_fences_wait(struct sde_hw_ctl *hw_ctl, struct dma_fenc num_fences, ctl_id, _get_client_id_name(data->hw_fence_client_id)); for (i = 0; i < num_fences; i++) { + /* get a refcount for each of the fences */ + dma_fence_get(fences[i]); + + if (dma_fence_is_array(fences[i])) { + array_count++; + array = container_of(fences[i], struct dma_fence_array, base); + array_childs += array->num_fences; + } + SDE_DEBUG("registering fence: ctx:%llu seqno:%llu\n", (fences[i])->context, (fences[i])->seqno); } + if (num_fences > 1) { + /* fence_list memory is freed during fence-array release */ + fence_list = kzalloc(((num_fences - array_count) + array_childs) + * (sizeof(struct dma_fence *)), GFP_KERNEL); + if (!fence_list) { + _cleanup_fences_refcount(fences, num_fences); + return -EINVAL; + } + + /* populate fence_list with the fences */ + for (i = 0; i < num_fences; i++) { + if (dma_fence_is_array(fences[i])) { + array = container_of(fences[i], struct dma_fence_array, base); + for (j = 0; j < array->num_fences; j++) { + /* get a refcount for each of the child fences */ + dma_fence_get(array->fences[j]); + fence_list[fence_list_index++] = array->fences[j]; + } + /* remove refcount on parent */ + dma_fence_put(fences[i]); + } else { + fence_list[fence_list_index++] = fences[i]; + } + } + + temp_array = dma_fence_array_create(fence_list_index, fence_list, + data->dma_context, data->hw_fence_array_seqno++, 0); + if (!temp_array) { + SDE_ERROR("unable to create fence array, cant register for wait\n"); + _cleanup_fences_refcount(fences, num_fences); + kfree(fence_list); + return -EINVAL; + } + + base_fence = &temp_array->base; + hw_fences = &base_fence; + num_hw_fences = 1; + + } else { + hw_fences = fences; + num_hw_fences = num_fences; + } + /* register for wait */ - ret = msm_hw_fence_wait_update(data->hw_fence_handle, fences, num_fences, true); + ret = msm_hw_fence_wait_update(data->hw_fence_handle, hw_fences, num_hw_fences, true); if (ret) SDE_ERROR("failed to register wait fences for ctl_id:%d ret:%d\n", ctl_id, ret); + + /* fence-array put will release each individual extra refcount during array release */ + if (temp_array) + dma_fence_put(&temp_array->base); + else + dma_fence_put(fences[0]); + SDE_EVT32_VERBOSE(ctl_id, num_fences, ret); return ret; diff --git a/msm/sde/sde_fence.h b/msm/sde/sde_fence.h index 87a0220078..8bd6a1c0d5 100644 --- a/msm/sde/sde_fence.h +++ b/msm/sde/sde_fence.h @@ -73,6 +73,8 @@ enum sde_fence_event { * @ipcc_out_signal_pp_idx: index of the output signal ping-pong * @ipcc_out_client: destination client id (APPS for the FCTL) * @ipcc_this_client: ipcc dpu client id (For Waipio: APPS, For Kailua: DPU HW) + * @dma_context: per client dma context used to create join fences + * @hw_fence_array_seqno: per-client seq number counter for join fences */ struct sde_hw_fence_data { int client_id; @@ -85,6 +87,8 @@ struct sde_hw_fence_data { u32 ipcc_out_signal_pp_idx; u32 ipcc_out_client; u32 ipcc_this_client; + u64 dma_context; + u32 hw_fence_array_seqno; }; #if IS_ENABLED(CONFIG_SYNC_FILE)