Commit 7a1619b97e978bb9c05fa4bbe64171068bd5bf85
Committed by
Dave Airlie
1 parent
471dd2ef37
Exists in
master
and in
6 other branches
drm/radeon: Make sure CS mutex is held across GPU reset.
This was only the case if the GPU reset was triggered from the CS ioctl, otherwise other processes could happily enter the CS ioctl and wreak havoc during the GPU reset. This is a little complicated because the GPU reset can be triggered from the CS ioctl, in which case we're already holding the mutex, or from other call paths, in which case we need to lock the mutex. AFAICT the mutex API doesn't allow recursive locking or finding out the mutex owner, so we need to handle this with helper functions which allow recursive locking from the same process. Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Reviewed-by: Jerome Glisse <jglisse@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Showing 3 changed files with 62 additions and 12 deletions Side-by-side Diff
drivers/gpu/drm/radeon/radeon.h
... | ... | @@ -1142,7 +1142,49 @@ |
1142 | 1142 | u64 gpu_addr; |
1143 | 1143 | }; |
1144 | 1144 | |
1145 | + | |
1145 | 1146 | /* |
1147 | + * Mutex which allows recursive locking from the same process. | |
1148 | + */ | |
1149 | +struct radeon_mutex { | |
1150 | + struct mutex mutex; | |
1151 | + struct task_struct *owner; | |
1152 | + int level; | |
1153 | +}; | |
1154 | + | |
1155 | +static inline void radeon_mutex_init(struct radeon_mutex *mutex) | |
1156 | +{ | |
1157 | + mutex_init(&mutex->mutex); | |
1158 | + mutex->owner = NULL; | |
1159 | + mutex->level = 0; | |
1160 | +} | |
1161 | + | |
1162 | +static inline void radeon_mutex_lock(struct radeon_mutex *mutex) | |
1163 | +{ | |
1164 | + if (mutex_trylock(&mutex->mutex)) { | |
1165 | + /* The mutex was unlocked before, so it's ours now */ | |
1166 | + mutex->owner = current; | |
1167 | + } else if (mutex->owner != current) { | |
1168 | + /* Another process locked the mutex, take it */ | |
1169 | + mutex_lock(&mutex->mutex); | |
1170 | + mutex->owner = current; | |
1171 | + } | |
1172 | + /* Otherwise the mutex was already locked by this process */ | |
1173 | + | |
1174 | + mutex->level++; | |
1175 | +} | |
1176 | + | |
1177 | +static inline void radeon_mutex_unlock(struct radeon_mutex *mutex) | |
1178 | +{ | |
1179 | + if (--mutex->level > 0) | |
1180 | + return; | |
1181 | + | |
1182 | + mutex->owner = NULL; | |
1183 | + mutex_unlock(&mutex->mutex); | |
1184 | +} | |
1185 | + | |
1186 | + | |
1187 | +/* | |
1146 | 1188 | * Core structure, functions and helpers. |
1147 | 1189 | */ |
1148 | 1190 | typedef uint32_t (*radeon_rreg_t)(struct radeon_device*, uint32_t); |
... | ... | @@ -1197,7 +1239,7 @@ |
1197 | 1239 | struct radeon_gem gem; |
1198 | 1240 | struct radeon_pm pm; |
1199 | 1241 | uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; |
1200 | - struct mutex cs_mutex; | |
1242 | + struct radeon_mutex cs_mutex; | |
1201 | 1243 | struct radeon_wb wb; |
1202 | 1244 | struct radeon_dummy_page dummy_page; |
1203 | 1245 | bool gpu_lockup; |
drivers/gpu/drm/radeon/radeon_cs.c
... | ... | @@ -222,7 +222,7 @@ |
222 | 222 | struct radeon_cs_chunk *ib_chunk; |
223 | 223 | int r; |
224 | 224 | |
225 | - mutex_lock(&rdev->cs_mutex); | |
225 | + radeon_mutex_lock(&rdev->cs_mutex); | |
226 | 226 | /* initialize parser */ |
227 | 227 | memset(&parser, 0, sizeof(struct radeon_cs_parser)); |
228 | 228 | parser.filp = filp; |
229 | 229 | |
... | ... | @@ -233,14 +233,14 @@ |
233 | 233 | if (r) { |
234 | 234 | DRM_ERROR("Failed to initialize parser !\n"); |
235 | 235 | radeon_cs_parser_fini(&parser, r); |
236 | - mutex_unlock(&rdev->cs_mutex); | |
236 | + radeon_mutex_unlock(&rdev->cs_mutex); | |
237 | 237 | return r; |
238 | 238 | } |
239 | 239 | r = radeon_ib_get(rdev, &parser.ib); |
240 | 240 | if (r) { |
241 | 241 | DRM_ERROR("Failed to get ib !\n"); |
242 | 242 | radeon_cs_parser_fini(&parser, r); |
243 | - mutex_unlock(&rdev->cs_mutex); | |
243 | + radeon_mutex_unlock(&rdev->cs_mutex); | |
244 | 244 | return r; |
245 | 245 | } |
246 | 246 | r = radeon_cs_parser_relocs(&parser); |
... | ... | @@ -248,7 +248,7 @@ |
248 | 248 | if (r != -ERESTARTSYS) |
249 | 249 | DRM_ERROR("Failed to parse relocation %d!\n", r); |
250 | 250 | radeon_cs_parser_fini(&parser, r); |
251 | - mutex_unlock(&rdev->cs_mutex); | |
251 | + radeon_mutex_unlock(&rdev->cs_mutex); | |
252 | 252 | return r; |
253 | 253 | } |
254 | 254 | /* Copy the packet into the IB, the parser will read from the |
255 | 255 | |
... | ... | @@ -260,14 +260,14 @@ |
260 | 260 | if (r || parser.parser_error) { |
261 | 261 | DRM_ERROR("Invalid command stream !\n"); |
262 | 262 | radeon_cs_parser_fini(&parser, r); |
263 | - mutex_unlock(&rdev->cs_mutex); | |
263 | + radeon_mutex_unlock(&rdev->cs_mutex); | |
264 | 264 | return r; |
265 | 265 | } |
266 | 266 | r = radeon_cs_finish_pages(&parser); |
267 | 267 | if (r) { |
268 | 268 | DRM_ERROR("Invalid command stream !\n"); |
269 | 269 | radeon_cs_parser_fini(&parser, r); |
270 | - mutex_unlock(&rdev->cs_mutex); | |
270 | + radeon_mutex_unlock(&rdev->cs_mutex); | |
271 | 271 | return r; |
272 | 272 | } |
273 | 273 | r = radeon_ib_schedule(rdev, parser.ib); |
... | ... | @@ -275,7 +275,7 @@ |
275 | 275 | DRM_ERROR("Failed to schedule IB !\n"); |
276 | 276 | } |
277 | 277 | radeon_cs_parser_fini(&parser, r); |
278 | - mutex_unlock(&rdev->cs_mutex); | |
278 | + radeon_mutex_unlock(&rdev->cs_mutex); | |
279 | 279 | return r; |
280 | 280 | } |
281 | 281 |
drivers/gpu/drm/radeon/radeon_device.c
... | ... | @@ -716,7 +716,7 @@ |
716 | 716 | |
717 | 717 | /* mutex initialization are all done here so we |
718 | 718 | * can recall function without having locking issues */ |
719 | - mutex_init(&rdev->cs_mutex); | |
719 | + radeon_mutex_init(&rdev->cs_mutex); | |
720 | 720 | mutex_init(&rdev->ib_pool.mutex); |
721 | 721 | mutex_init(&rdev->cp.mutex); |
722 | 722 | mutex_init(&rdev->dc_hw_i2c_mutex); |
... | ... | @@ -955,6 +955,9 @@ |
955 | 955 | int r; |
956 | 956 | int resched; |
957 | 957 | |
958 | + /* Prevent CS ioctl from interfering */ | |
959 | + radeon_mutex_lock(&rdev->cs_mutex); | |
960 | + | |
958 | 961 | radeon_save_bios_scratch_regs(rdev); |
959 | 962 | /* block TTM */ |
960 | 963 | resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); |
961 | 964 | |
... | ... | @@ -967,10 +970,15 @@ |
967 | 970 | radeon_restore_bios_scratch_regs(rdev); |
968 | 971 | drm_helper_resume_force_mode(rdev->ddev); |
969 | 972 | ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); |
970 | - return 0; | |
971 | 973 | } |
972 | - /* bad news, how to tell it to userspace ? */ | |
973 | - dev_info(rdev->dev, "GPU reset failed\n"); | |
974 | + | |
975 | + radeon_mutex_unlock(&rdev->cs_mutex); | |
976 | + | |
977 | + if (r) { | |
978 | + /* bad news, how to tell it to userspace ? */ | |
979 | + dev_info(rdev->dev, "GPU reset failed\n"); | |
980 | + } | |
981 | + | |
974 | 982 | return r; |
975 | 983 | } |
976 | 984 |