@@ -441,6 +441,8 @@ int adreno_set_param(struct msm_gpu *gpu, struct msm_file_private *ctx,
if (!capable(CAP_SYS_ADMIN))
return UERR(EPERM, drm, "invalid permissions");
return msm_file_private_set_sysprof(ctx, gpu, value);
+ case MSM_PARAM_REQ_CNTRS:
+ return msm_file_private_request_counters(ctx, gpu, value);
default:
return UERR(EINVAL, drm, "%s: invalid param: %u", gpu->name, param);
}
@@ -377,9 +377,12 @@ static void msm_postclose(struct drm_device *dev, struct drm_file *file)
* It is not possible to set sysprof param to non-zero if gpu
* is not initialized:
*/
- if (priv->gpu)
+ if (ctx->sysprof)
msm_file_private_set_sysprof(ctx, priv->gpu, 0);
+ if (ctx->counters_requested)
+ msm_file_private_request_counters(ctx, priv->gpu, 0);
+
context_close(ctx);
}
@@ -991,6 +991,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
gpu->nr_rings = nr_rings;
refcount_set(&gpu->sysprof_active, 1);
+ refcount_set(&gpu->local_counters_active, 1);
return 0;
@@ -195,12 +195,28 @@ struct msm_gpu {
int nr_rings;
/**
- * sysprof_active:
+ * @sysprof_active:
*
- * The count of contexts that have enabled system profiling.
+ * The count of contexts that have enabled system profiling plus one.
+ *
+ * Note: refcount_t does not like 0->1 transitions.. we want to keep
+ * the under/overflow checks that refcount_t provides, but allow
+ * multiple on/off transitions so we track the logical value plus one.)
*/
refcount_t sysprof_active;
+ /**
+ * @local_counters_active:
+ *
+ * The count of contexts that have requested local (intra-submit)
+ * performance counter usage plus one.
+ *
+ * Note: refcount_t does not like 0->1 transitions.. we want to keep
+ * the under/overflow checks that refcount_t provides, but allow
+ * multiple on/off transitions so we track the logical value plus one.)
+ */
+ refcount_t local_counters_active;
+
/**
* lock:
*
@@ -383,6 +399,13 @@ struct msm_file_private {
*/
int sysprof;
+ /**
+ * @counters_requested:
+ *
+ * Has the context requested local perfcntr usage.
+ */
+ bool counters_requested;
+
/**
* comm: Overridden task comm, see MSM_PARAM_COMM
*
@@ -626,6 +649,8 @@ void msm_submitqueue_destroy(struct kref *kref);
int msm_file_private_set_sysprof(struct msm_file_private *ctx,
struct msm_gpu *gpu, int sysprof);
+int msm_file_private_request_counters(struct msm_file_private *ctx,
+ struct msm_gpu *gpu, int reqcntrs);
void __msm_file_private_destroy(struct kref *kref);
static inline void msm_file_private_put(struct msm_file_private *ctx)
@@ -10,6 +10,15 @@
int msm_file_private_set_sysprof(struct msm_file_private *ctx,
struct msm_gpu *gpu, int sysprof)
{
+ int ret = 0;
+
+ mutex_lock(&gpu->lock);
+
+ if (sysprof && (refcount_read(&gpu->local_counters_active) > 1)) {
+ ret = UERR(EBUSY, gpu->dev, "Local counter usage active");
+ goto out_unlock;
+ }
+
/*
* Since pm_runtime and sysprof_active are both refcounts, we
* call apply the new value first, and then unwind the previous
@@ -18,7 +27,8 @@ int msm_file_private_set_sysprof(struct msm_file_private *ctx,
switch (sysprof) {
default:
- return UERR(EINVAL, gpu->dev, "Invalid sysprof: %d", sysprof);
+ ret = UERR(EINVAL, gpu->dev, "Invalid sysprof: %d", sysprof);
+ goto out_unlock;
case 2:
pm_runtime_get_sync(&gpu->pdev->dev);
fallthrough;
@@ -43,7 +53,45 @@ int msm_file_private_set_sysprof(struct msm_file_private *ctx,
ctx->sysprof = sysprof;
- return 0;
+out_unlock:
+ mutex_unlock(&gpu->lock);
+
+ return ret;
+}
+
+int msm_file_private_request_counters(struct msm_file_private *ctx,
+ struct msm_gpu *gpu, int reqctrs)
+{
+ int ret = 0;
+
+ mutex_lock(&gpu->lock);
+
+ if (reqctrs && (refcount_read(&gpu->sysprof_active) > 1)) {
+ ret = UERR(EBUSY, gpu->dev, "System profiling active");
+ goto out_unlock;
+ }
+
+ if (reqctrs) {
+ if (ctx->counters_requested) {
+ ret = UERR(EINVAL, gpu->dev, "Already requested");
+ goto out_unlock;
+ }
+
+ ctx->counters_requested = true;
+ refcount_inc(&gpu->local_counters_active);
+ } else {
+ if (!ctx->counters_requested) {
+ ret = UERR(EINVAL, gpu->dev, "Not requested");
+ goto out_unlock;
+ }
+ refcount_dec(&gpu->local_counters_active);
+ ctx->counters_requested = false;
+ }
+
+out_unlock:
+ mutex_unlock(&gpu->lock);
+
+ return ret;
}
void __msm_file_private_destroy(struct kref *kref)
@@ -91,6 +91,7 @@ struct drm_msm_timespec {
#define MSM_PARAM_UBWC_SWIZZLE 0x12 /* RO */
#define MSM_PARAM_MACROTILE_MODE 0x13 /* RO */
#define MSM_PARAM_UCHE_TRAP_BASE 0x14 /* RO */
+#define MSM_PARAM_REQ_CNTRS 0x15 /* WO: request "local" (intra-submit) perfcntr usage */
/* For backwards compat. The original support for preemption was based on
* a single ring per priority level so # of priority levels equals the #