Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2a826db0 authored by Harshdeep Dhatt's avatar Harshdeep Dhatt
Browse files

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: default avatarHarshdeep Dhatt <hdhatt@codeaurora.org>
parent 4f3a132f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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

+60 −6
Original line number Diff line number Diff line
@@ -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);
	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];
}
+11 −0
Original line number Diff line number Diff line
@@ -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
+85 −0
Original line number Diff line number Diff line
@@ -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,