From eb7183da312cbc8deabe384779a79a43214a20a9 Mon Sep 17 00:00:00 2001 From: Jack Diver Date: Fri, 19 Jan 2024 12:00:12 +0000 Subject: mali_kbase: Repurpose liveness ioctl as SLC signal Bug: 321199350 Test: gfxbench Signed-off-by: Jack Diver (cherry picked from https://partner-android-review.googlesource.com/q/commit:57ef78bad803aab9d83325f80349f33727af9af8) Merged-In: I94ff92333cae9b9c54f27af550777fc21da06cb7 Change-Id: I94ff92333cae9b9c54f27af550777fc21da06cb7 --- mali_kbase/platform/pixel/pixel_gpu_slc.c | 153 +++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) (limited to 'mali_kbase/platform/pixel/pixel_gpu_slc.c') diff --git a/mali_kbase/platform/pixel/pixel_gpu_slc.c b/mali_kbase/platform/pixel/pixel_gpu_slc.c index cf330af..1aac4d8 100644 --- a/mali_kbase/platform/pixel/pixel_gpu_slc.c +++ b/mali_kbase/platform/pixel/pixel_gpu_slc.c @@ -48,6 +48,73 @@ static bool transition(int *v, int old, int new) return cond; } +#ifndef PIXEL_GPU_SLC_ACPM_SIGNAL +/** + * struct gpu_slc_liveness_update_info - Buffer info, and live ranges + * + * @buffer_sizes: Array of buffer sizes + * @buffer_count: Number of elements in the va and sizes buffers + * @live_ranges: Array of &struct kbase_pixel_gpu_slc_liveness_mark denoting live ranges for + * each buffer + * @live_ranges_count: Number of elements in the live ranges buffer + */ +struct gpu_slc_liveness_update_info { + u64* buffer_sizes; + u64 buffer_count; + struct kbase_pixel_gpu_slc_liveness_mark* live_ranges; + u64 live_ranges_count; +}; + +/** + * gpu_slc_liveness_update - Respond to a liveness update by trying to put the new buffers into free + * SLC space, and resizing the partition to meet demand. + * + * @kctx: The &struct kbase_context corresponding to a user space context which sent the liveness + * update + * @info: See struct gpu_slc_liveness_update_info + */ +static void gpu_slc_liveness_update(struct kbase_context* kctx, + struct gpu_slc_liveness_update_info* info) +{ + struct kbase_device* kbdev = kctx->kbdev; + struct pixel_context *pc = kbdev->platform_context; + struct pixel_platform_data *kctx_pd = kctx->platform_data; + s64 current_demand = 0, peak_demand = 0, old_demand; + int i; + + dev_dbg(kbdev->dev, "pixel: buffer liveness update received"); + + for (i = 0; i < info->live_ranges_count; ++i) + { + u64 size; + u32 index = info->live_ranges[i].index; + + if (unlikely(index >= info->buffer_count)) + continue; + + size = info->buffer_sizes[index]; + + switch (info->live_ranges[i].type) + { + case KBASE_PIXEL_GPU_LIVE_RANGE_BEGIN: + /* Update demand as though there's no size limit */ + current_demand += size; + peak_demand = max(peak_demand, current_demand); + break; + case KBASE_PIXEL_GPU_LIVE_RANGE_END: + current_demand -= size; + break; + } + } + + /* Indicates a missing live range end marker */ + WARN_ON_ONCE(current_demand != 0); + + /* Update the demand */ + old_demand = atomic_xchg(&kctx_pd->slc_demand, peak_demand); + atomic_add(peak_demand - old_demand, &pc->slc_demand); +} + /** * gpu_pixel_handle_buffer_liveness_update_ioctl() - See gpu_slc_liveness_update * @@ -61,9 +128,74 @@ static bool transition(int *v, int old, int new) int gpu_pixel_handle_buffer_liveness_update_ioctl(struct kbase_context* kctx, struct kbase_ioctl_buffer_liveness_update* update) { - (void)kctx, (void)update; - return 0; + int err = -EINVAL; + struct gpu_slc_liveness_update_info info; + u64* buff = NULL; + u64 total_buff_size; + + /* Compute the sizes of the user space arrays that we need to copy */ + u64 const buffer_info_size = sizeof(u64) * update->buffer_count; + u64 const live_ranges_size = + sizeof(struct kbase_pixel_gpu_slc_liveness_mark) * update->live_ranges_count; + + /* Guard against overflows and empty sizes */ + if (!buffer_info_size || !live_ranges_size) + goto done; + if (U64_MAX / sizeof(u64) < update->buffer_count) + goto done; + if (U64_MAX / sizeof(struct kbase_pixel_gpu_slc_liveness_mark) < update->live_ranges_count) + goto done; + /* Guard against nullptr */ + if (!update->live_ranges_address || !update->buffer_sizes_address) + goto done; + /* Calculate the total buffer size required and detect overflows */ + if ((U64_MAX - live_ranges_size) < buffer_info_size) + goto done; + + total_buff_size = buffer_info_size + live_ranges_size; + + /* Allocate the memory we require to copy from user space */ + buff = kmalloc(total_buff_size, GFP_KERNEL); + if (buff == NULL) { + dev_err(kctx->kbdev->dev, "pixel: failed to allocate buffer for liveness update"); + err = -ENOMEM; + goto done; + } + + /* Set up the info struct by pointing into the allocation. All 8 byte aligned */ + info = (struct gpu_slc_liveness_update_info){ + .buffer_sizes = buff, + .buffer_count = update->buffer_count, + .live_ranges = (struct kbase_pixel_gpu_slc_liveness_mark*)(buff + update->buffer_count), + .live_ranges_count = update->live_ranges_count, + }; + + /* Copy the data from user space */ + err = copy_from_user( + info.live_ranges, u64_to_user_ptr(update->live_ranges_address), live_ranges_size); + if (err) { + dev_err(kctx->kbdev->dev, "pixel: failed to copy live ranges"); + err = -EFAULT; + goto done; + } + + err = copy_from_user( + info.buffer_sizes, u64_to_user_ptr(update->buffer_sizes_address), buffer_info_size); + if (err) { + dev_err(kctx->kbdev->dev, "pixel: failed to copy buffer sizes"); + err = -EFAULT; + goto done; + } + + /* Execute an slc update */ + gpu_slc_liveness_update(kctx, &info); + +done: + kfree(buff); + + return err; } +#endif /* PIXEL_GPU_SLC_ACPM_SIGNAL */ /** * gpu_slc_kctx_init() - Called when a kernel context is created @@ -93,6 +225,15 @@ void gpu_slc_kctx_term(struct kbase_context *kctx) /* Contexts can be terminated without being idled first */ if (transition(&pd->slc_vote, VOTING, IDLE)) pixel_mgm_slc_dec_refcount(kctx->kbdev->mgm_dev); + +#ifndef PIXEL_GPU_SLC_ACPM_SIGNAL + { + struct pixel_context* pc = kctx->kbdev->platform_context; + /* Deduct the usage and demand, freeing that SLC space for the next update */ + u64 kctx_demand = atomic_xchg(&pd->slc_demand, 0); + atomic_sub(kctx_demand, &pc->slc_demand); + } +#endif /* PIXEL_GPU_SLC_ACPM_SIGNAL */ } /** @@ -132,7 +273,15 @@ void gpu_slc_kctx_idle(struct kbase_context *kctx) */ void gpu_slc_tick_tock(struct kbase_device *kbdev) { +#ifndef PIXEL_GPU_SLC_ACPM_SIGNAL + struct pixel_context* pc = kbdev->platform_context; + /* Threshold of 4MB */ + u64 signal = atomic_read(&pc->slc_demand) / (4 << 20); + + pixel_mgm_slc_update_signal(kbdev->mgm_dev, signal); +#else pixel_mgm_slc_update_signal(kbdev->mgm_dev, 0); +#endif /* PIXEL_GPU_SLC_ACPM_SIGNAL */ } /** -- cgit v1.2.3