1 /*
2 * Copyright 2017 Valve Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Andres Rodriguez <andresx7@gmail.com>
23 */
24
25 #include <linux/fdtable.h>
26 #include <linux/file.h>
27 #include <linux/pid.h>
28
29 #include <drm/amdgpu_drm.h>
30
31 #include "amdgpu.h"
32 #include "amdgpu_sched.h"
33 #include "amdgpu_vm.h"
34
amdgpu_to_sched_priority(int amdgpu_priority,enum drm_sched_priority * prio)35 int amdgpu_to_sched_priority(int amdgpu_priority,
36 enum drm_sched_priority *prio)
37 {
38 switch (amdgpu_priority) {
39 case AMDGPU_CTX_PRIORITY_VERY_HIGH:
40 *prio = DRM_SCHED_PRIORITY_HIGH;
41 break;
42 case AMDGPU_CTX_PRIORITY_HIGH:
43 *prio = DRM_SCHED_PRIORITY_HIGH;
44 break;
45 case AMDGPU_CTX_PRIORITY_NORMAL:
46 *prio = DRM_SCHED_PRIORITY_NORMAL;
47 break;
48 case AMDGPU_CTX_PRIORITY_LOW:
49 case AMDGPU_CTX_PRIORITY_VERY_LOW:
50 *prio = DRM_SCHED_PRIORITY_MIN;
51 break;
52 case AMDGPU_CTX_PRIORITY_UNSET:
53 *prio = DRM_SCHED_PRIORITY_UNSET;
54 break;
55 default:
56 WARN(1, "Invalid context priority %d\n", amdgpu_priority);
57 return -EINVAL;
58 }
59
60 return 0;
61 }
62
amdgpu_sched_process_priority_override(struct amdgpu_device * adev,int fd,enum drm_sched_priority priority)63 static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev,
64 int fd,
65 enum drm_sched_priority priority)
66 {
67 struct fd f = fdget(fd);
68 struct amdgpu_fpriv *fpriv;
69 struct amdgpu_ctx_mgr *mgr;
70 struct amdgpu_ctx *ctx;
71 uint32_t id;
72 int r;
73
74 if (!f.file)
75 return -EINVAL;
76
77 r = amdgpu_file_to_fpriv(f.file, &fpriv);
78 if (r) {
79 fdput(f);
80 return r;
81 }
82
83 mgr = &fpriv->ctx_mgr;
84 mutex_lock(&mgr->lock);
85 idr_for_each_entry(&mgr->ctx_handles, ctx, id)
86 amdgpu_ctx_priority_override(ctx, priority);
87 mutex_unlock(&mgr->lock);
88
89 fdput(f);
90 return 0;
91 }
92
amdgpu_sched_context_priority_override(struct amdgpu_device * adev,int fd,unsigned ctx_id,enum drm_sched_priority priority)93 static int amdgpu_sched_context_priority_override(struct amdgpu_device *adev,
94 int fd,
95 unsigned ctx_id,
96 enum drm_sched_priority priority)
97 {
98 struct fd f = fdget(fd);
99 struct amdgpu_fpriv *fpriv;
100 struct amdgpu_ctx *ctx;
101 int r;
102
103 if (!f.file)
104 return -EINVAL;
105
106 r = amdgpu_file_to_fpriv(f.file, &fpriv);
107 if (r) {
108 fdput(f);
109 return r;
110 }
111
112 ctx = amdgpu_ctx_get(fpriv, ctx_id);
113
114 if (!ctx) {
115 fdput(f);
116 return -EINVAL;
117 }
118
119 amdgpu_ctx_priority_override(ctx, priority);
120 amdgpu_ctx_put(ctx);
121 fdput(f);
122
123 return 0;
124 }
125
amdgpu_sched_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)126 int amdgpu_sched_ioctl(struct drm_device *dev, void *data,
127 struct drm_file *filp)
128 {
129 union drm_amdgpu_sched *args = data;
130 struct amdgpu_device *adev = drm_to_adev(dev);
131 enum drm_sched_priority priority;
132 int r;
133
134 /* First check the op, then the op's argument.
135 */
136 switch (args->in.op) {
137 case AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE:
138 case AMDGPU_SCHED_OP_CONTEXT_PRIORITY_OVERRIDE:
139 break;
140 default:
141 DRM_ERROR("Invalid sched op specified: %d\n", args->in.op);
142 return -EINVAL;
143 }
144
145 r = amdgpu_to_sched_priority(args->in.priority, &priority);
146 if (r)
147 return r;
148
149 switch (args->in.op) {
150 case AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE:
151 r = amdgpu_sched_process_priority_override(adev,
152 args->in.fd,
153 priority);
154 break;
155 case AMDGPU_SCHED_OP_CONTEXT_PRIORITY_OVERRIDE:
156 r = amdgpu_sched_context_priority_override(adev,
157 args->in.fd,
158 args->in.ctx_id,
159 priority);
160 break;
161 default:
162 /* Impossible.
163 */
164 r = -EINVAL;
165 break;
166 }
167
168 return r;
169 }
170