From 2a826db07d1ee70be9206873b9fc9c76703fdc21 Mon Sep 17 00:00:00 2001 From: Harshdeep Dhatt Date: Mon, 28 Sep 2020 13:00:43 -0600 Subject: [PATCH] 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,