From 738e1770d692ebcc300fdb7349df12d40ebf516b Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Fri, 28 Aug 2020 14:32:59 -0600 Subject: [PATCH 1/7] msm: kgsl: Make sure dispatch jobs are not lost due to faults Say a context has only one submission i.e. it has only one dispatch job. And say gpu encounters a fault and sets dispatcher fault. The dispatch job will be free'd and post recovery, the context will never get to the ringbuffer until it queues another submission. This behaviour holds true in cases where dispatcher is halted for example during suspend. So in either case, add back the job the the dispatcher jobs list to make sure the job is not lost. Change-Id: Iec0a0abfbdcf2535d7f82ec1e286581e1c93a3ea Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_dispatch.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index f6c3853e4ca2..9d0c2604d7e4 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -858,8 +858,7 @@ static void dispatcher_handle_jobs_list(struct adreno_device *adreno_dev, llist_for_each_entry_safe(job, next, list, node) { int ret; - if (adreno_gpu_stopped(adreno_dev) || - adreno_drawctxt_bad(job->drawctxt)) { + if (adreno_drawctxt_bad(job->drawctxt)) { kgsl_context_put(&job->drawctxt->base); kmem_cache_free(jobs_cache, job); continue; @@ -879,6 +878,16 @@ static void dispatcher_handle_jobs_list(struct adreno_device *adreno_dev, continue; } + /* + * If gpu is in fault or dispatcher is halted, add back the jobs + * so that they are processed after recovery or when dispatcher + * is resumed. + */ + if (adreno_gpu_stopped(adreno_dev)) { + llist_add(&job->node, &dispatcher->jobs[id]); + continue; + } + ret = dispatcher_context_sendcmds(adreno_dev, job->drawctxt); /* From 640c8e1be7e04d5dc0c5bcbf5c8d6d4b066fd35d Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Tue, 15 Sep 2020 16:40:15 -0600 Subject: [PATCH 2/7] msm: kgsl: Print global memory flags in debugfs With hwscheduling, the flags are requested by GMU outside of kgsl domain. Printing these flags helps to know the flags as requested by GMU. Change-Id: I71d19ead02e115c0a4ead9861de9afd2a0dd2608 Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/kgsl_debugfs.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index 94e7639fbcda..bdffbd47e403 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -72,11 +72,19 @@ static int globals_print(struct seq_file *s, void *unused) list_for_each_entry(md, &device->globals, node) { struct kgsl_memdesc *memdesc = &md->memdesc; + char flags[6]; - seq_printf(s, "0x%pK-0x%pK %16llu %s\n", + flags[0] = memdesc->priv & KGSL_MEMDESC_PRIVILEGED ? 'p' : '-'; + flags[1] = !(memdesc->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 'w' : '-'; + flags[2] = kgsl_memdesc_is_secured(memdesc) ? 's' : '-'; + flags[3] = memdesc->priv & KGSL_MEMDESC_RANDOM ? 'r' : '-'; + flags[4] = memdesc->priv & KGSL_MEMDESC_UCODE ? 'u' : '-'; + flags[5] = '\0'; + + seq_printf(s, "0x%pK-0x%pK %16llu %5s %s\n", (u64 *)(uintptr_t) memdesc->gpuaddr, (u64 *)(uintptr_t) (memdesc->gpuaddr + - memdesc->size - 1), memdesc->size, + memdesc->size - 1), memdesc->size, flags, md->name); } From 83db7b27334475f1547d83f1b385033e26cc31aa Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Fri, 18 Sep 2020 15:46:33 -0600 Subject: [PATCH 3/7] msm: kgsl: Correctly mask out the OOB bits The result of GENMASK needs to be inverted so that the handler doesn't report OOB bits as unknown bits. Change-Id: I3e39334a6dd79343109591b043c9aa30a8bdff9d Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c index e91b2fe93d4a..6e38f0bdecb1 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c @@ -296,7 +296,7 @@ static irqreturn_t a6xx_hwsched_hfi_handler(int irq, void *data) } /* Ignore OOB bits */ - status &= GENMASK(31, 31 - (oob_max - 1)); + status &= GENMASK(31 - (oob_max - 1), 0); if (status & ~hfi->irq_mask) dev_err_ratelimited(&gmu->pdev->dev, From a920566522c8572ddc6d2fb94329726ecf97953c Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Fri, 18 Sep 2020 15:50:58 -0600 Subject: [PATCH 4/7] msm: kgsl: Enable secure buffers via memalloc packets This is to allow GMU to request secure gpu global buffers. Change-Id: Iacef726ee3abe02b56178f475ebe9835649a868c Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c | 3 +++ drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c index 6e38f0bdecb1..d517ffb03b67 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c @@ -545,6 +545,9 @@ static struct mem_alloc_entry *get_mem_alloc_entry( if (!(desc->flags & MEMFLAG_GFX_WRITEABLE)) flags |= KGSL_MEMFLAGS_GPUREADONLY; + if (desc->flags & MEMFLAG_GFX_SECURE) + flags |= KGSL_MEMFLAGS_SECURE; + entry->gpu_md = kgsl_allocate_global(device, desc->size, flags, priv, memkind_string); if (IS_ERR(entry->gpu_md)) { diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h index 5dc4be971baa..7ee95afeee72 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h @@ -104,6 +104,9 @@ enum mem_kind { /* Host initializes the buffer */ #define MEMFLAG_HOST_INIT BIT(9) +/* Gfx buffer needs to be secure */ +#define MEMFLAG_GFX_SECURE BIT(12) + struct mem_alloc_entry { struct hfi_mem_alloc_desc desc; struct kgsl_memdesc *gpu_md; From c7fdd108da84e765fd64bffcd3207a7ae0bcd893 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Thu, 24 Sep 2020 15:35:14 -0600 Subject: [PATCH 5/7] msm: kgsl: Enable preemption for hwscheduling enabled devices Send the HFI feature control packet to the GMU in order to enable preemption. Change-Id: Ic00e3943bceb29feb28740dbadd3fb7c6fdc562b Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_hwsched.c | 15 ++++++++++----- drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c | 9 ++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched.c b/drivers/gpu/msm/adreno_a6xx_hwsched.c index 81d6f8e1a779..185d53386f2c 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched.c @@ -987,18 +987,23 @@ static int a6xx_hwsched_bind(struct device *dev, struct device *master, void *data) { struct kgsl_device *device = dev_get_drvdata(master); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; ret = a6xx_gmu_probe(device, to_platform_device(dev)); if (ret) goto error; - ret = a6xx_hwsched_hfi_probe(ADRENO_DEVICE(device)); + ret = a6xx_hwsched_hfi_probe(adreno_dev); + if (ret) + goto error; - if (!ret) { - set_bit(GMU_DISPATCH, &device->gmu_core.flags); - return 0; - } + set_bit(GMU_DISPATCH, &device->gmu_core.flags); + + if (ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) + set_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); + + return 0; error: a6xx_gmu_remove(device); diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c index d517ffb03b67..a75c4b388161 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c @@ -769,7 +769,14 @@ int a6xx_hwsched_hfi_start(struct adreno_device *adreno_dev) ret = a6xx_hfi_send_feature_ctrl(adreno_dev, HFI_FEATURE_KPROF, 1, 0); if (ret) - return ret; + goto err; + + if (adreno_is_preemption_enabled(adreno_dev)) { + ret = a6xx_hfi_send_feature_ctrl(adreno_dev, + HFI_FEATURE_PREEMPTION, 1, 0); + if (ret) + goto err; + } ret = a6xx_hfi_send_core_fw_start(adreno_dev); if (ret) From 4f3a132f8831b175a2d58141ced3f1d8a0dcee7e Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Wed, 16 Sep 2020 14:44:57 -0600 Subject: [PATCH 6/7] msm: kgsl: Move preemption sysfs nodes to dispatcher This paves the way to hook preemption sysfs nodes to hwscheduling which need to talk to GMU when changing preemption parameters via sysfs. Change-Id: I6940dbf294ad71a18b2dcded207cbacf18ba661d Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_dispatch.c | 117 ++++++++++++++++++++ drivers/gpu/msm/adreno_sysfs.c | 174 ++---------------------------- drivers/gpu/msm/adreno_sysfs.h | 78 ++++++++++++++ 3 files changed, 204 insertions(+), 165 deletions(-) create mode 100644 drivers/gpu/msm/adreno_sysfs.h diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 9d0c2604d7e4..88d4e734f377 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -4,8 +4,10 @@ */ #include +#include #include #include "adreno.h" +#include "adreno_sysfs.h" #include "adreno_trace.h" #include "kgsl_gmu_core.h" #include "kgsl_timeline.h" @@ -2658,6 +2660,116 @@ void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device) del_timer_sync(&dispatcher->fault_timer); } +static int _skipsaverestore_store(struct adreno_device *adreno_dev, bool val) +{ + adreno_dev->preempt.skipsaverestore = val ? true : false; + return 0; +} + +static bool _skipsaverestore_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->preempt.skipsaverestore; +} + +static int _usesgmem_store(struct adreno_device *adreno_dev, bool val) +{ + adreno_dev->preempt.usesgmem = val ? true : false; + return 0; +} + +static bool _usesgmem_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->preempt.usesgmem; +} + +static int _preempt_level_store(struct adreno_device *adreno_dev, + unsigned int val) +{ + adreno_dev->preempt.preempt_level = min_t(unsigned int, val, 2); + return 0; +} + +static unsigned int _preempt_level_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->preempt.preempt_level; +} + +static void change_preemption(struct adreno_device *adreno_dev, void *priv) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_context *context; + struct adreno_context *drawctxt; + struct adreno_ringbuffer *rb; + int id, i, ret; + + /* Make sure all ringbuffers are finished */ + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + ret = adreno_ringbuffer_waittimestamp(rb, rb->timestamp, + 2 * 1000); + if (ret) { + dev_err(device->dev, + "Cannot disable preemption because couldn't idle ringbuffer[%d] ret: %d\n", + rb->id, ret); + return; + } + } + + change_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); + adreno_dev->cur_rb = &adreno_dev->ringbuffers[0]; + adreno_dev->next_rb = NULL; + adreno_dev->prev_rb = NULL; + + /* Update the ringbuffer for each draw context */ + write_lock(&device->context_lock); + idr_for_each_entry(&device->context_idr, context, id) { + drawctxt = ADRENO_CONTEXT(context); + drawctxt->rb = adreno_ctx_get_rb(adreno_dev, drawctxt); + + /* + * Make sure context destroy checks against the correct + * ringbuffer's timestamp. + */ + adreno_rb_readtimestamp(adreno_dev, drawctxt->rb, + KGSL_TIMESTAMP_RETIRED, &drawctxt->internal_timestamp); + } + write_unlock(&device->context_lock); +} + +static int _preemption_store(struct adreno_device *adreno_dev, bool val) +{ + if (!(ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) || + (test_bit(ADRENO_DEVICE_PREEMPTION, + &adreno_dev->priv) == val)) + return 0; + + return adreno_power_cycle(adreno_dev, change_preemption, NULL); +} + +static bool _preemption_show(struct adreno_device *adreno_dev) +{ + return adreno_is_preemption_enabled(adreno_dev); +} + +static unsigned int _preempt_count_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->preempt.count; +} + +static ADRENO_SYSFS_BOOL(preemption); +static ADRENO_SYSFS_U32(preempt_level); +static ADRENO_SYSFS_BOOL(usesgmem); +static ADRENO_SYSFS_BOOL(skipsaverestore); +static ADRENO_SYSFS_RO_U32(preempt_count); + +static const struct attribute *_preempt_attr_list[] = { + &adreno_attr_preemption.attr.attr, + &adreno_attr_preempt_level.attr.attr, + &adreno_attr_usesgmem.attr.attr, + &adreno_attr_skipsaverestore.attr.attr, + &adreno_attr_preempt_count.attr.attr, + NULL, +}; + /** * adreno_dispatcher_close() - close the dispatcher * @adreno_dev: pointer to the adreno device structure @@ -2669,6 +2781,7 @@ void adreno_dispatcher_close(struct adreno_device *adreno_dev) struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; int i; struct adreno_ringbuffer *rb; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); mutex_lock(&dispatcher->mutex); del_timer_sync(&dispatcher->timer); @@ -2690,6 +2803,8 @@ void adreno_dispatcher_close(struct adreno_device *adreno_dev) kobject_put(&dispatcher->kobj); kmem_cache_destroy(jobs_cache); + + sysfs_remove_files(&device->dev->kobj, _preempt_attr_list); } struct dispatcher_attribute { @@ -2839,6 +2954,8 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) if (ret) return ret; + sysfs_create_files(&device->dev->kobj, _preempt_attr_list); + mutex_init(&dispatcher->mutex); timer_setup(&dispatcher->timer, adreno_dispatcher_timer, 0); diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index be8ef6db3d74..b926438c9391 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -6,18 +6,7 @@ #include #include "adreno.h" - -struct adreno_sysfs_attribute_u32 { - struct device_attribute attr; - u32 (*show)(struct adreno_device *adreno_dev); - int (*store)(struct adreno_device *adreno_dev, u32 val); -}; - -struct adreno_sysfs_attribute_bool { - struct device_attribute attr; - bool (*show)(struct adreno_device *adreno_dev); - int (*store)(struct adreno_device *adreno_dev, bool val); -}; +#include "adreno_sysfs.h" static int _ft_policy_store(struct adreno_device *adreno_dev, unsigned int val) @@ -31,47 +20,6 @@ static unsigned int _ft_policy_show(struct adreno_device *adreno_dev) return adreno_dev->ft_policy; } -static int _preempt_level_store(struct adreno_device *adreno_dev, - unsigned int val) -{ - struct adreno_preemption *preempt = &adreno_dev->preempt; - - if (val <= 2) - preempt->preempt_level = val; - return 0; -} - -static unsigned int _preempt_level_show(struct adreno_device *adreno_dev) -{ - return adreno_dev->preempt.preempt_level; -} - -static int _usesgmem_store(struct adreno_device *adreno_dev, bool val) -{ - struct adreno_preemption *preempt = &adreno_dev->preempt; - - preempt->usesgmem = val ? true : false; - return 0; -} - -static bool _usesgmem_show(struct adreno_device *adreno_dev) -{ - return adreno_dev->preempt.usesgmem; -} - -static int _skipsaverestore_store(struct adreno_device *adreno_dev, bool val) -{ - struct adreno_preemption *preempt = &adreno_dev->preempt; - - preempt->skipsaverestore = val ? true : false; - return 0; -} - -static bool _skipsaverestore_show(struct adreno_device *adreno_dev) -{ - return adreno_dev->preempt.skipsaverestore; -} - static int _ft_pagefault_policy_store(struct adreno_device *adreno_dev, unsigned int val) { @@ -139,62 +87,6 @@ static bool _ft_hang_intr_status_show(struct adreno_device *adreno_dev) return true; } -static void change_preemption(struct adreno_device *adreno_dev, void *priv) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_context *context; - struct adreno_context *drawctxt; - struct adreno_ringbuffer *rb; - int id, i, ret; - - /* Make sure all ringbuffers are finished */ - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - ret = adreno_ringbuffer_waittimestamp(rb, rb->timestamp, - 2 * 1000); - if (ret) { - dev_err(device->dev, - "Cannot disable preemption because couldn't idle ringbuffer[%d] ret: %d\n", - rb->id, ret); - return; - } - } - - change_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); - adreno_dev->cur_rb = &adreno_dev->ringbuffers[0]; - adreno_dev->next_rb = NULL; - adreno_dev->prev_rb = NULL; - - /* Update the ringbuffer for each draw context */ - write_lock(&device->context_lock); - idr_for_each_entry(&device->context_idr, context, id) { - drawctxt = ADRENO_CONTEXT(context); - drawctxt->rb = adreno_ctx_get_rb(adreno_dev, drawctxt); - - /* - * Make sure context destroy checks against the correct - * ringbuffer's timestamp. - */ - adreno_rb_readtimestamp(adreno_dev, drawctxt->rb, - KGSL_TIMESTAMP_RETIRED, &drawctxt->internal_timestamp); - } - write_unlock(&device->context_lock); -} - -static int _preemption_store(struct adreno_device *adreno_dev, bool val) -{ - if (!(ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) || - (test_bit(ADRENO_DEVICE_PREEMPTION, - &adreno_dev->priv) == val)) - return 0; - - return adreno_power_cycle(adreno_dev, change_preemption, NULL); -} - -static bool _preemption_show(struct adreno_device *adreno_dev) -{ - return adreno_is_preemption_enabled(adreno_dev); -} - static int _hwcg_store(struct adreno_device *adreno_dev, bool val) { if (adreno_dev->hwcg_enabled == val) @@ -269,13 +161,6 @@ static unsigned int _ifpc_count_show(struct adreno_device *adreno_dev) return adreno_dev->ifpc_count; } -static unsigned int _preempt_count_show(struct adreno_device *adreno_dev) -{ - struct adreno_preemption *preempt = &adreno_dev->preempt; - - return preempt->count; -} - static bool _acd_show(struct adreno_device *adreno_dev) { return adreno_dev->acd_enabled; @@ -301,9 +186,8 @@ static int _bcl_store(struct adreno_device *adreno_dev, bool val) val); } -static ssize_t _sysfs_store_u32(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +ssize_t adreno_sysfs_store_u32(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct adreno_device *adreno_dev = ADRENO_DEVICE(dev_get_drvdata(dev)); struct adreno_sysfs_attribute_u32 *_attr = @@ -322,9 +206,8 @@ static ssize_t _sysfs_store_u32(struct device *dev, return count; } -static ssize_t _sysfs_show_u32(struct device *dev, - struct device_attribute *attr, - char *buf) +ssize_t adreno_sysfs_show_u32(struct device *dev, + struct device_attribute *attr, char *buf) { struct adreno_device *adreno_dev = ADRENO_DEVICE(dev_get_drvdata(dev)); struct adreno_sysfs_attribute_u32 *_attr = @@ -333,9 +216,8 @@ static ssize_t _sysfs_show_u32(struct device *dev, return scnprintf(buf, PAGE_SIZE, "0x%X\n", _attr->show(adreno_dev)); } -static ssize_t _sysfs_store_bool(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +ssize_t adreno_sysfs_store_bool(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { struct adreno_device *adreno_dev = ADRENO_DEVICE(dev_get_drvdata(dev)); struct adreno_sysfs_attribute_bool *_attr = @@ -354,9 +236,8 @@ static ssize_t _sysfs_store_bool(struct device *dev, return count; } -static ssize_t _sysfs_show_bool(struct device *dev, - struct device_attribute *attr, - char *buf) +ssize_t adreno_sysfs_show_bool(struct device *dev, + struct device_attribute *attr, char *buf) { struct adreno_device *adreno_dev = ADRENO_DEVICE(dev_get_drvdata(dev)); struct adreno_sysfs_attribute_bool *_attr = @@ -364,39 +245,8 @@ static ssize_t _sysfs_show_bool(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", _attr->show(adreno_dev)); } - -#define ADRENO_SYSFS_BOOL(_name) \ -struct adreno_sysfs_attribute_bool adreno_attr_##_name = { \ - .attr = __ATTR(_name, 0644, _sysfs_show_bool, _sysfs_store_bool), \ - .show = _ ## _name ## _show, \ - .store = _ ## _name ## _store, \ -} - -#define ADRENO_SYSFS_RO_BOOL(_name) \ -struct adreno_sysfs_attribute_bool adreno_attr_##_name = { \ - .attr = __ATTR(_name, 0444, _sysfs_show_bool, NULL), \ - .show = _ ## _name ## _show, \ -} - -#define ADRENO_SYSFS_U32(_name) \ -struct adreno_sysfs_attribute_u32 adreno_attr_##_name = { \ - .attr = __ATTR(_name, 0644, _sysfs_show_u32, _sysfs_store_u32), \ - .show = _ ## _name ## _show, \ - .store = _ ## _name ## _store, \ -} - -#define ADRENO_SYSFS_RO_U32(_name) \ -struct adreno_sysfs_attribute_u32 adreno_attr_##_name = { \ - .attr = __ATTR(_name, 0444, _sysfs_show_u32, NULL), \ - .show = _ ## _name ## _show, \ -} - static ADRENO_SYSFS_U32(ft_policy); static ADRENO_SYSFS_U32(ft_pagefault_policy); -static ADRENO_SYSFS_U32(preempt_level); -static ADRENO_SYSFS_RO_U32(preempt_count); -static ADRENO_SYSFS_BOOL(usesgmem); -static ADRENO_SYSFS_BOOL(skipsaverestore); static ADRENO_SYSFS_BOOL(ft_long_ib_detect); static ADRENO_SYSFS_RO_BOOL(ft_hang_intr_status); static ADRENO_SYSFS_BOOL(gpu_llc_slice_enable); @@ -407,7 +257,6 @@ static DEVICE_INT_ATTR(wake_timeout, 0644, adreno_wake_timeout); static ADRENO_SYSFS_BOOL(sptp_pc); static ADRENO_SYSFS_BOOL(lm); -static ADRENO_SYSFS_BOOL(preemption); static ADRENO_SYSFS_BOOL(hwcg); static ADRENO_SYSFS_BOOL(throttling); static ADRENO_SYSFS_BOOL(ifpc); @@ -425,17 +274,12 @@ static const struct attribute *_attr_list[] = { &dev_attr_wake_timeout.attr.attr, &adreno_attr_sptp_pc.attr.attr, &adreno_attr_lm.attr.attr, - &adreno_attr_preemption.attr.attr, &adreno_attr_hwcg.attr.attr, &adreno_attr_throttling.attr.attr, &adreno_attr_gpu_llc_slice_enable.attr.attr, &adreno_attr_gpuhtw_llc_slice_enable.attr.attr, - &adreno_attr_preempt_level.attr.attr, - &adreno_attr_usesgmem.attr.attr, - &adreno_attr_skipsaverestore.attr.attr, &adreno_attr_ifpc.attr.attr, &adreno_attr_ifpc_count.attr.attr, - &adreno_attr_preempt_count.attr.attr, &adreno_attr_acd.attr.attr, &adreno_attr_bcl.attr.attr, NULL, diff --git a/drivers/gpu/msm/adreno_sysfs.h b/drivers/gpu/msm/adreno_sysfs.h new file mode 100644 index 000000000000..66212d34dbc8 --- /dev/null +++ b/drivers/gpu/msm/adreno_sysfs.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _ADRENO_SYSFS_H_ +#define _ADRENO_SYSFS_H_ + +/* + * struct adreno_sysfs_attribute_u32 - Container for accessing and modifying + * integers in kgsl via sysfs + */ +struct adreno_sysfs_attribute_u32 { + /** #attr: The device attribute corresponding to the sysfs node */ + struct device_attribute attr; + /** @show: Function to show the value of the integer */ + u32 (*show)(struct adreno_device *adreno_dev); + /** @store: Function to store the value of the integer */ + int (*store)(struct adreno_device *adreno_dev, u32 val); +}; + +/* + * struct adreno_sysfs_attribute_bool - Container for accessing and modifying + * booleans in kgsl via sysfs + */ +struct adreno_sysfs_attribute_bool { + /** #attr: The device attribute corresponding to the sysfs node */ + struct device_attribute attr; + /** @show: Function to show the value of the boolean */ + bool (*show)(struct adreno_device *adreno_dev); + /** @store: Function to store the value of the boolean */ + int (*store)(struct adreno_device *adreno_dev, bool val); +}; + +/* Helper function to modify an integer in kgsl */ +ssize_t adreno_sysfs_store_u32(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +/* Helper function to read an integer in kgsl */ +ssize_t adreno_sysfs_show_u32(struct device *dev, + struct device_attribute *attr, char *buf); + +/* Helper function to modify a boolean in kgsl */ +ssize_t adreno_sysfs_store_bool(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +/* Helper function to read a boolean in kgsl */ +ssize_t adreno_sysfs_show_bool(struct device *dev, + struct device_attribute *attr, char *buf); + +#define ADRENO_SYSFS_BOOL(_name) \ +struct adreno_sysfs_attribute_bool adreno_attr_##_name = { \ + .attr = __ATTR(_name, 0644, adreno_sysfs_show_bool, \ + adreno_sysfs_store_bool), \ + .show = _ ## _name ## _show, \ + .store = _ ## _name ## _store, \ +} + +#define ADRENO_SYSFS_RO_BOOL(_name) \ +struct adreno_sysfs_attribute_bool adreno_attr_##_name = { \ + .attr = __ATTR(_name, 0444, adreno_sysfs_show_bool, NULL), \ + .show = _ ## _name ## _show, \ +} + +#define ADRENO_SYSFS_U32(_name) \ +struct adreno_sysfs_attribute_u32 adreno_attr_##_name = { \ + .attr = __ATTR(_name, 0644, adreno_sysfs_show_u32, \ + adreno_sysfs_store_u32), \ + .show = _ ## _name ## _show, \ + .store = _ ## _name ## _store, \ +} + +#define ADRENO_SYSFS_RO_U32(_name) \ +struct adreno_sysfs_attribute_u32 adreno_attr_##_name = { \ + .attr = __ATTR(_name, 0444, adreno_sysfs_show_u32, NULL), \ + .show = _ ## _name ## _show, \ +} +#endif From 2a826db07d1ee70be9206873b9fc9c76703fdc21 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 28 Sep 2020 13:00:43 -0600 Subject: [PATCH 7/7] msm: kgsl: Hook preemption sysfs nodes to hwscheduling With hwscheduling, we need to communicate the preemption parameters to GMU. Also, we need to use GET_VALUE hfi packet to get the number of preemptions since last SLUMBER exit. Change-Id: I2ab342817a3cea4e1d1797369aa272895730357b Signed-off-by: Harshdeep Dhatt --- drivers/gpu/msm/adreno_a6xx_hfi.h | 1 + drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c | 66 ++++++++++++++++-- drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h | 11 +++ drivers/gpu/msm/adreno_hwsched.c | 85 +++++++++++++++++++++++ 4 files changed, 157 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_hfi.h b/drivers/gpu/msm/adreno_a6xx_hfi.h index f43efe6e1d6c..f487e39dbc95 100644 --- a/drivers/gpu/msm/adreno_a6xx_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hfi.h @@ -78,6 +78,7 @@ #define HFI_VALUE_LOG_EVENT_OFF 113 #define HFI_VALUE_DCVS_OBJ 114 #define HFI_VALUE_LM_CS0 115 +#define HFI_VALUE_PREEMPT_COUNT 120 #define HFI_VALUE_GLOBAL_TOKEN 0xFFFFFFFF diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c index a75c4b388161..2c5dfc0d95ad 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c @@ -733,6 +733,26 @@ static void enable_async_hfi(struct adreno_device *adreno_dev) (u32)~hfi->irq_mask); } +static int enable_preemption(struct adreno_device *adreno_dev) +{ + u32 data; + + if (!adreno_is_preemption_enabled(adreno_dev)) + return 0; + + /* + * Bits [0:1] contains the preemption level + * Bit 2 is to enable/disable gmem save/restore + * Bit 3 is to enable/disable skipsaverestore + */ + data = FIELD_PREP(GENMASK(1, 0), adreno_dev->preempt.preempt_level) | + FIELD_PREP(BIT(2), adreno_dev->preempt.usesgmem) | + FIELD_PREP(BIT(3), adreno_dev->preempt.skipsaverestore); + + return a6xx_hfi_send_feature_ctrl(adreno_dev, HFI_FEATURE_PREEMPTION, 1, + data); +} + int a6xx_hwsched_hfi_start(struct adreno_device *adreno_dev) { struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); @@ -771,12 +791,9 @@ int a6xx_hwsched_hfi_start(struct adreno_device *adreno_dev) if (ret) goto err; - if (adreno_is_preemption_enabled(adreno_dev)) { - ret = a6xx_hfi_send_feature_ctrl(adreno_dev, - HFI_FEATURE_PREEMPTION, 1, 0); - if (ret) - goto err; - } + ret = enable_preemption(adreno_dev); + if (ret) + goto err; ret = a6xx_hfi_send_core_fw_start(adreno_dev); if (ret) @@ -1336,3 +1353,40 @@ void a6xx_hwsched_context_detach(struct adreno_context *drawctxt) mutex_unlock(&device->mutex); } + +int a6xx_hwsched_preempt_count_get(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct hfi_get_value_cmd cmd; + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct a6xx_hwsched_hfi *hfi = to_a6xx_hwsched_hfi(adreno_dev); + u32 seqnum = atomic_inc_return(&gmu->hfi.seqnum); + struct pending_cmd pending_ack; + int rc; + + if (device->state != KGSL_STATE_ACTIVE) + return 0; + + CMD_MSG_HDR(cmd, H2F_MSG_GET_VALUE); + + cmd.hdr = MSG_HDR_SET_SEQNUM(cmd.hdr, seqnum); + cmd.type = HFI_VALUE_PREEMPT_COUNT; + cmd.subtype = 0; + + add_waiter(hfi, cmd.hdr, &pending_ack); + + rc = a6xx_hfi_cmdq_write(adreno_dev, (u32 *)&cmd); + if (rc) + goto done; + + rc = wait_ack_completion(adreno_dev, &pending_ack); + if (rc) + goto done; + + rc = check_ack_failure(adreno_dev, &pending_ack); + +done: + del_waiter(hfi, &pending_ack); + + return rc ? rc : pending_ack.results[2]; +} diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h index 7ee95afeee72..027833709421 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h @@ -217,4 +217,15 @@ void a6xx_hwsched_context_detach(struct adreno_context *drawctxt); /* Helper function to get to a6xx hwsched hfi device from adreno device */ struct a6xx_hwsched_hfi *to_a6xx_hwsched_hfi(struct adreno_device *adreno_dev); + +/** + * a6xx_hwsched_preempt_count_get - Get preemption count from GMU + * @adreno_dev: Pointer to adreno device + * + * This function sends a GET_VALUE HFI packet to get the number of + * preemptions completed since last SLUMBER exit. + * + * Return: Preemption count on success or negative error on failure + */ +int a6xx_hwsched_preempt_count_get(struct adreno_device *adreno_dev); #endif diff --git a/drivers/gpu/msm/adreno_hwsched.c b/drivers/gpu/msm/adreno_hwsched.c index 402fe2a02bec..643acbdf0da3 100644 --- a/drivers/gpu/msm/adreno_hwsched.c +++ b/drivers/gpu/msm/adreno_hwsched.c @@ -7,6 +7,7 @@ #include "adreno_a6xx.h" #include "adreno_a6xx_hwsched.h" #include "adreno_snapshot.h" +#include "adreno_sysfs.h" #include "adreno_trace.h" /* This structure represents inflight command object */ @@ -1006,10 +1007,91 @@ void adreno_hwsched_start(struct adreno_device *adreno_dev) adreno_hwsched_trigger(adreno_dev); } +static int _skipsaverestore_store(struct adreno_device *adreno_dev, bool val) +{ + return adreno_power_cycle_bool(adreno_dev, + &adreno_dev->preempt.skipsaverestore, val); +} + +static bool _skipsaverestore_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->preempt.skipsaverestore; +} + +static int _usesgmem_store(struct adreno_device *adreno_dev, bool val) +{ + return adreno_power_cycle_bool(adreno_dev, + &adreno_dev->preempt.usesgmem, val); +} + +static bool _usesgmem_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->preempt.usesgmem; +} + +static int _preempt_level_store(struct adreno_device *adreno_dev, + unsigned int val) +{ + return adreno_power_cycle_u32(adreno_dev, + &adreno_dev->preempt.preempt_level, + min_t(unsigned int, val, 2)); +} + +static unsigned int _preempt_level_show(struct adreno_device *adreno_dev) +{ + return adreno_dev->preempt.preempt_level; +} + +static void change_preemption(struct adreno_device *adreno_dev, void *priv) +{ + change_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); +} + +static int _preemption_store(struct adreno_device *adreno_dev, bool val) +{ + if (!(ADRENO_FEATURE(adreno_dev, ADRENO_PREEMPTION)) || + (test_bit(ADRENO_DEVICE_PREEMPTION, + &adreno_dev->priv) == val)) + return 0; + + return adreno_power_cycle(adreno_dev, change_preemption, NULL); +} + +static bool _preemption_show(struct adreno_device *adreno_dev) +{ + return adreno_is_preemption_enabled(adreno_dev); +} + +static unsigned int _preempt_count_show(struct adreno_device *adreno_dev) +{ + int count = a6xx_hwsched_preempt_count_get(adreno_dev); + + return count < 0 ? 0 : count; +} + +static ADRENO_SYSFS_BOOL(preemption); +static ADRENO_SYSFS_U32(preempt_level); +static ADRENO_SYSFS_BOOL(usesgmem); +static ADRENO_SYSFS_BOOL(skipsaverestore); +static ADRENO_SYSFS_RO_U32(preempt_count); + +static const struct attribute *_preempt_attr_list[] = { + &adreno_attr_preemption.attr.attr, + &adreno_attr_preempt_level.attr.attr, + &adreno_attr_usesgmem.attr.attr, + &adreno_attr_skipsaverestore.attr.attr, + &adreno_attr_preempt_count.attr.attr, + NULL, +}; + void adreno_hwsched_dispatcher_close(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + kmem_cache_destroy(jobs_cache); kmem_cache_destroy(obj_cache); + + sysfs_remove_files(&device->dev->kobj, _preempt_attr_list); } static void adreno_hwsched_init_replay(struct adreno_hwsched *hwsched) @@ -1231,6 +1313,7 @@ static void adreno_hwsched_work(struct kthread_work *work) void adreno_hwsched_init(struct adreno_device *adreno_dev) { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_hwsched *hwsched = to_hwsched(adreno_dev); int i; @@ -1249,6 +1332,8 @@ void adreno_hwsched_init(struct adreno_device *adreno_dev) init_llist_head(&hwsched->jobs[i]); init_llist_head(&hwsched->requeue[i]); } + + sysfs_create_files(&device->dev->kobj, _preempt_attr_list); } void adreno_hwsched_mark_drawobj(struct adreno_device *adreno_dev,