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 <hdhatt@codeaurora.org>
This commit is contained in:
Harshdeep Dhatt 2020-09-28 13:00:43 -06:00
commit 2a826db07d
4 changed files with 157 additions and 6 deletions

View file

@ -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

View file

@ -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];
}

View file

@ -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

View file

@ -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,