@@ -261,8 +261,8 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
return ret;
}
return -EINVAL;
- case MSM_PARAM_NR_RINGS:
- *value = gpu->nr_rings;
+ case MSM_PARAM_PRIORITIES:
+ *value = gpu->nr_rings * NR_SCHED_PRIORITIES;
return 0;
case MSM_PARAM_PP_PGTABLE:
*value = 0;
@@ -59,7 +59,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev,
submit->gpu = gpu;
submit->cmd = (void *)&submit->bos[nr_bos];
submit->queue = queue;
- submit->ring = gpu->rb[queue->prio];
+ submit->ring = gpu->rb[queue->ring_nr];
submit->fault_dumped = false;
INIT_LIST_HEAD(&submit->node);
@@ -751,7 +751,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
/* Get a unique identifier for the submission for logging purposes */
submitid = atomic_inc_return(&ident) - 1;
- ring = gpu->rb[queue->prio];
+ ring = gpu->rb[queue->ring_nr];
trace_msm_gpu_submit(pid_nr(pid), ring->id, submitid,
args->nr_bos, args->nr_cmds);
@@ -208,6 +208,22 @@ struct msm_gpu_perfcntr {
const char *name;
};
+/**
+ * With drm/scheduler providing it's own level of prioritization, our total
+ * number of available priority levels is (nr_rings * NR_SCHED_PRIORITIES).
+ * Each ring is associated with it's own scheduler instance. The userspace
+ * provided priority (when a submitqueue is created) is mapped to ring nr
+ * and scheduler priority as such:
+ *
+ * ring_nr = userspace_prio / NR_SCHED_PRIORITIES
+ * sched_prio = userspace_prio % NR_SCHED_PRIORITIES
+ *
+ * This allows generations without preemption (nr_rings==1) to have some
+ * amount of prioritization, and provides more priority levels for gens
+ * that do have preemption.
+ */
+#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_HIGH - DRM_SCHED_PRIORITY_MIN)
+
/**
* A submitqueue is associated with a gl context or vk queue (or equiv)
* in userspace.
@@ -215,7 +231,8 @@ struct msm_gpu_perfcntr {
* @id: userspace id for the submitqueue, unique within the drm_file
* @flags: userspace flags for the submitqueue, specified at creation
* (currently unusued)
- * @prio: the submitqueue priority
+ * @ring_nr: the ringbuffer used by this submitqueue, which is determined
+ * by the submitqueue's priority
* @faults: the number of GPU hangs associated with this submitqueue
* @ctx: the per-drm_file context associated with the submitqueue (ie.
* which set of pgtables do submits jobs associated with the
@@ -230,7 +247,7 @@ struct msm_gpu_perfcntr {
struct msm_gpu_submitqueue {
int id;
u32 flags;
- u32 prio;
+ u32 ring_nr;
int faults;
struct msm_file_private *ctx;
struct list_head node;
@@ -68,6 +68,7 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx,
struct msm_gpu_submitqueue *queue;
struct msm_ringbuffer *ring;
struct drm_gpu_scheduler *sched;
+ u32 sched_prio, ring_nr;
int ret;
if (!ctx)
@@ -76,7 +77,16 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx,
if (!priv->gpu)
return -ENODEV;
- if (prio >= priv->gpu->nr_rings)
+ /*
+ * Map the userspace provided priority to the internal ringbuffer
+ * (queue->prio) and drm/scheduler priority:
+ *
+ * ring_nr = prio / NR_SCHED_PRIORITIES
+ * sched_prio = prio % NR_SCHED_PRIORITIES
+ */
+ ring_nr = div_u64_rem(prio, NR_SCHED_PRIORITIES, &sched_prio);
+
+ if (ring_nr >= priv->gpu->nr_rings)
return -EINVAL;
queue = kzalloc(sizeof(*queue), GFP_KERNEL);
@@ -86,24 +96,13 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx,
kref_init(&queue->ref);
queue->flags = flags;
- queue->prio = prio;
+ queue->ring_nr = ring_nr;
- ring = priv->gpu->rb[prio];
+ ring = priv->gpu->rb[ring_nr];
sched = &ring->sched;
- /*
- * TODO we can allow more priorities than we have ringbuffers by
- * mapping:
- *
- * ring = prio / 3;
- * ent_prio = DRM_SCHED_PRIORITY_MIN + (prio % 3);
- *
- * Probably avoid using DRM_SCHED_PRIORITY_KERNEL as that is
- * treated specially in places.
- */
ret = drm_sched_entity_init(&queue->entity,
- DRM_SCHED_PRIORITY_NORMAL,
- &sched, 1, NULL);
+ sched_prio, &sched, 1, NULL);
if (ret) {
kfree(queue);
return ret;
@@ -73,11 +73,19 @@ struct drm_msm_timespec {
#define MSM_PARAM_MAX_FREQ 0x04
#define MSM_PARAM_TIMESTAMP 0x05
#define MSM_PARAM_GMEM_BASE 0x06
-#define MSM_PARAM_NR_RINGS 0x07
+#define MSM_PARAM_PRIORITIES 0x07 /* The # of priority levels */
#define MSM_PARAM_PP_PGTABLE 0x08 /* => 1 for per-process pagetables, else 0 */
#define MSM_PARAM_FAULTS 0x09
#define MSM_PARAM_SUSPENDS 0x0a
+/* For backwards compat. The original support for preemption was based on
+ * a single ring per priority level so # of priority levels equals the #
+ * of rings. With drm/scheduler providing additional levels of priority,
+ * the number of priorities is greater than the # of rings. The param is
+ * renamed to better reflect this.
+ */
+#define MSM_PARAM_NR_RINGS MSM_PARAM_PRIORITIES
+
struct drm_msm_param {
__u32 pipe; /* in, MSM_PIPE_x */
__u32 param; /* in, MSM_PARAM_x */