Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'drm-misc-next-2018-12-06' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

Final changes to drm-misc-next for v4.21:

UAPI Changes:

Core Changes:
- Add dma_fence_get_stub to dma-buf, and use it in drm/syncobj.
- Add and use DRM_MODESET_LOCK_BEGIN/END helpers.
- Small fixes to drm_atomic_helper_resume(), drm_mode_setcrtc() and
drm_atomic_helper_commit_duplicated_state()
- Fix drm_atomic_state_helper.[c] extraction.

Driver Changes:
- Small fixes to tinydrm, vkms, meson, rcar-du, virtio, vkms,
v3d, and pl111.
- vc4: Allow scaling and YUV formats on cursor planes.
- v3d: Enable use of the Texture Formatting Unit, and fix
prime imports of buffers from other drivers.
- Add support for the AUO G101EVN010 panel.
- sun4i: Enable support for the H6 display engine.

Signed-off-by: Dave Airlie <airlied@redhat.com>
[airlied: added drm/v3d: fix broken build to the merge commit]
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/321be9d3-ab75-5f92-8193-e5113662edef@linux.intel.com

+1163 -517
+12
Documentation/devicetree/bindings/display/panel/auo,g101evn010
··· 1 + AU Optronics Corporation 10.1" (1280x800) color TFT LCD panel 2 + 3 + Required properties: 4 + - compatible: should be "auo,g101evn010" 5 + - power-supply: as specified in the base binding 6 + 7 + Optional properties: 8 + - backlight: as specified in the base binding 9 + - enable-gpios: as specified in the base binding 10 + 11 + This binding is compatible with the simple-panel binding, which is specified 12 + in simple-panel.txt in this directory.
+15
Documentation/gpu/todo.rst
··· 241 241 GEM objects can now have a function table instead of having the callbacks on the 242 242 DRM driver struct. This is now the preferred way and drivers can be moved over. 243 243 244 + Use DRM_MODESET_LOCK_ALL_* helpers instead of boilerplate 245 + --------------------------------------------------------- 246 + 247 + For cases where drivers are attempting to grab the modeset locks with a local 248 + acquire context. Replace the boilerplate code surrounding 249 + drm_modeset_lock_all_ctx() with DRM_MODESET_LOCK_ALL_BEGIN() and 250 + DRM_MODESET_LOCK_ALL_END() instead. 251 + 252 + This should also be done for all places where drm_modest_lock_all() is still 253 + used. 254 + 255 + As a reference, take a look at the conversions already completed in drm core. 256 + 257 + Contact: Sean Paul, respective driver maintainers 258 + 244 259 Core refactorings 245 260 ================= 246 261
+35 -1
drivers/dma-buf/dma-fence.c
··· 30 30 EXPORT_TRACEPOINT_SYMBOL(dma_fence_emit); 31 31 EXPORT_TRACEPOINT_SYMBOL(dma_fence_enable_signal); 32 32 33 + static DEFINE_SPINLOCK(dma_fence_stub_lock); 34 + static struct dma_fence dma_fence_stub; 35 + 33 36 /* 34 37 * fence context counter: each execution context should have its own 35 38 * fence context, this allows checking if fences belong to the same 36 39 * context or not. One device can have multiple separate contexts, 37 40 * and they're used if some engine can run independently of another. 38 41 */ 39 - static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(0); 42 + static atomic64_t dma_fence_context_counter = ATOMIC64_INIT(1); 40 43 41 44 /** 42 45 * DOC: DMA fences overview ··· 70 67 * implicit fences are stored in &struct reservation_object through the 71 68 * &dma_buf.resv pointer. 72 69 */ 70 + 71 + static const char *dma_fence_stub_get_name(struct dma_fence *fence) 72 + { 73 + return "stub"; 74 + } 75 + 76 + static const struct dma_fence_ops dma_fence_stub_ops = { 77 + .get_driver_name = dma_fence_stub_get_name, 78 + .get_timeline_name = dma_fence_stub_get_name, 79 + }; 80 + 81 + /** 82 + * dma_fence_get_stub - return a signaled fence 83 + * 84 + * Return a stub fence which is already signaled. 85 + */ 86 + struct dma_fence *dma_fence_get_stub(void) 87 + { 88 + spin_lock(&dma_fence_stub_lock); 89 + if (!dma_fence_stub.ops) { 90 + dma_fence_init(&dma_fence_stub, 91 + &dma_fence_stub_ops, 92 + &dma_fence_stub_lock, 93 + 0, 0); 94 + dma_fence_signal_locked(&dma_fence_stub); 95 + } 96 + spin_unlock(&dma_fence_stub_lock); 97 + 98 + return dma_fence_get(&dma_fence_stub); 99 + } 100 + EXPORT_SYMBOL(dma_fence_get_stub); 73 101 74 102 /** 75 103 * dma_fence_context_alloc - allocate an array of fence contexts
+1 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
··· 1193 1193 int i; 1194 1194 1195 1195 for (i = 0; i < p->num_post_dep_syncobjs; ++i) 1196 - drm_syncobj_replace_fence(p->post_dep_syncobjs[i], 0, p->fence); 1196 + drm_syncobj_replace_fence(p->post_dep_syncobjs[i], p->fence); 1197 1197 } 1198 1198 1199 1199 static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
+175 -42
drivers/gpu/drm/drm_atomic_helper.c
··· 3131 3131 struct drm_modeset_acquire_ctx ctx; 3132 3132 int ret; 3133 3133 3134 - drm_modeset_acquire_init(&ctx, 0); 3135 - while (1) { 3136 - ret = drm_modeset_lock_all_ctx(dev, &ctx); 3137 - if (!ret) 3138 - ret = __drm_atomic_helper_disable_all(dev, &ctx, true); 3134 + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); 3139 3135 3140 - if (ret != -EDEADLK) 3141 - break; 3142 - 3143 - drm_modeset_backoff(&ctx); 3144 - } 3145 - 3136 + ret = __drm_atomic_helper_disable_all(dev, &ctx, true); 3146 3137 if (ret) 3147 3138 DRM_ERROR("Disabling all crtc's during unload failed with %i\n", ret); 3148 3139 3149 - drm_modeset_drop_locks(&ctx); 3150 - drm_modeset_acquire_fini(&ctx); 3140 + DRM_MODESET_LOCK_ALL_END(ctx, ret); 3151 3141 } 3152 3142 EXPORT_SYMBOL(drm_atomic_helper_shutdown); 3143 + 3144 + /** 3145 + * drm_atomic_helper_duplicate_state - duplicate an atomic state object 3146 + * @dev: DRM device 3147 + * @ctx: lock acquisition context 3148 + * 3149 + * Makes a copy of the current atomic state by looping over all objects and 3150 + * duplicating their respective states. This is used for example by suspend/ 3151 + * resume support code to save the state prior to suspend such that it can 3152 + * be restored upon resume. 3153 + * 3154 + * Note that this treats atomic state as persistent between save and restore. 3155 + * Drivers must make sure that this is possible and won't result in confusion 3156 + * or erroneous behaviour. 3157 + * 3158 + * Note that if callers haven't already acquired all modeset locks this might 3159 + * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). 3160 + * 3161 + * Returns: 3162 + * A pointer to the copy of the atomic state object on success or an 3163 + * ERR_PTR()-encoded error code on failure. 3164 + * 3165 + * See also: 3166 + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() 3167 + */ 3168 + struct drm_atomic_state * 3169 + drm_atomic_helper_duplicate_state(struct drm_device *dev, 3170 + struct drm_modeset_acquire_ctx *ctx) 3171 + { 3172 + struct drm_atomic_state *state; 3173 + struct drm_connector *conn; 3174 + struct drm_connector_list_iter conn_iter; 3175 + struct drm_plane *plane; 3176 + struct drm_crtc *crtc; 3177 + int err = 0; 3178 + 3179 + state = drm_atomic_state_alloc(dev); 3180 + if (!state) 3181 + return ERR_PTR(-ENOMEM); 3182 + 3183 + state->acquire_ctx = ctx; 3184 + 3185 + drm_for_each_crtc(crtc, dev) { 3186 + struct drm_crtc_state *crtc_state; 3187 + 3188 + crtc_state = drm_atomic_get_crtc_state(state, crtc); 3189 + if (IS_ERR(crtc_state)) { 3190 + err = PTR_ERR(crtc_state); 3191 + goto free; 3192 + } 3193 + } 3194 + 3195 + drm_for_each_plane(plane, dev) { 3196 + struct drm_plane_state *plane_state; 3197 + 3198 + plane_state = drm_atomic_get_plane_state(state, plane); 3199 + if (IS_ERR(plane_state)) { 3200 + err = PTR_ERR(plane_state); 3201 + goto free; 3202 + } 3203 + } 3204 + 3205 + drm_connector_list_iter_begin(dev, &conn_iter); 3206 + drm_for_each_connector_iter(conn, &conn_iter) { 3207 + struct drm_connector_state *conn_state; 3208 + 3209 + conn_state = drm_atomic_get_connector_state(state, conn); 3210 + if (IS_ERR(conn_state)) { 3211 + err = PTR_ERR(conn_state); 3212 + drm_connector_list_iter_end(&conn_iter); 3213 + goto free; 3214 + } 3215 + } 3216 + drm_connector_list_iter_end(&conn_iter); 3217 + 3218 + /* clear the acquire context so that it isn't accidentally reused */ 3219 + state->acquire_ctx = NULL; 3220 + 3221 + free: 3222 + if (err < 0) { 3223 + drm_atomic_state_put(state); 3224 + state = ERR_PTR(err); 3225 + } 3226 + 3227 + return state; 3228 + } 3229 + EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); 3153 3230 3154 3231 /** 3155 3232 * drm_atomic_helper_suspend - subsystem-level suspend helper ··· 3259 3182 struct drm_atomic_state *state; 3260 3183 int err; 3261 3184 3262 - drm_modeset_acquire_init(&ctx, 0); 3185 + /* This can never be returned, but it makes the compiler happy */ 3186 + state = ERR_PTR(-EINVAL); 3263 3187 3264 - retry: 3265 - err = drm_modeset_lock_all_ctx(dev, &ctx); 3266 - if (err < 0) { 3267 - state = ERR_PTR(err); 3268 - goto unlock; 3269 - } 3188 + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); 3270 3189 3271 3190 state = drm_atomic_helper_duplicate_state(dev, &ctx); 3272 3191 if (IS_ERR(state)) ··· 3276 3203 } 3277 3204 3278 3205 unlock: 3279 - if (PTR_ERR(state) == -EDEADLK) { 3280 - drm_modeset_backoff(&ctx); 3281 - goto retry; 3282 - } 3206 + DRM_MODESET_LOCK_ALL_END(ctx, err); 3207 + if (err) 3208 + return ERR_PTR(err); 3283 3209 3284 - drm_modeset_drop_locks(&ctx); 3285 - drm_modeset_acquire_fini(&ctx); 3286 3210 return state; 3287 3211 } 3288 3212 EXPORT_SYMBOL(drm_atomic_helper_suspend); ··· 3302 3232 int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, 3303 3233 struct drm_modeset_acquire_ctx *ctx) 3304 3234 { 3305 - int i; 3235 + int i, ret; 3306 3236 struct drm_plane *plane; 3307 3237 struct drm_plane_state *new_plane_state; 3308 3238 struct drm_connector *connector; ··· 3321 3251 for_each_new_connector_in_state(state, connector, new_conn_state, i) 3322 3252 state->connectors[i].old_state = connector->state; 3323 3253 3324 - return drm_atomic_commit(state); 3254 + ret = drm_atomic_commit(state); 3255 + 3256 + state->acquire_ctx = NULL; 3257 + 3258 + return ret; 3325 3259 } 3326 3260 EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state); 3327 3261 ··· 3353 3279 3354 3280 drm_mode_config_reset(dev); 3355 3281 3356 - drm_modeset_acquire_init(&ctx, 0); 3357 - while (1) { 3358 - err = drm_modeset_lock_all_ctx(dev, &ctx); 3359 - if (err) 3360 - goto out; 3282 + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err); 3361 3283 3362 - err = drm_atomic_helper_commit_duplicated_state(state, &ctx); 3363 - out: 3364 - if (err != -EDEADLK) 3365 - break; 3284 + err = drm_atomic_helper_commit_duplicated_state(state, &ctx); 3366 3285 3367 - drm_modeset_backoff(&ctx); 3368 - } 3369 - 3286 + DRM_MODESET_LOCK_ALL_END(ctx, err); 3370 3287 drm_atomic_state_put(state); 3371 - drm_modeset_drop_locks(&ctx); 3372 - drm_modeset_acquire_fini(&ctx); 3373 3288 3374 3289 return err; 3375 3290 } ··· 3497 3434 return ret; 3498 3435 } 3499 3436 EXPORT_SYMBOL(drm_atomic_helper_page_flip_target); 3437 + 3438 + /** 3439 + * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table 3440 + * @crtc: CRTC object 3441 + * @red: red correction table 3442 + * @green: green correction table 3443 + * @blue: green correction table 3444 + * @size: size of the tables 3445 + * @ctx: lock acquire context 3446 + * 3447 + * Implements support for legacy gamma correction table for drivers 3448 + * that support color management through the DEGAMMA_LUT/GAMMA_LUT 3449 + * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for 3450 + * how the atomic color management and gamma tables work. 3451 + */ 3452 + int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, 3453 + u16 *red, u16 *green, u16 *blue, 3454 + uint32_t size, 3455 + struct drm_modeset_acquire_ctx *ctx) 3456 + { 3457 + struct drm_device *dev = crtc->dev; 3458 + struct drm_atomic_state *state; 3459 + struct drm_crtc_state *crtc_state; 3460 + struct drm_property_blob *blob = NULL; 3461 + struct drm_color_lut *blob_data; 3462 + int i, ret = 0; 3463 + bool replaced; 3464 + 3465 + state = drm_atomic_state_alloc(crtc->dev); 3466 + if (!state) 3467 + return -ENOMEM; 3468 + 3469 + blob = drm_property_create_blob(dev, 3470 + sizeof(struct drm_color_lut) * size, 3471 + NULL); 3472 + if (IS_ERR(blob)) { 3473 + ret = PTR_ERR(blob); 3474 + blob = NULL; 3475 + goto fail; 3476 + } 3477 + 3478 + /* Prepare GAMMA_LUT with the legacy values. */ 3479 + blob_data = blob->data; 3480 + for (i = 0; i < size; i++) { 3481 + blob_data[i].red = red[i]; 3482 + blob_data[i].green = green[i]; 3483 + blob_data[i].blue = blue[i]; 3484 + } 3485 + 3486 + state->acquire_ctx = ctx; 3487 + crtc_state = drm_atomic_get_crtc_state(state, crtc); 3488 + if (IS_ERR(crtc_state)) { 3489 + ret = PTR_ERR(crtc_state); 3490 + goto fail; 3491 + } 3492 + 3493 + /* Reset DEGAMMA_LUT and CTM properties. */ 3494 + replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); 3495 + replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); 3496 + replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); 3497 + crtc_state->color_mgmt_changed |= replaced; 3498 + 3499 + ret = drm_atomic_commit(state); 3500 + 3501 + fail: 3502 + drm_atomic_state_put(state); 3503 + drm_property_blob_put(blob); 3504 + return ret; 3505 + } 3506 + EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
-157
drivers/gpu/drm/drm_atomic_state_helper.c
··· 394 394 EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); 395 395 396 396 /** 397 - * drm_atomic_helper_duplicate_state - duplicate an atomic state object 398 - * @dev: DRM device 399 - * @ctx: lock acquisition context 400 - * 401 - * Makes a copy of the current atomic state by looping over all objects and 402 - * duplicating their respective states. This is used for example by suspend/ 403 - * resume support code to save the state prior to suspend such that it can 404 - * be restored upon resume. 405 - * 406 - * Note that this treats atomic state as persistent between save and restore. 407 - * Drivers must make sure that this is possible and won't result in confusion 408 - * or erroneous behaviour. 409 - * 410 - * Note that if callers haven't already acquired all modeset locks this might 411 - * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). 412 - * 413 - * Returns: 414 - * A pointer to the copy of the atomic state object on success or an 415 - * ERR_PTR()-encoded error code on failure. 416 - * 417 - * See also: 418 - * drm_atomic_helper_suspend(), drm_atomic_helper_resume() 419 - */ 420 - struct drm_atomic_state * 421 - drm_atomic_helper_duplicate_state(struct drm_device *dev, 422 - struct drm_modeset_acquire_ctx *ctx) 423 - { 424 - struct drm_atomic_state *state; 425 - struct drm_connector *conn; 426 - struct drm_connector_list_iter conn_iter; 427 - struct drm_plane *plane; 428 - struct drm_crtc *crtc; 429 - int err = 0; 430 - 431 - state = drm_atomic_state_alloc(dev); 432 - if (!state) 433 - return ERR_PTR(-ENOMEM); 434 - 435 - state->acquire_ctx = ctx; 436 - 437 - drm_for_each_crtc(crtc, dev) { 438 - struct drm_crtc_state *crtc_state; 439 - 440 - crtc_state = drm_atomic_get_crtc_state(state, crtc); 441 - if (IS_ERR(crtc_state)) { 442 - err = PTR_ERR(crtc_state); 443 - goto free; 444 - } 445 - } 446 - 447 - drm_for_each_plane(plane, dev) { 448 - struct drm_plane_state *plane_state; 449 - 450 - plane_state = drm_atomic_get_plane_state(state, plane); 451 - if (IS_ERR(plane_state)) { 452 - err = PTR_ERR(plane_state); 453 - goto free; 454 - } 455 - } 456 - 457 - drm_connector_list_iter_begin(dev, &conn_iter); 458 - drm_for_each_connector_iter(conn, &conn_iter) { 459 - struct drm_connector_state *conn_state; 460 - 461 - conn_state = drm_atomic_get_connector_state(state, conn); 462 - if (IS_ERR(conn_state)) { 463 - err = PTR_ERR(conn_state); 464 - drm_connector_list_iter_end(&conn_iter); 465 - goto free; 466 - } 467 - } 468 - drm_connector_list_iter_end(&conn_iter); 469 - 470 - /* clear the acquire context so that it isn't accidentally reused */ 471 - state->acquire_ctx = NULL; 472 - 473 - free: 474 - if (err < 0) { 475 - drm_atomic_state_put(state); 476 - state = ERR_PTR(err); 477 - } 478 - 479 - return state; 480 - } 481 - EXPORT_SYMBOL(drm_atomic_helper_duplicate_state); 482 - 483 - /** 484 397 * __drm_atomic_helper_connector_destroy_state - release connector state 485 398 * @state: connector state object to release 486 399 * ··· 427 514 kfree(state); 428 515 } 429 516 EXPORT_SYMBOL(drm_atomic_helper_connector_destroy_state); 430 - 431 - /** 432 - * drm_atomic_helper_legacy_gamma_set - set the legacy gamma correction table 433 - * @crtc: CRTC object 434 - * @red: red correction table 435 - * @green: green correction table 436 - * @blue: green correction table 437 - * @size: size of the tables 438 - * @ctx: lock acquire context 439 - * 440 - * Implements support for legacy gamma correction table for drivers 441 - * that support color management through the DEGAMMA_LUT/GAMMA_LUT 442 - * properties. See drm_crtc_enable_color_mgmt() and the containing chapter for 443 - * how the atomic color management and gamma tables work. 444 - */ 445 - int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, 446 - u16 *red, u16 *green, u16 *blue, 447 - uint32_t size, 448 - struct drm_modeset_acquire_ctx *ctx) 449 - { 450 - struct drm_device *dev = crtc->dev; 451 - struct drm_atomic_state *state; 452 - struct drm_crtc_state *crtc_state; 453 - struct drm_property_blob *blob = NULL; 454 - struct drm_color_lut *blob_data; 455 - int i, ret = 0; 456 - bool replaced; 457 - 458 - state = drm_atomic_state_alloc(crtc->dev); 459 - if (!state) 460 - return -ENOMEM; 461 - 462 - blob = drm_property_create_blob(dev, 463 - sizeof(struct drm_color_lut) * size, 464 - NULL); 465 - if (IS_ERR(blob)) { 466 - ret = PTR_ERR(blob); 467 - blob = NULL; 468 - goto fail; 469 - } 470 - 471 - /* Prepare GAMMA_LUT with the legacy values. */ 472 - blob_data = blob->data; 473 - for (i = 0; i < size; i++) { 474 - blob_data[i].red = red[i]; 475 - blob_data[i].green = green[i]; 476 - blob_data[i].blue = blue[i]; 477 - } 478 - 479 - state->acquire_ctx = ctx; 480 - crtc_state = drm_atomic_get_crtc_state(state, crtc); 481 - if (IS_ERR(crtc_state)) { 482 - ret = PTR_ERR(crtc_state); 483 - goto fail; 484 - } 485 - 486 - /* Reset DEGAMMA_LUT and CTM properties. */ 487 - replaced = drm_property_replace_blob(&crtc_state->degamma_lut, NULL); 488 - replaced |= drm_property_replace_blob(&crtc_state->ctm, NULL); 489 - replaced |= drm_property_replace_blob(&crtc_state->gamma_lut, blob); 490 - crtc_state->color_mgmt_changed |= replaced; 491 - 492 - ret = drm_atomic_commit(state); 493 - 494 - fail: 495 - drm_atomic_state_put(state); 496 - drm_property_blob_put(blob); 497 - return ret; 498 - } 499 - EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set); 500 517 501 518 /** 502 519 * __drm_atomic_helper_private_duplicate_state - copy atomic private state
+2 -12
drivers/gpu/drm/drm_color_mgmt.c
··· 255 255 if (crtc_lut->gamma_size != crtc->gamma_size) 256 256 return -EINVAL; 257 257 258 - drm_modeset_acquire_init(&ctx, 0); 259 - retry: 260 - ret = drm_modeset_lock_all_ctx(dev, &ctx); 261 - if (ret) 262 - goto out; 258 + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); 263 259 264 260 size = crtc_lut->gamma_size * (sizeof(uint16_t)); 265 261 r_base = crtc->gamma_store; ··· 280 284 crtc->gamma_size, &ctx); 281 285 282 286 out: 283 - if (ret == -EDEADLK) { 284 - drm_modeset_backoff(&ctx); 285 - goto retry; 286 - } 287 - drm_modeset_drop_locks(&ctx); 288 - drm_modeset_acquire_fini(&ctx); 289 - 287 + DRM_MODESET_LOCK_ALL_END(ctx, ret); 290 288 return ret; 291 289 292 290 }
+12 -19
drivers/gpu/drm/drm_crtc.c
··· 572 572 struct drm_mode_crtc *crtc_req = data; 573 573 struct drm_crtc *crtc; 574 574 struct drm_plane *plane; 575 - struct drm_connector **connector_set, *connector; 576 - struct drm_framebuffer *fb; 577 - struct drm_display_mode *mode; 575 + struct drm_connector **connector_set = NULL, *connector; 576 + struct drm_framebuffer *fb = NULL; 577 + struct drm_display_mode *mode = NULL; 578 578 struct drm_mode_set set; 579 579 uint32_t __user *set_connectors_ptr; 580 580 struct drm_modeset_acquire_ctx ctx; ··· 601 601 plane = crtc->primary; 602 602 603 603 mutex_lock(&crtc->dev->mode_config.mutex); 604 - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); 605 - retry: 606 - connector_set = NULL; 607 - fb = NULL; 608 - mode = NULL; 609 - 610 - ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx); 611 - if (ret) 612 - goto out; 604 + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 605 + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); 613 606 614 607 if (crtc_req->mode_valid) { 615 608 /* If we have a mode we need a framebuffer. */ ··· 761 768 } 762 769 kfree(connector_set); 763 770 drm_mode_destroy(dev, mode); 764 - if (ret == -EDEADLK) { 765 - ret = drm_modeset_backoff(&ctx); 766 - if (!ret) 767 - goto retry; 768 - } 769 - drm_modeset_drop_locks(&ctx); 770 - drm_modeset_acquire_fini(&ctx); 771 + 772 + /* In case we need to retry... */ 773 + connector_set = NULL; 774 + fb = NULL; 775 + mode = NULL; 776 + 777 + DRM_MODESET_LOCK_ALL_END(ctx, ret); 771 778 mutex_unlock(&crtc->dev->mode_config.mutex); 772 779 773 780 return ret;
+6
drivers/gpu/drm/drm_modeset_lock.c
··· 56 56 * drm_modeset_drop_locks(ctx); 57 57 * drm_modeset_acquire_fini(ctx); 58 58 * 59 + * For convenience this control flow is implemented in 60 + * DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() for the case 61 + * where all modeset locks need to be taken through drm_modeset_lock_all_ctx(). 62 + * 59 63 * If all that is needed is a single modeset lock, then the &struct 60 64 * drm_modeset_acquire_ctx is not needed and the locking can be simplified 61 65 * by passing a NULL instead of ctx in the drm_modeset_lock() call or ··· 386 382 * 387 383 * Locks acquired with this function should be released by calling the 388 384 * drm_modeset_drop_locks() function on @ctx. 385 + * 386 + * See also: DRM_MODESET_LOCK_ALL_BEGIN() and DRM_MODESET_LOCK_ALL_END() 389 387 * 390 388 * Returns: 0 on success or a negative error-code on failure. 391 389 */
+3 -13
drivers/gpu/drm/drm_plane.c
··· 767 767 struct drm_modeset_acquire_ctx ctx; 768 768 int ret; 769 769 770 - drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); 771 - retry: 772 - ret = drm_modeset_lock_all_ctx(plane->dev, &ctx); 773 - if (ret) 774 - goto fail; 770 + DRM_MODESET_LOCK_ALL_BEGIN(plane->dev, ctx, 771 + DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret); 775 772 776 773 if (drm_drv_uses_atomic_modeset(plane->dev)) 777 774 ret = __setplane_atomic(plane, crtc, fb, ··· 779 782 crtc_x, crtc_y, crtc_w, crtc_h, 780 783 src_x, src_y, src_w, src_h, &ctx); 781 784 782 - fail: 783 - if (ret == -EDEADLK) { 784 - ret = drm_modeset_backoff(&ctx); 785 - if (!ret) 786 - goto retry; 787 - } 788 - drm_modeset_drop_locks(&ctx); 789 - drm_modeset_acquire_fini(&ctx); 785 + DRM_MODESET_LOCK_ALL_END(ctx, ret); 790 786 791 787 return ret; 792 788 }
+19 -51
drivers/gpu/drm/drm_syncobj.c
··· 56 56 #include "drm_internal.h" 57 57 #include <drm/drm_syncobj.h> 58 58 59 - struct drm_syncobj_stub_fence { 60 - struct dma_fence base; 61 - spinlock_t lock; 62 - }; 63 - 64 - static const char *drm_syncobj_stub_fence_get_name(struct dma_fence *fence) 65 - { 66 - return "syncobjstub"; 67 - } 68 - 69 - static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { 70 - .get_driver_name = drm_syncobj_stub_fence_get_name, 71 - .get_timeline_name = drm_syncobj_stub_fence_get_name, 72 - }; 73 - 74 - 75 59 /** 76 60 * drm_syncobj_find - lookup and reference a sync object. 77 61 * @file_private: drm file private pointer ··· 140 156 /** 141 157 * drm_syncobj_replace_fence - replace fence in a sync object. 142 158 * @syncobj: Sync object to replace fence in 143 - * @point: timeline point 144 159 * @fence: fence to install in sync file. 145 160 * 146 - * This replaces the fence on a sync object, or a timeline point fence. 161 + * This replaces the fence on a sync object. 147 162 */ 148 163 void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, 149 - u64 point, 150 164 struct dma_fence *fence) 151 165 { 152 166 struct dma_fence *old_fence; ··· 172 190 } 173 191 EXPORT_SYMBOL(drm_syncobj_replace_fence); 174 192 175 - static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) 193 + /** 194 + * drm_syncobj_assign_null_handle - assign a stub fence to the sync object 195 + * @syncobj: sync object to assign the fence on 196 + * 197 + * Assign a already signaled stub fence to the sync object. 198 + */ 199 + static void drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) 176 200 { 177 - struct drm_syncobj_stub_fence *fence; 178 - fence = kzalloc(sizeof(*fence), GFP_KERNEL); 179 - if (fence == NULL) 180 - return -ENOMEM; 201 + struct dma_fence *fence = dma_fence_get_stub(); 181 202 182 - spin_lock_init(&fence->lock); 183 - dma_fence_init(&fence->base, &drm_syncobj_stub_fence_ops, 184 - &fence->lock, 0, 0); 185 - dma_fence_signal(&fence->base); 186 - 187 - drm_syncobj_replace_fence(syncobj, 0, &fence->base); 188 - 189 - dma_fence_put(&fence->base); 190 - 191 - return 0; 203 + drm_syncobj_replace_fence(syncobj, fence); 204 + dma_fence_put(fence); 192 205 } 193 206 194 207 /** ··· 231 254 struct drm_syncobj *syncobj = container_of(kref, 232 255 struct drm_syncobj, 233 256 refcount); 234 - drm_syncobj_replace_fence(syncobj, 0, NULL); 257 + drm_syncobj_replace_fence(syncobj, NULL); 235 258 kfree(syncobj); 236 259 } 237 260 EXPORT_SYMBOL(drm_syncobj_free); ··· 251 274 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags, 252 275 struct dma_fence *fence) 253 276 { 254 - int ret; 255 277 struct drm_syncobj *syncobj; 256 278 257 279 syncobj = kzalloc(sizeof(struct drm_syncobj), GFP_KERNEL); ··· 261 285 INIT_LIST_HEAD(&syncobj->cb_list); 262 286 spin_lock_init(&syncobj->lock); 263 287 264 - if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) { 265 - ret = drm_syncobj_assign_null_handle(syncobj); 266 - if (ret < 0) { 267 - drm_syncobj_put(syncobj); 268 - return ret; 269 - } 270 - } 288 + if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) 289 + drm_syncobj_assign_null_handle(syncobj); 271 290 272 291 if (fence) 273 - drm_syncobj_replace_fence(syncobj, 0, fence); 292 + drm_syncobj_replace_fence(syncobj, fence); 274 293 275 294 *out_syncobj = syncobj; 276 295 return 0; ··· 450 479 return -ENOENT; 451 480 } 452 481 453 - drm_syncobj_replace_fence(syncobj, 0, fence); 482 + drm_syncobj_replace_fence(syncobj, fence); 454 483 dma_fence_put(fence); 455 484 drm_syncobj_put(syncobj); 456 485 return 0; ··· 921 950 return ret; 922 951 923 952 for (i = 0; i < args->count_handles; i++) 924 - drm_syncobj_replace_fence(syncobjs[i], 0, NULL); 953 + drm_syncobj_replace_fence(syncobjs[i], NULL); 925 954 926 955 drm_syncobj_array_free(syncobjs, args->count_handles); 927 956 ··· 953 982 if (ret < 0) 954 983 return ret; 955 984 956 - for (i = 0; i < args->count_handles; i++) { 957 - ret = drm_syncobj_assign_null_handle(syncobjs[i]); 958 - if (ret < 0) 959 - break; 960 - } 985 + for (i = 0; i < args->count_handles; i++) 986 + drm_syncobj_assign_null_handle(syncobjs[i]); 961 987 962 988 drm_syncobj_array_free(syncobjs, args->count_handles); 963 989
+1 -1
drivers/gpu/drm/i915/i915_gem_execbuffer.c
··· 2191 2191 if (!(flags & I915_EXEC_FENCE_SIGNAL)) 2192 2192 continue; 2193 2193 2194 - drm_syncobj_replace_fence(syncobj, 0, fence); 2194 + drm_syncobj_replace_fence(syncobj, fence); 2195 2195 } 2196 2196 } 2197 2197
+12
drivers/gpu/drm/meson/meson_plane.c
··· 80 80 struct meson_plane { 81 81 struct drm_plane base; 82 82 struct meson_drm *priv; 83 + bool enabled; 83 84 }; 84 85 #define to_meson_plane(x) container_of(x, struct meson_plane, base) 85 86 ··· 305 304 priv->viu.osd1_stride = fb->pitches[0]; 306 305 priv->viu.osd1_height = fb->height; 307 306 307 + if (!meson_plane->enabled) { 308 + /* Reset OSD1 before enabling it on GXL+ SoCs */ 309 + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || 310 + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) 311 + meson_viu_osd1_reset(priv); 312 + 313 + meson_plane->enabled = true; 314 + } 315 + 308 316 spin_unlock_irqrestore(&priv->drm->event_lock, flags); 309 317 } 310 318 ··· 326 316 /* Disable OSD1 */ 327 317 writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, 328 318 priv->io_base + _REG(VPP_MISC)); 319 + 320 + meson_plane->enabled = false; 329 321 330 322 } 331 323
+27
drivers/gpu/drm/meson/meson_viu.c
··· 296 296 true); 297 297 } 298 298 299 + /* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */ 300 + void meson_viu_osd1_reset(struct meson_drm *priv) 301 + { 302 + uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2; 303 + 304 + /* Save these 2 registers state */ 305 + osd1_fifo_ctrl_stat = readl_relaxed( 306 + priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); 307 + osd1_ctrl_stat2 = readl_relaxed( 308 + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 309 + 310 + /* Reset OSD1 */ 311 + writel_bits_relaxed(BIT(0), BIT(0), 312 + priv->io_base + _REG(VIU_SW_RESET)); 313 + writel_bits_relaxed(BIT(0), 0, 314 + priv->io_base + _REG(VIU_SW_RESET)); 315 + 316 + /* Rewrite these registers state lost in the reset */ 317 + writel_relaxed(osd1_fifo_ctrl_stat, 318 + priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); 319 + writel_relaxed(osd1_ctrl_stat2, 320 + priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); 321 + 322 + /* Reload the conversion matrix */ 323 + meson_viu_load_matrix(priv); 324 + } 325 + 299 326 void meson_viu_init(struct meson_drm *priv) 300 327 { 301 328 uint32_t reg;
+1
drivers/gpu/drm/meson/meson_viu.h
··· 59 59 #define OSD_REPLACE_EN BIT(14) 60 60 #define OSD_REPLACE_SHIFT 6 61 61 62 + void meson_viu_osd1_reset(struct meson_drm *priv); 62 63 void meson_viu_init(struct meson_drm *priv); 63 64 64 65 #endif /* __MESON_VIU_H */
+27
drivers/gpu/drm/panel/panel-simple.c
··· 618 618 }, 619 619 }; 620 620 621 + static const struct drm_display_mode auo_g101evn010_mode = { 622 + .clock = 68930, 623 + .hdisplay = 1280, 624 + .hsync_start = 1280 + 82, 625 + .hsync_end = 1280 + 82 + 2, 626 + .htotal = 1280 + 82 + 2 + 84, 627 + .vdisplay = 800, 628 + .vsync_start = 800 + 8, 629 + .vsync_end = 800 + 8 + 2, 630 + .vtotal = 800 + 8 + 2 + 6, 631 + .vrefresh = 60, 632 + }; 633 + 634 + static const struct panel_desc auo_g101evn010 = { 635 + .modes = &auo_g101evn010_mode, 636 + .num_modes = 1, 637 + .bpc = 6, 638 + .size = { 639 + .width = 216, 640 + .height = 135, 641 + }, 642 + .bus_format = MEDIA_BUS_FMT_RGB666_1X18, 643 + }; 644 + 621 645 static const struct drm_display_mode auo_g104sn02_mode = { 622 646 .clock = 40000, 623 647 .hdisplay = 800, ··· 2517 2493 }, { 2518 2494 .compatible = "auo,g070vvn01", 2519 2495 .data = &auo_g070vvn01, 2496 + }, { 2497 + .compatible = "auo,g101evn010", 2498 + .data = &auo_g101evn010, 2520 2499 }, { 2521 2500 .compatible = "auo,g104sn02", 2522 2501 .data = &auo_g104sn02,
+2
drivers/gpu/drm/pl111/pl111_vexpress.c
··· 55 55 } 56 56 } 57 57 58 + of_node_put(root); 59 + 58 60 /* 59 61 * If there is a coretile HDLCD and it has a driver, 60 62 * do not mux the CLCD on the motherboard to the DVI.
+3 -11
drivers/gpu/drm/rcar-du/rcar_du_drv.c
··· 21 21 #include <drm/drm_atomic_helper.h> 22 22 #include <drm/drm_crtc_helper.h> 23 23 #include <drm/drm_fb_cma_helper.h> 24 + #include <drm/drm_fb_helper.h> 24 25 #include <drm/drm_gem_cma_helper.h> 25 26 26 27 #include "rcar_du_drv.h" ··· 393 392 * DRM operations 394 393 */ 395 394 396 - static void rcar_du_lastclose(struct drm_device *dev) 397 - { 398 - struct rcar_du_device *rcdu = dev->dev_private; 399 - 400 - drm_fbdev_cma_restore_mode(rcdu->fbdev); 401 - } 402 - 403 395 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops); 404 396 405 397 static struct drm_driver rcar_du_driver = { 406 398 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME 407 399 | DRIVER_ATOMIC, 408 - .lastclose = rcar_du_lastclose, 409 400 .gem_free_object_unlocked = drm_gem_cma_free_object, 410 401 .gem_vm_ops = &drm_gem_cma_vm_ops, 411 402 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ··· 452 459 struct drm_device *ddev = rcdu->ddev; 453 460 454 461 drm_dev_unregister(ddev); 455 - 456 - if (rcdu->fbdev) 457 - drm_fbdev_cma_fini(rcdu->fbdev); 458 462 459 463 drm_kms_helper_poll_fini(ddev); 460 464 drm_mode_config_cleanup(ddev); ··· 511 521 goto error; 512 522 513 523 DRM_INFO("Device %s probed\n", dev_name(&pdev->dev)); 524 + 525 + drm_fbdev_generic_setup(ddev, 32); 514 526 515 527 return 0; 516 528
-2
drivers/gpu/drm/rcar-du/rcar_du_drv.h
··· 20 20 struct clk; 21 21 struct device; 22 22 struct drm_device; 23 - struct drm_fbdev_cma; 24 23 struct rcar_du_device; 25 24 26 25 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK BIT(0) /* Per-CRTC IRQ and clock */ ··· 77 78 void __iomem *mmio; 78 79 79 80 struct drm_device *ddev; 80 - struct drm_fbdev_cma *fbdev; 81 81 82 82 struct rcar_du_crtc crtcs[RCAR_DU_MAX_CRTCS]; 83 83 unsigned int num_crtcs;
-21
drivers/gpu/drm/rcar-du/rcar_du_kms.c
··· 255 255 return drm_gem_fb_create(dev, file_priv, mode_cmd); 256 256 } 257 257 258 - static void rcar_du_output_poll_changed(struct drm_device *dev) 259 - { 260 - struct rcar_du_device *rcdu = dev->dev_private; 261 - 262 - drm_fbdev_cma_hotplug_event(rcdu->fbdev); 263 - } 264 - 265 258 /* ----------------------------------------------------------------------------- 266 259 * Atomic Check and Update 267 260 */ ··· 301 308 302 309 static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { 303 310 .fb_create = rcar_du_fb_create, 304 - .output_poll_changed = rcar_du_output_poll_changed, 305 311 .atomic_check = rcar_du_atomic_check, 306 312 .atomic_commit = drm_atomic_helper_commit, 307 313 }; ··· 535 543 536 544 struct drm_device *dev = rcdu->ddev; 537 545 struct drm_encoder *encoder; 538 - struct drm_fbdev_cma *fbdev; 539 546 unsigned int dpad0_sources; 540 547 unsigned int num_encoders; 541 548 unsigned int num_groups; ··· 672 681 drm_mode_config_reset(dev); 673 682 674 683 drm_kms_helper_poll_init(dev); 675 - 676 - if (dev->mode_config.num_connector) { 677 - fbdev = drm_fbdev_cma_init(dev, 32, 678 - dev->mode_config.num_connector); 679 - if (IS_ERR(fbdev)) 680 - return PTR_ERR(fbdev); 681 - 682 - rcdu->fbdev = fbdev; 683 - } else { 684 - dev_info(rcdu->dev, 685 - "no connector found, disabling fbdev emulation\n"); 686 - } 687 684 688 685 return 0; 689 686 }
+1
drivers/gpu/drm/sun4i/sun4i_drv.c
··· 410 410 { .compatible = "allwinner,sun8i-v3s-display-engine" }, 411 411 { .compatible = "allwinner,sun9i-a80-display-engine" }, 412 412 { .compatible = "allwinner,sun50i-a64-display-engine" }, 413 + { .compatible = "allwinner,sun50i-h6-display-engine" }, 413 414 { } 414 415 }; 415 416 MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
+1 -2
drivers/gpu/drm/tinydrm/repaper.c
··· 108 108 109 109 /* Stack allocated tx? */ 110 110 if (tx && len <= 32) { 111 - txbuf = kmalloc(len, GFP_KERNEL); 111 + txbuf = kmemdup(tx, len, GFP_KERNEL); 112 112 if (!txbuf) { 113 113 ret = -ENOMEM; 114 114 goto out_free; 115 115 } 116 - memcpy(txbuf, tx, len); 117 116 } 118 117 119 118 if (rx) {
+1
drivers/gpu/drm/v3d/v3d_bo.c
··· 293 293 bo->resv = attach->dmabuf->resv; 294 294 295 295 bo->sgt = sgt; 296 + obj->import_attach = attach; 296 297 v3d_bo_get_pages(bo); 297 298 298 299 v3d_mmu_insert_ptes(bo);
+11 -4
drivers/gpu/drm/v3d/v3d_drv.c
··· 112 112 return 0; 113 113 } 114 114 115 - /* Any params that aren't just register reads would go here. */ 116 115 117 - DRM_DEBUG("Unknown parameter %d\n", args->param); 118 - return -EINVAL; 116 + switch (args->param) { 117 + case DRM_V3D_PARAM_SUPPORTS_TFU: 118 + args->value = 1; 119 + return 0; 120 + default: 121 + DRM_DEBUG("Unknown parameter %d\n", args->param); 122 + return -EINVAL; 123 + } 119 124 } 120 125 121 126 static int ··· 175 170 /* DRM_AUTH is required on SUBMIT_CL for now, while we don't have GMP 176 171 * protection between clients. Note that render nodes would be be 177 172 * able to submit CLs that could access BOs from clients authenticated 178 - * with the master node. 173 + * with the master node. The TFU doesn't use the GMP, so it would 174 + * need to stay DRM_AUTH until we do buffer size/offset validation. 179 175 */ 180 176 static const struct drm_ioctl_desc v3d_drm_ioctls[] = { 181 177 DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CL, v3d_submit_cl_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), ··· 185 179 DRM_IOCTL_DEF_DRV(V3D_MMAP_BO, v3d_mmap_bo_ioctl, DRM_RENDER_ALLOW), 186 180 DRM_IOCTL_DEF_DRV(V3D_GET_PARAM, v3d_get_param_ioctl, DRM_RENDER_ALLOW), 187 181 DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW), 182 + DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH), 188 183 }; 189 184 190 185 static const struct vm_operations_struct v3d_vm_ops = {
+27 -5
drivers/gpu/drm/v3d/v3d_drv.h
··· 7 7 #include <drm/drm_encoder.h> 8 8 #include <drm/drm_gem.h> 9 9 #include <drm/gpu_scheduler.h> 10 + #include "uapi/drm/v3d_drm.h" 10 11 11 12 #define GMP_GRANULARITY (128 * 1024) 12 13 13 - /* Enum for each of the V3D queues. We maintain various queue 14 - * tracking as an array because at some point we'll want to support 15 - * the TFU (texture formatting unit) as another queue. 16 - */ 14 + /* Enum for each of the V3D queues. */ 17 15 enum v3d_queue { 18 16 V3D_BIN, 19 17 V3D_RENDER, 18 + V3D_TFU, 20 19 }; 21 20 22 - #define V3D_MAX_QUEUES (V3D_RENDER + 1) 21 + #define V3D_MAX_QUEUES (V3D_TFU + 1) 23 22 24 23 struct v3d_queue_state { 25 24 struct drm_gpu_scheduler sched; ··· 67 68 68 69 struct v3d_exec_info *bin_job; 69 70 struct v3d_exec_info *render_job; 71 + struct v3d_tfu_job *tfu_job; 70 72 71 73 struct v3d_queue_state queue[V3D_MAX_QUEUES]; 72 74 ··· 218 218 u32 qma, qms, qts; 219 219 }; 220 220 221 + struct v3d_tfu_job { 222 + struct drm_sched_job base; 223 + 224 + struct drm_v3d_submit_tfu args; 225 + 226 + /* An optional fence userspace can pass in for the job to depend on. */ 227 + struct dma_fence *in_fence; 228 + 229 + /* v3d fence to be signaled by IRQ handler when the job is complete. */ 230 + struct dma_fence *done_fence; 231 + 232 + struct v3d_dev *v3d; 233 + 234 + struct kref refcount; 235 + 236 + /* This is the array of BOs that were looked up at the start of exec. */ 237 + struct v3d_bo *bo[4]; 238 + }; 239 + 221 240 /** 222 241 * _wait_for - magic (register) wait macro 223 242 * ··· 300 281 void v3d_gem_destroy(struct drm_device *dev); 301 282 int v3d_submit_cl_ioctl(struct drm_device *dev, void *data, 302 283 struct drm_file *file_priv); 284 + int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, 285 + struct drm_file *file_priv); 303 286 int v3d_wait_bo_ioctl(struct drm_device *dev, void *data, 304 287 struct drm_file *file_priv); 305 288 void v3d_exec_put(struct v3d_exec_info *exec); 289 + void v3d_tfu_job_put(struct v3d_tfu_job *exec); 306 290 void v3d_reset(struct v3d_dev *v3d); 307 291 void v3d_invalidate_caches(struct v3d_dev *v3d); 308 292 void v3d_flush_caches(struct v3d_dev *v3d);
+8 -2
drivers/gpu/drm/v3d/v3d_fence.c
··· 29 29 { 30 30 struct v3d_fence *f = to_v3d_fence(fence); 31 31 32 - if (f->queue == V3D_BIN) 32 + switch (f->queue) { 33 + case V3D_BIN: 33 34 return "v3d-bin"; 34 - else 35 + case V3D_RENDER: 35 36 return "v3d-render"; 37 + case V3D_TFU: 38 + return "v3d-tfu"; 39 + default: 40 + return NULL; 41 + } 36 42 } 37 43 38 44 const struct dma_fence_ops v3d_fence_ops = {
+163 -24
drivers/gpu/drm/v3d/v3d_gem.c
··· 207 207 } 208 208 209 209 static void 210 - v3d_attach_object_fences(struct v3d_exec_info *exec) 210 + v3d_attach_object_fences(struct v3d_bo **bos, int bo_count, 211 + struct dma_fence *fence) 211 212 { 212 - struct dma_fence *out_fence = exec->render_done_fence; 213 213 int i; 214 214 215 - for (i = 0; i < exec->bo_count; i++) { 215 + for (i = 0; i < bo_count; i++) { 216 216 /* XXX: Use shared fences for read-only objects. */ 217 - reservation_object_add_excl_fence(exec->bo[i]->resv, out_fence); 217 + reservation_object_add_excl_fence(bos[i]->resv, fence); 218 218 } 219 219 } 220 220 221 221 static void 222 - v3d_unlock_bo_reservations(struct drm_device *dev, 223 - struct v3d_exec_info *exec, 222 + v3d_unlock_bo_reservations(struct v3d_bo **bos, 223 + int bo_count, 224 224 struct ww_acquire_ctx *acquire_ctx) 225 225 { 226 226 int i; 227 227 228 - for (i = 0; i < exec->bo_count; i++) 229 - ww_mutex_unlock(&exec->bo[i]->resv->lock); 228 + for (i = 0; i < bo_count; i++) 229 + ww_mutex_unlock(&bos[i]->resv->lock); 230 230 231 231 ww_acquire_fini(acquire_ctx); 232 232 } ··· 239 239 * to v3d, so we don't attach dma-buf fences to them. 240 240 */ 241 241 static int 242 - v3d_lock_bo_reservations(struct drm_device *dev, 243 - struct v3d_exec_info *exec, 242 + v3d_lock_bo_reservations(struct v3d_bo **bos, 243 + int bo_count, 244 244 struct ww_acquire_ctx *acquire_ctx) 245 245 { 246 246 int contended_lock = -1; ··· 250 250 251 251 retry: 252 252 if (contended_lock != -1) { 253 - struct v3d_bo *bo = exec->bo[contended_lock]; 253 + struct v3d_bo *bo = bos[contended_lock]; 254 254 255 255 ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock, 256 256 acquire_ctx); ··· 260 260 } 261 261 } 262 262 263 - for (i = 0; i < exec->bo_count; i++) { 263 + for (i = 0; i < bo_count; i++) { 264 264 if (i == contended_lock) 265 265 continue; 266 266 267 - ret = ww_mutex_lock_interruptible(&exec->bo[i]->resv->lock, 267 + ret = ww_mutex_lock_interruptible(&bos[i]->resv->lock, 268 268 acquire_ctx); 269 269 if (ret) { 270 270 int j; 271 271 272 272 for (j = 0; j < i; j++) 273 - ww_mutex_unlock(&exec->bo[j]->resv->lock); 273 + ww_mutex_unlock(&bos[j]->resv->lock); 274 274 275 275 if (contended_lock != -1 && contended_lock >= i) { 276 - struct v3d_bo *bo = exec->bo[contended_lock]; 276 + struct v3d_bo *bo = bos[contended_lock]; 277 277 278 278 ww_mutex_unlock(&bo->resv->lock); 279 279 } ··· 293 293 /* Reserve space for our shared (read-only) fence references, 294 294 * before we commit the CL to the hardware. 295 295 */ 296 - for (i = 0; i < exec->bo_count; i++) { 297 - ret = reservation_object_reserve_shared(exec->bo[i]->resv, 1); 296 + for (i = 0; i < bo_count; i++) { 297 + ret = reservation_object_reserve_shared(bos[i]->resv, 1); 298 298 if (ret) { 299 - v3d_unlock_bo_reservations(dev, exec, acquire_ctx); 299 + v3d_unlock_bo_reservations(bos, bo_count, 300 + acquire_ctx); 300 301 return ret; 301 302 } 302 303 } ··· 420 419 kref_put(&exec->refcount, v3d_exec_cleanup); 421 420 } 422 421 422 + static void 423 + v3d_tfu_job_cleanup(struct kref *ref) 424 + { 425 + struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job, 426 + refcount); 427 + struct v3d_dev *v3d = job->v3d; 428 + unsigned int i; 429 + 430 + dma_fence_put(job->in_fence); 431 + dma_fence_put(job->done_fence); 432 + 433 + for (i = 0; i < ARRAY_SIZE(job->bo); i++) { 434 + if (job->bo[i]) 435 + drm_gem_object_put_unlocked(&job->bo[i]->base); 436 + } 437 + 438 + pm_runtime_mark_last_busy(v3d->dev); 439 + pm_runtime_put_autosuspend(v3d->dev); 440 + 441 + kfree(job); 442 + } 443 + 444 + void v3d_tfu_job_put(struct v3d_tfu_job *job) 445 + { 446 + kref_put(&job->refcount, v3d_tfu_job_cleanup); 447 + } 448 + 423 449 int 424 450 v3d_wait_bo_ioctl(struct drm_device *dev, void *data, 425 451 struct drm_file *file_priv) ··· 521 493 struct drm_syncobj *sync_out; 522 494 int ret = 0; 523 495 496 + trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end); 497 + 524 498 if (args->pad != 0) { 525 499 DRM_INFO("pad must be zero: %d\n", args->pad); 526 500 return -EINVAL; ··· 566 536 if (ret) 567 537 goto fail; 568 538 569 - ret = v3d_lock_bo_reservations(dev, exec, &acquire_ctx); 539 + ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count, 540 + &acquire_ctx); 570 541 if (ret) 571 542 goto fail; 572 543 ··· 601 570 &v3d_priv->sched_entity[V3D_RENDER]); 602 571 mutex_unlock(&v3d->sched_lock); 603 572 604 - v3d_attach_object_fences(exec); 573 + v3d_attach_object_fences(exec->bo, exec->bo_count, 574 + exec->render_done_fence); 605 575 606 - v3d_unlock_bo_reservations(dev, exec, &acquire_ctx); 576 + v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx); 607 577 608 578 /* Update the return sync object for the */ 609 579 sync_out = drm_syncobj_find(file_priv, args->out_sync); 610 580 if (sync_out) { 611 - drm_syncobj_replace_fence(sync_out, 0, 612 - exec->render_done_fence); 581 + drm_syncobj_replace_fence(sync_out, exec->render_done_fence); 613 582 drm_syncobj_put(sync_out); 614 583 } 615 584 ··· 619 588 620 589 fail_unreserve: 621 590 mutex_unlock(&v3d->sched_lock); 622 - v3d_unlock_bo_reservations(dev, exec, &acquire_ctx); 591 + v3d_unlock_bo_reservations(exec->bo, exec->bo_count, &acquire_ctx); 623 592 fail: 624 593 v3d_exec_put(exec); 594 + 595 + return ret; 596 + } 597 + 598 + /** 599 + * v3d_submit_tfu_ioctl() - Submits a TFU (texture formatting) job to the V3D. 600 + * @dev: DRM device 601 + * @data: ioctl argument 602 + * @file_priv: DRM file for this fd 603 + * 604 + * Userspace provides the register setup for the TFU, which we don't 605 + * need to validate since the TFU is behind the MMU. 606 + */ 607 + int 608 + v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, 609 + struct drm_file *file_priv) 610 + { 611 + struct v3d_dev *v3d = to_v3d_dev(dev); 612 + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; 613 + struct drm_v3d_submit_tfu *args = data; 614 + struct v3d_tfu_job *job; 615 + struct ww_acquire_ctx acquire_ctx; 616 + struct drm_syncobj *sync_out; 617 + struct dma_fence *sched_done_fence; 618 + int ret = 0; 619 + int bo_count; 620 + 621 + trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia); 622 + 623 + job = kcalloc(1, sizeof(*job), GFP_KERNEL); 624 + if (!job) 625 + return -ENOMEM; 626 + 627 + ret = pm_runtime_get_sync(v3d->dev); 628 + if (ret < 0) { 629 + kfree(job); 630 + return ret; 631 + } 632 + 633 + kref_init(&job->refcount); 634 + 635 + ret = drm_syncobj_find_fence(file_priv, args->in_sync, 636 + 0, 0, &job->in_fence); 637 + if (ret == -EINVAL) 638 + goto fail; 639 + 640 + job->args = *args; 641 + job->v3d = v3d; 642 + 643 + spin_lock(&file_priv->table_lock); 644 + for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) { 645 + struct drm_gem_object *bo; 646 + 647 + if (!args->bo_handles[bo_count]) 648 + break; 649 + 650 + bo = idr_find(&file_priv->object_idr, 651 + args->bo_handles[bo_count]); 652 + if (!bo) { 653 + DRM_DEBUG("Failed to look up GEM BO %d: %d\n", 654 + bo_count, args->bo_handles[bo_count]); 655 + ret = -ENOENT; 656 + spin_unlock(&file_priv->table_lock); 657 + goto fail; 658 + } 659 + drm_gem_object_get(bo); 660 + job->bo[bo_count] = to_v3d_bo(bo); 661 + } 662 + spin_unlock(&file_priv->table_lock); 663 + 664 + ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx); 665 + if (ret) 666 + goto fail; 667 + 668 + mutex_lock(&v3d->sched_lock); 669 + ret = drm_sched_job_init(&job->base, 670 + &v3d_priv->sched_entity[V3D_TFU], 671 + v3d_priv); 672 + if (ret) 673 + goto fail_unreserve; 674 + 675 + sched_done_fence = dma_fence_get(&job->base.s_fence->finished); 676 + 677 + kref_get(&job->refcount); /* put by scheduler job completion */ 678 + drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]); 679 + mutex_unlock(&v3d->sched_lock); 680 + 681 + v3d_attach_object_fences(job->bo, bo_count, sched_done_fence); 682 + 683 + v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx); 684 + 685 + /* Update the return sync object */ 686 + sync_out = drm_syncobj_find(file_priv, args->out_sync); 687 + if (sync_out) { 688 + drm_syncobj_replace_fence(sync_out, sched_done_fence); 689 + drm_syncobj_put(sync_out); 690 + } 691 + dma_fence_put(sched_done_fence); 692 + 693 + v3d_tfu_job_put(job); 694 + 695 + return 0; 696 + 697 + fail_unreserve: 698 + mutex_unlock(&v3d->sched_lock); 699 + v3d_unlock_bo_reservations(job->bo, bo_count, &acquire_ctx); 700 + fail: 701 + v3d_tfu_job_put(job); 625 702 626 703 return ret; 627 704 }
+24 -5
drivers/gpu/drm/v3d/v3d_irq.c
··· 4 4 /** 5 5 * DOC: Interrupt management for the V3D engine 6 6 * 7 - * When we take a binning or rendering flush done interrupt, we need 8 - * to signal the fence for that job so that the scheduler can queue up 7 + * When we take a bin, render, or TFU done interrupt, we need to 8 + * signal the fence for that job so that the scheduler can queue up 9 9 * the next one and unblock any waiters. 10 10 * 11 11 * When we take the binner out of memory interrupt, we need to ··· 15 15 16 16 #include "v3d_drv.h" 17 17 #include "v3d_regs.h" 18 + #include "v3d_trace.h" 18 19 19 20 #define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \ 20 21 V3D_INT_FLDONE | \ ··· 24 23 25 24 #define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \ 26 25 V3D_HUB_INT_MMU_PTI | \ 27 - V3D_HUB_INT_MMU_CAP)) 26 + V3D_HUB_INT_MMU_CAP | \ 27 + V3D_HUB_INT_TFUC)) 28 28 29 29 static void 30 30 v3d_overflow_mem_work(struct work_struct *work) ··· 89 87 } 90 88 91 89 if (intsts & V3D_INT_FLDONE) { 92 - dma_fence_signal(v3d->bin_job->bin.done_fence); 90 + struct v3d_fence *fence = 91 + to_v3d_fence(v3d->bin_job->bin.done_fence); 92 + 93 + trace_v3d_bcl_irq(&v3d->drm, fence->seqno); 94 + dma_fence_signal(&fence->base); 93 95 status = IRQ_HANDLED; 94 96 } 95 97 96 98 if (intsts & V3D_INT_FRDONE) { 97 - dma_fence_signal(v3d->render_job->render.done_fence); 99 + struct v3d_fence *fence = 100 + to_v3d_fence(v3d->render_job->render.done_fence); 101 + 102 + trace_v3d_rcl_irq(&v3d->drm, fence->seqno); 103 + dma_fence_signal(&fence->base); 98 104 status = IRQ_HANDLED; 99 105 } 100 106 ··· 126 116 127 117 /* Acknowledge the interrupts we're handling here. */ 128 118 V3D_WRITE(V3D_HUB_INT_CLR, intsts); 119 + 120 + if (intsts & V3D_HUB_INT_TFUC) { 121 + struct v3d_fence *fence = 122 + to_v3d_fence(v3d->tfu_job->done_fence); 123 + 124 + trace_v3d_tfu_irq(&v3d->drm, fence->seqno); 125 + dma_fence_signal(&fence->base); 126 + status = IRQ_HANDLED; 127 + } 129 128 130 129 if (intsts & (V3D_HUB_INT_MMU_WRV | 131 130 V3D_HUB_INT_MMU_PTI |
+49
drivers/gpu/drm/v3d/v3d_regs.h
··· 86 86 # define V3D_TOP_GR_BRIDGE_SW_INIT_1 0x0000c 87 87 # define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0) 88 88 89 + #define V3D_TFU_CS 0x00400 90 + /* Stops current job, empties input fifo. */ 91 + # define V3D_TFU_CS_TFURST BIT(31) 92 + # define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16) 93 + # define V3D_TFU_CS_CVTCT_SHIFT 16 94 + # define V3D_TFU_CS_NFREE_MASK V3D_MASK(13, 8) 95 + # define V3D_TFU_CS_NFREE_SHIFT 8 96 + # define V3D_TFU_CS_BUSY BIT(0) 97 + 98 + #define V3D_TFU_SU 0x00404 99 + /* Interrupt when FINTTHR input slots are free (0 = disabled) */ 100 + # define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8) 101 + # define V3D_TFU_SU_FINTTHR_SHIFT 8 102 + /* Skips resetting the CRC at the start of CRC generation. */ 103 + # define V3D_TFU_SU_CRCCHAIN BIT(4) 104 + /* skips writes, computes CRC of the image. miplevels must be 0. */ 105 + # define V3D_TFU_SU_CRC BIT(3) 106 + # define V3D_TFU_SU_THROTTLE_MASK V3D_MASK(1, 0) 107 + # define V3D_TFU_SU_THROTTLE_SHIFT 0 108 + 109 + #define V3D_TFU_ICFG 0x00408 110 + /* Interrupt when the conversion is complete. */ 111 + # define V3D_TFU_ICFG_IOC BIT(0) 112 + 113 + /* Input Image Address */ 114 + #define V3D_TFU_IIA 0x0040c 115 + /* Input Chroma Address */ 116 + #define V3D_TFU_ICA 0x00410 117 + /* Input Image Stride */ 118 + #define V3D_TFU_IIS 0x00414 119 + /* Input Image U-Plane Address */ 120 + #define V3D_TFU_IUA 0x00418 121 + /* Output Image Address */ 122 + #define V3D_TFU_IOA 0x0041c 123 + /* Image Output Size */ 124 + #define V3D_TFU_IOS 0x00420 125 + /* TFU YUV Coefficient 0 */ 126 + #define V3D_TFU_COEF0 0x00424 127 + /* Use these regs instead of the defaults. */ 128 + # define V3D_TFU_COEF0_USECOEF BIT(31) 129 + /* TFU YUV Coefficient 1 */ 130 + #define V3D_TFU_COEF1 0x00428 131 + /* TFU YUV Coefficient 2 */ 132 + #define V3D_TFU_COEF2 0x0042c 133 + /* TFU YUV Coefficient 3 */ 134 + #define V3D_TFU_COEF3 0x00430 135 + 136 + #define V3D_TFU_CRC 0x00434 137 + 89 138 /* Per-MMU registers. */ 90 139 91 140 #define V3D_MMUC_CONTROL 0x01000
+128 -19
drivers/gpu/drm/v3d/v3d_sched.c
··· 30 30 return container_of(sched_job, struct v3d_job, base); 31 31 } 32 32 33 + static struct v3d_tfu_job * 34 + to_tfu_job(struct drm_sched_job *sched_job) 35 + { 36 + return container_of(sched_job, struct v3d_tfu_job, base); 37 + } 38 + 33 39 static void 34 40 v3d_job_free(struct drm_sched_job *sched_job) 35 41 { ··· 44 38 drm_sched_job_cleanup(sched_job); 45 39 46 40 v3d_exec_put(job->exec); 41 + } 42 + 43 + static void 44 + v3d_tfu_job_free(struct drm_sched_job *sched_job) 45 + { 46 + struct v3d_tfu_job *job = to_tfu_job(sched_job); 47 + 48 + drm_sched_job_cleanup(sched_job); 49 + 50 + v3d_tfu_job_put(job); 47 51 } 48 52 49 53 /** ··· 92 76 */ 93 77 94 78 return fence; 79 + } 80 + 81 + /** 82 + * Returns the fences that the TFU job depends on, one by one. 83 + * v3d_tfu_job_run() won't be called until all of them have been 84 + * signaled. 85 + */ 86 + static struct dma_fence * 87 + v3d_tfu_job_dependency(struct drm_sched_job *sched_job, 88 + struct drm_sched_entity *s_entity) 89 + { 90 + struct v3d_tfu_job *job = to_tfu_job(sched_job); 91 + struct dma_fence *fence; 92 + 93 + fence = job->in_fence; 94 + if (fence) { 95 + job->in_fence = NULL; 96 + return fence; 97 + } 98 + 99 + return NULL; 95 100 } 96 101 97 102 static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job) ··· 186 149 return fence; 187 150 } 188 151 189 - static void 190 - v3d_job_timedout(struct drm_sched_job *sched_job) 152 + static struct dma_fence * 153 + v3d_tfu_job_run(struct drm_sched_job *sched_job) 191 154 { 192 - struct v3d_job *job = to_v3d_job(sched_job); 193 - struct v3d_exec_info *exec = job->exec; 194 - struct v3d_dev *v3d = exec->v3d; 195 - enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER; 196 - enum v3d_queue q; 197 - u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q)); 198 - u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q)); 155 + struct v3d_tfu_job *job = to_tfu_job(sched_job); 156 + struct v3d_dev *v3d = job->v3d; 157 + struct drm_device *dev = &v3d->drm; 158 + struct dma_fence *fence; 199 159 200 - /* If the current address or return address have changed, then 201 - * the GPU has probably made progress and we should delay the 202 - * reset. This could fail if the GPU got in an infinite loop 203 - * in the CL, but that is pretty unlikely outside of an i-g-t 204 - * testcase. 205 - */ 206 - if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) { 207 - job->timedout_ctca = ctca; 208 - job->timedout_ctra = ctra; 209 - return; 160 + fence = v3d_fence_create(v3d, V3D_TFU); 161 + if (IS_ERR(fence)) 162 + return NULL; 163 + 164 + v3d->tfu_job = job; 165 + if (job->done_fence) 166 + dma_fence_put(job->done_fence); 167 + job->done_fence = dma_fence_get(fence); 168 + 169 + trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno); 170 + 171 + V3D_WRITE(V3D_TFU_IIA, job->args.iia); 172 + V3D_WRITE(V3D_TFU_IIS, job->args.iis); 173 + V3D_WRITE(V3D_TFU_ICA, job->args.ica); 174 + V3D_WRITE(V3D_TFU_IUA, job->args.iua); 175 + V3D_WRITE(V3D_TFU_IOA, job->args.ioa); 176 + V3D_WRITE(V3D_TFU_IOS, job->args.ios); 177 + V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]); 178 + if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) { 179 + V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]); 180 + V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]); 181 + V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]); 210 182 } 183 + /* ICFG kicks off the job. */ 184 + V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC); 185 + 186 + return fence; 187 + } 188 + 189 + static void 190 + v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) 191 + { 192 + enum v3d_queue q; 211 193 212 194 mutex_lock(&v3d->reset_lock); 213 195 ··· 251 195 mutex_unlock(&v3d->reset_lock); 252 196 } 253 197 198 + static void 199 + v3d_job_timedout(struct drm_sched_job *sched_job) 200 + { 201 + struct v3d_job *job = to_v3d_job(sched_job); 202 + struct v3d_exec_info *exec = job->exec; 203 + struct v3d_dev *v3d = exec->v3d; 204 + enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER; 205 + u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q)); 206 + u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q)); 207 + 208 + /* If the current address or return address have changed, then 209 + * the GPU has probably made progress and we should delay the 210 + * reset. This could fail if the GPU got in an infinite loop 211 + * in the CL, but that is pretty unlikely outside of an i-g-t 212 + * testcase. 213 + */ 214 + if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) { 215 + job->timedout_ctca = ctca; 216 + job->timedout_ctra = ctra; 217 + return; 218 + } 219 + 220 + v3d_gpu_reset_for_timeout(v3d, sched_job); 221 + } 222 + 223 + static void 224 + v3d_tfu_job_timedout(struct drm_sched_job *sched_job) 225 + { 226 + struct v3d_tfu_job *job = to_tfu_job(sched_job); 227 + 228 + v3d_gpu_reset_for_timeout(job->v3d, sched_job); 229 + } 230 + 254 231 static const struct drm_sched_backend_ops v3d_sched_ops = { 255 232 .dependency = v3d_job_dependency, 256 233 .run_job = v3d_job_run, 257 234 .timedout_job = v3d_job_timedout, 258 235 .free_job = v3d_job_free 236 + }; 237 + 238 + static const struct drm_sched_backend_ops v3d_tfu_sched_ops = { 239 + .dependency = v3d_tfu_job_dependency, 240 + .run_job = v3d_tfu_job_run, 241 + .timedout_job = v3d_tfu_job_timedout, 242 + .free_job = v3d_tfu_job_free 259 243 }; 260 244 261 245 int ··· 324 228 if (ret) { 325 229 dev_err(v3d->dev, "Failed to create render scheduler: %d.", 326 230 ret); 231 + drm_sched_fini(&v3d->queue[V3D_BIN].sched); 232 + return ret; 233 + } 234 + 235 + ret = drm_sched_init(&v3d->queue[V3D_TFU].sched, 236 + &v3d_tfu_sched_ops, 237 + hw_jobs_limit, job_hang_limit, 238 + msecs_to_jiffies(hang_limit_ms), 239 + "v3d_tfu"); 240 + if (ret) { 241 + dev_err(v3d->dev, "Failed to create TFU scheduler: %d.", 242 + ret); 243 + drm_sched_fini(&v3d->queue[V3D_RENDER].sched); 327 244 drm_sched_fini(&v3d->queue[V3D_BIN].sched); 328 245 return ret; 329 246 }
+121
drivers/gpu/drm/v3d/v3d_trace.h
··· 12 12 #define TRACE_SYSTEM v3d 13 13 #define TRACE_INCLUDE_FILE v3d_trace 14 14 15 + TRACE_EVENT(v3d_submit_cl_ioctl, 16 + TP_PROTO(struct drm_device *dev, u32 ct1qba, u32 ct1qea), 17 + TP_ARGS(dev, ct1qba, ct1qea), 18 + 19 + TP_STRUCT__entry( 20 + __field(u32, dev) 21 + __field(u32, ct1qba) 22 + __field(u32, ct1qea) 23 + ), 24 + 25 + TP_fast_assign( 26 + __entry->dev = dev->primary->index; 27 + __entry->ct1qba = ct1qba; 28 + __entry->ct1qea = ct1qea; 29 + ), 30 + 31 + TP_printk("dev=%u, RCL 0x%08x..0x%08x", 32 + __entry->dev, 33 + __entry->ct1qba, 34 + __entry->ct1qea) 35 + ); 36 + 15 37 TRACE_EVENT(v3d_submit_cl, 16 38 TP_PROTO(struct drm_device *dev, bool is_render, 17 39 uint64_t seqno, ··· 62 40 __entry->seqno, 63 41 __entry->ctnqba, 64 42 __entry->ctnqea) 43 + ); 44 + 45 + TRACE_EVENT(v3d_bcl_irq, 46 + TP_PROTO(struct drm_device *dev, 47 + uint64_t seqno), 48 + TP_ARGS(dev, seqno), 49 + 50 + TP_STRUCT__entry( 51 + __field(u32, dev) 52 + __field(u64, seqno) 53 + ), 54 + 55 + TP_fast_assign( 56 + __entry->dev = dev->primary->index; 57 + __entry->seqno = seqno; 58 + ), 59 + 60 + TP_printk("dev=%u, seqno=%llu", 61 + __entry->dev, 62 + __entry->seqno) 63 + ); 64 + 65 + TRACE_EVENT(v3d_rcl_irq, 66 + TP_PROTO(struct drm_device *dev, 67 + uint64_t seqno), 68 + TP_ARGS(dev, seqno), 69 + 70 + TP_STRUCT__entry( 71 + __field(u32, dev) 72 + __field(u64, seqno) 73 + ), 74 + 75 + TP_fast_assign( 76 + __entry->dev = dev->primary->index; 77 + __entry->seqno = seqno; 78 + ), 79 + 80 + TP_printk("dev=%u, seqno=%llu", 81 + __entry->dev, 82 + __entry->seqno) 83 + ); 84 + 85 + TRACE_EVENT(v3d_tfu_irq, 86 + TP_PROTO(struct drm_device *dev, 87 + uint64_t seqno), 88 + TP_ARGS(dev, seqno), 89 + 90 + TP_STRUCT__entry( 91 + __field(u32, dev) 92 + __field(u64, seqno) 93 + ), 94 + 95 + TP_fast_assign( 96 + __entry->dev = dev->primary->index; 97 + __entry->seqno = seqno; 98 + ), 99 + 100 + TP_printk("dev=%u, seqno=%llu", 101 + __entry->dev, 102 + __entry->seqno) 103 + ); 104 + 105 + TRACE_EVENT(v3d_submit_tfu_ioctl, 106 + TP_PROTO(struct drm_device *dev, u32 iia), 107 + TP_ARGS(dev, iia), 108 + 109 + TP_STRUCT__entry( 110 + __field(u32, dev) 111 + __field(u32, iia) 112 + ), 113 + 114 + TP_fast_assign( 115 + __entry->dev = dev->primary->index; 116 + __entry->iia = iia; 117 + ), 118 + 119 + TP_printk("dev=%u, IIA 0x%08x", 120 + __entry->dev, 121 + __entry->iia) 122 + ); 123 + 124 + TRACE_EVENT(v3d_submit_tfu, 125 + TP_PROTO(struct drm_device *dev, 126 + uint64_t seqno), 127 + TP_ARGS(dev, seqno), 128 + 129 + TP_STRUCT__entry( 130 + __field(u32, dev) 131 + __field(u64, seqno) 132 + ), 133 + 134 + TP_fast_assign( 135 + __entry->dev = dev->primary->index; 136 + __entry->seqno = seqno; 137 + ), 138 + 139 + TP_printk("dev=%u, seqno=%llu", 140 + __entry->dev, 141 + __entry->seqno) 65 142 ); 66 143 67 144 TRACE_EVENT(v3d_reset_begin,
+6
drivers/gpu/drm/vc4/vc4_drv.h
··· 338 338 u32 pos0_offset; 339 339 u32 pos2_offset; 340 340 u32 ptr0_offset; 341 + u32 lbm_offset; 341 342 342 343 /* Offset where the plane's dlist was last stored in the 343 344 * hardware at vc4_crtc_atomic_flush() time. ··· 370 369 * to enable background color fill. 371 370 */ 372 371 bool needs_bg_fill; 372 + 373 + /* Mark the dlist as initialized. Useful to avoid initializing it twice 374 + * when async update is not possible. 375 + */ 376 + bool dlist_initialized; 373 377 }; 374 378 375 379 static inline struct vc4_plane_state *
+1 -1
drivers/gpu/drm/vc4/vc4_gem.c
··· 681 681 exec->fence = &fence->base; 682 682 683 683 if (out_sync) 684 - drm_syncobj_replace_fence(out_sync, 0, exec->fence); 684 + drm_syncobj_replace_fence(out_sync, exec->fence); 685 685 686 686 vc4_update_bo_seqnos(exec, seqno); 687 687
+142 -81
drivers/gpu/drm/vc4/vc4_plane.c
··· 154 154 return NULL; 155 155 156 156 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); 157 + vc4_state->dlist_initialized = 0; 157 158 158 159 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); 159 160 ··· 260 259 261 260 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) 262 261 { 263 - struct drm_plane *plane = state->plane; 264 262 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 265 263 struct drm_framebuffer *fb = state->fb; 266 264 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); 267 265 u32 subpixel_src_mask = (1 << 16) - 1; 268 266 u32 format = fb->format->format; 269 267 int num_planes = fb->format->num_planes; 270 - int min_scale = 1, max_scale = INT_MAX; 271 268 struct drm_crtc_state *crtc_state; 272 269 u32 h_subsample, v_subsample; 273 270 int i, ret; ··· 277 278 return -EINVAL; 278 279 } 279 280 280 - /* No configuring scaling on the cursor plane, since it gets 281 - * non-vblank-synced updates, and scaling requires LBM changes which 282 - * have to be vblank-synced. 283 - */ 284 - if (plane->type == DRM_PLANE_TYPE_CURSOR) { 285 - min_scale = DRM_PLANE_HELPER_NO_SCALING; 286 - max_scale = DRM_PLANE_HELPER_NO_SCALING; 287 - } else { 288 - min_scale = 1; 289 - max_scale = INT_MAX; 290 - } 291 - 292 - ret = drm_atomic_helper_check_plane_state(state, crtc_state, 293 - min_scale, max_scale, 294 - true, true); 281 + ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1, 282 + INT_MAX, true, true); 295 283 if (ret) 296 284 return ret; 297 285 ··· 381 395 u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w); 382 396 u32 lbm; 383 397 398 + /* LBM is not needed when there's no vertical scaling. */ 399 + if (vc4_state->y_scaling[0] == VC4_SCALING_NONE && 400 + vc4_state->y_scaling[1] == VC4_SCALING_NONE) 401 + return 0; 402 + 384 403 if (!vc4_state->is_yuv) { 385 - if (vc4_state->is_unity) 386 - return 0; 387 - else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) 404 + if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) 388 405 lbm = pix_per_line * 8; 389 406 else { 390 407 /* In special cases, this multiplier might be 12. */ ··· 438 449 } 439 450 } 440 451 452 + static int vc4_plane_allocate_lbm(struct drm_plane_state *state) 453 + { 454 + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); 455 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 456 + unsigned long irqflags; 457 + u32 lbm_size; 458 + 459 + lbm_size = vc4_lbm_size(state); 460 + if (!lbm_size) 461 + return 0; 462 + 463 + if (WARN_ON(!vc4_state->lbm_offset)) 464 + return -EINVAL; 465 + 466 + /* Allocate the LBM memory that the HVS will use for temporary 467 + * storage due to our scaling/format conversion. 468 + */ 469 + if (!vc4_state->lbm.allocated) { 470 + int ret; 471 + 472 + spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 473 + ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, 474 + &vc4_state->lbm, 475 + lbm_size, 32, 0, 0); 476 + spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 477 + 478 + if (ret) 479 + return ret; 480 + } else { 481 + WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); 482 + } 483 + 484 + vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; 485 + 486 + return 0; 487 + } 488 + 441 489 /* Writes out a full display list for an active plane to the plane's 442 490 * private dlist state. 443 491 */ ··· 492 466 bool mix_plane_alpha; 493 467 bool covers_screen; 494 468 u32 scl0, scl1, pitch0; 495 - u32 lbm_size, tiling; 496 - unsigned long irqflags; 469 + u32 tiling; 497 470 u32 hvs_format = format->hvs; 498 471 int ret, i; 499 472 473 + if (vc4_state->dlist_initialized) 474 + return 0; 475 + 500 476 ret = vc4_plane_setup_clipping_and_scaling(state); 501 - if (ret) 502 - return ret; 503 - 504 - /* Allocate the LBM memory that the HVS will use for temporary 505 - * storage due to our scaling/format conversion. 506 - */ 507 - lbm_size = vc4_lbm_size(state); 508 - if (lbm_size) { 509 - if (!vc4_state->lbm.allocated) { 510 - spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 511 - ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, 512 - &vc4_state->lbm, 513 - lbm_size, 32, 0, 0); 514 - spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 515 - } else { 516 - WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); 517 - } 518 - } 519 - 520 477 if (ret) 521 478 return ret; 522 479 ··· 723 714 vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); 724 715 } 725 716 717 + vc4_state->lbm_offset = 0; 718 + 726 719 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || 727 720 vc4_state->x_scaling[1] != VC4_SCALING_NONE || 728 721 vc4_state->y_scaling[0] != VC4_SCALING_NONE || 729 722 vc4_state->y_scaling[1] != VC4_SCALING_NONE) { 730 - /* LBM Base Address. */ 723 + /* Reserve a slot for the LBM Base Address. The real value will 724 + * be set when calling vc4_plane_allocate_lbm(). 725 + */ 731 726 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || 732 - vc4_state->y_scaling[1] != VC4_SCALING_NONE) { 733 - vc4_dlist_write(vc4_state, vc4_state->lbm.start); 734 - } 727 + vc4_state->y_scaling[1] != VC4_SCALING_NONE) 728 + vc4_state->lbm_offset = vc4_state->dlist_count++; 735 729 736 730 if (num_planes > 1) { 737 731 /* Emit Cb/Cr as channel 0 and Y as channel ··· 780 768 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen || 781 769 state->alpha != DRM_BLEND_ALPHA_OPAQUE; 782 770 771 + /* Flag the dlist as initialized to avoid checking it twice in case 772 + * the async update check already called vc4_plane_mode_set() and 773 + * decided to fallback to sync update because async update was not 774 + * possible. 775 + */ 776 + vc4_state->dlist_initialized = 1; 777 + 783 778 return 0; 784 779 } 785 780 ··· 801 782 struct drm_plane_state *state) 802 783 { 803 784 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 785 + int ret; 804 786 805 787 vc4_state->dlist_count = 0; 806 788 807 - if (plane_enabled(state)) 808 - return vc4_plane_mode_set(plane, state); 809 - else 789 + if (!plane_enabled(state)) 810 790 return 0; 791 + 792 + ret = vc4_plane_mode_set(plane, state); 793 + if (ret) 794 + return ret; 795 + 796 + return vc4_plane_allocate_lbm(state); 811 797 } 812 798 813 799 static void vc4_plane_atomic_update(struct drm_plane *plane, ··· 880 856 { 881 857 struct vc4_plane_state *vc4_state, *new_vc4_state; 882 858 883 - if (plane->state->fb != state->fb) { 884 - vc4_plane_async_set_fb(plane, state->fb); 885 - drm_atomic_set_fb_for_plane(plane->state, state->fb); 886 - } 887 - 888 - /* Set the cursor's position on the screen. This is the 889 - * expected change from the drm_mode_cursor_universal() 890 - * helper. 891 - */ 859 + drm_atomic_set_fb_for_plane(plane->state, state->fb); 892 860 plane->state->crtc_x = state->crtc_x; 893 861 plane->state->crtc_y = state->crtc_y; 894 - 895 - /* Allow changing the start position within the cursor BO, if 896 - * that matters. 897 - */ 862 + plane->state->crtc_w = state->crtc_w; 863 + plane->state->crtc_h = state->crtc_h; 898 864 plane->state->src_x = state->src_x; 899 865 plane->state->src_y = state->src_y; 900 - 901 - /* Update the display list based on the new crtc_x/y. */ 902 - vc4_plane_atomic_check(plane, state); 866 + plane->state->src_w = state->src_w; 867 + plane->state->src_h = state->src_h; 868 + plane->state->src_h = state->src_h; 869 + plane->state->alpha = state->alpha; 870 + plane->state->pixel_blend_mode = state->pixel_blend_mode; 871 + plane->state->rotation = state->rotation; 872 + plane->state->zpos = state->zpos; 873 + plane->state->normalized_zpos = state->normalized_zpos; 874 + plane->state->color_encoding = state->color_encoding; 875 + plane->state->color_range = state->color_range; 876 + plane->state->src = state->src; 877 + plane->state->dst = state->dst; 878 + plane->state->visible = state->visible; 903 879 904 880 new_vc4_state = to_vc4_plane_state(state); 905 881 vc4_state = to_vc4_plane_state(plane->state); 882 + 883 + vc4_state->crtc_x = new_vc4_state->crtc_x; 884 + vc4_state->crtc_y = new_vc4_state->crtc_y; 885 + vc4_state->crtc_h = new_vc4_state->crtc_h; 886 + vc4_state->crtc_w = new_vc4_state->crtc_w; 887 + vc4_state->src_x = new_vc4_state->src_x; 888 + vc4_state->src_y = new_vc4_state->src_y; 889 + memcpy(vc4_state->src_w, new_vc4_state->src_w, 890 + sizeof(vc4_state->src_w)); 891 + memcpy(vc4_state->src_h, new_vc4_state->src_h, 892 + sizeof(vc4_state->src_h)); 893 + memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling, 894 + sizeof(vc4_state->x_scaling)); 895 + memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling, 896 + sizeof(vc4_state->y_scaling)); 897 + vc4_state->is_unity = new_vc4_state->is_unity; 898 + vc4_state->is_yuv = new_vc4_state->is_yuv; 899 + memcpy(vc4_state->offsets, new_vc4_state->offsets, 900 + sizeof(vc4_state->offsets)); 901 + vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill; 906 902 907 903 /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ 908 904 vc4_state->dlist[vc4_state->pos0_offset] = ··· 947 903 static int vc4_plane_atomic_async_check(struct drm_plane *plane, 948 904 struct drm_plane_state *state) 949 905 { 950 - /* No configuring new scaling in the fast path. */ 951 - if (plane->state->crtc_w != state->crtc_w || 952 - plane->state->crtc_h != state->crtc_h || 953 - plane->state->src_w != state->src_w || 954 - plane->state->src_h != state->src_h) 906 + struct vc4_plane_state *old_vc4_state, *new_vc4_state; 907 + int ret; 908 + u32 i; 909 + 910 + ret = vc4_plane_mode_set(plane, state); 911 + if (ret) 912 + return ret; 913 + 914 + old_vc4_state = to_vc4_plane_state(plane->state); 915 + new_vc4_state = to_vc4_plane_state(state); 916 + if (old_vc4_state->dlist_count != new_vc4_state->dlist_count || 917 + old_vc4_state->pos0_offset != new_vc4_state->pos0_offset || 918 + old_vc4_state->pos2_offset != new_vc4_state->pos2_offset || 919 + old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset || 920 + vc4_lbm_size(plane->state) != vc4_lbm_size(state)) 955 921 return -EINVAL; 922 + 923 + /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update 924 + * if anything else has changed, fallback to a sync update. 925 + */ 926 + for (i = 0; i < new_vc4_state->dlist_count; i++) { 927 + if (i == new_vc4_state->pos0_offset || 928 + i == new_vc4_state->pos2_offset || 929 + i == new_vc4_state->ptr0_offset || 930 + (new_vc4_state->lbm_offset && 931 + i == new_vc4_state->lbm_offset)) 932 + continue; 933 + 934 + if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i]) 935 + return -EINVAL; 936 + } 956 937 957 938 return 0; 958 939 } ··· 1095 1026 struct drm_plane *plane = NULL; 1096 1027 struct vc4_plane *vc4_plane; 1097 1028 u32 formats[ARRAY_SIZE(hvs_formats)]; 1098 - u32 num_formats = 0; 1099 1029 int ret = 0; 1100 1030 unsigned i; 1101 1031 static const uint64_t modifiers[] = { ··· 1111 1043 if (!vc4_plane) 1112 1044 return ERR_PTR(-ENOMEM); 1113 1045 1114 - for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { 1115 - /* Don't allow YUV in cursor planes, since that means 1116 - * tuning on the scaler, which we don't allow for the 1117 - * cursor. 1118 - */ 1119 - if (type != DRM_PLANE_TYPE_CURSOR || 1120 - hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) { 1121 - formats[num_formats++] = hvs_formats[i].drm; 1122 - } 1123 - } 1046 + for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) 1047 + formats[i] = hvs_formats[i].drm; 1048 + 1124 1049 plane = &vc4_plane->base; 1125 1050 ret = drm_universal_plane_init(dev, plane, 0, 1126 1051 &vc4_plane_funcs, 1127 - formats, num_formats, 1052 + formats, ARRAY_SIZE(formats), 1128 1053 modifiers, type, NULL); 1129 1054 1130 1055 drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
+7 -8
drivers/gpu/drm/virtio/virtgpu_drv.h
··· 270 270 uint64_t offset, 271 271 __le32 width, __le32 height, 272 272 __le32 x, __le32 y, 273 - struct virtio_gpu_fence **fence); 273 + struct virtio_gpu_fence *fence); 274 274 void virtio_gpu_cmd_resource_flush(struct virtio_gpu_device *vgdev, 275 275 uint32_t resource_id, 276 276 uint32_t x, uint32_t y, ··· 281 281 uint32_t x, uint32_t y); 282 282 int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, 283 283 struct virtio_gpu_object *obj, 284 - struct virtio_gpu_fence **fence); 284 + struct virtio_gpu_fence *fence); 285 285 void virtio_gpu_object_detach(struct virtio_gpu_device *vgdev, 286 286 struct virtio_gpu_object *obj); 287 287 int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev); ··· 306 306 uint32_t resource_id); 307 307 void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev, 308 308 void *data, uint32_t data_size, 309 - uint32_t ctx_id, struct virtio_gpu_fence **fence); 309 + uint32_t ctx_id, struct virtio_gpu_fence *fence); 310 310 void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev, 311 311 uint32_t resource_id, uint32_t ctx_id, 312 312 uint64_t offset, uint32_t level, 313 313 struct virtio_gpu_box *box, 314 - struct virtio_gpu_fence **fence); 314 + struct virtio_gpu_fence *fence); 315 315 void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev, 316 316 struct virtio_gpu_object *bo, 317 317 uint32_t ctx_id, 318 318 uint64_t offset, uint32_t level, 319 319 struct virtio_gpu_box *box, 320 - struct virtio_gpu_fence **fence); 320 + struct virtio_gpu_fence *fence); 321 321 void 322 322 virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, 323 323 struct virtio_gpu_object *bo, 324 - struct virtio_gpu_resource_create_3d *rc_3d, 325 - struct virtio_gpu_fence **fence); 324 + struct virtio_gpu_resource_create_3d *rc_3d); 326 325 void virtio_gpu_ctrl_ack(struct virtqueue *vq); 327 326 void virtio_gpu_cursor_ack(struct virtqueue *vq); 328 327 void virtio_gpu_fence_ack(struct virtqueue *vq); ··· 354 355 void virtio_gpu_fence_cleanup(struct virtio_gpu_fence *fence); 355 356 int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, 356 357 struct virtio_gpu_ctrl_hdr *cmd_hdr, 357 - struct virtio_gpu_fence **fence); 358 + struct virtio_gpu_fence *fence); 358 359 void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev, 359 360 u64 last_seq); 360 361
+5 -5
drivers/gpu/drm/virtio/virtgpu_fence.c
··· 91 91 92 92 int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, 93 93 struct virtio_gpu_ctrl_hdr *cmd_hdr, 94 - struct virtio_gpu_fence **fence) 94 + struct virtio_gpu_fence *fence) 95 95 { 96 96 struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; 97 97 unsigned long irq_flags; 98 98 99 99 spin_lock_irqsave(&drv->lock, irq_flags); 100 - (*fence)->seq = ++drv->sync_seq; 101 - dma_fence_get(&(*fence)->f); 102 - list_add_tail(&(*fence)->node, &drv->fences); 100 + fence->seq = ++drv->sync_seq; 101 + dma_fence_get(&fence->f); 102 + list_add_tail(&fence->node, &drv->fences); 103 103 spin_unlock_irqrestore(&drv->lock, irq_flags); 104 104 105 105 cmd_hdr->flags |= cpu_to_le32(VIRTIO_GPU_FLAG_FENCE); 106 - cmd_hdr->fence_id = cpu_to_le64((*fence)->seq); 106 + cmd_hdr->fence_id = cpu_to_le64(fence->seq); 107 107 return 0; 108 108 } 109 109
+5 -5
drivers/gpu/drm/virtio/virtgpu_ioctl.c
··· 221 221 } 222 222 223 223 virtio_gpu_cmd_submit(vgdev, buf, exbuf->size, 224 - vfpriv->ctx_id, &out_fence); 224 + vfpriv->ctx_id, out_fence); 225 225 226 226 ttm_eu_fence_buffer_objects(&ticket, &validate_list, &out_fence->f); 227 227 ··· 348 348 goto fail_backoff; 349 349 } 350 350 351 - virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d, NULL); 352 - ret = virtio_gpu_object_attach(vgdev, qobj, &fence); 351 + virtio_gpu_cmd_resource_create_3d(vgdev, qobj, &rc_3d); 352 + ret = virtio_gpu_object_attach(vgdev, qobj, fence); 353 353 if (ret) { 354 354 virtio_gpu_fence_cleanup(fence); 355 355 goto fail_backoff; ··· 450 450 virtio_gpu_cmd_transfer_from_host_3d 451 451 (vgdev, qobj->hw_res_handle, 452 452 vfpriv->ctx_id, offset, args->level, 453 - &box, &fence); 453 + &box, fence); 454 454 reservation_object_add_excl_fence(qobj->tbo.resv, 455 455 &fence->f); 456 456 ··· 504 504 virtio_gpu_cmd_transfer_to_host_3d 505 505 (vgdev, qobj, 506 506 vfpriv ? vfpriv->ctx_id : 0, offset, 507 - args->level, &box, &fence); 507 + args->level, &box, fence); 508 508 reservation_object_add_excl_fence(qobj->tbo.resv, 509 509 &fence->f); 510 510 dma_fence_put(&fence->f);
+1 -1
drivers/gpu/drm/virtio/virtgpu_plane.c
··· 204 204 (vgdev, bo, 0, 205 205 cpu_to_le32(plane->state->crtc_w), 206 206 cpu_to_le32(plane->state->crtc_h), 207 - 0, 0, &vgfb->fence); 207 + 0, 0, vgfb->fence); 208 208 ret = virtio_gpu_object_reserve(bo, false); 209 209 if (!ret) { 210 210 reservation_object_add_excl_fence(bo->tbo.resv,
+11 -12
drivers/gpu/drm/virtio/virtgpu_vq.c
··· 298 298 static int virtio_gpu_queue_fenced_ctrl_buffer(struct virtio_gpu_device *vgdev, 299 299 struct virtio_gpu_vbuffer *vbuf, 300 300 struct virtio_gpu_ctrl_hdr *hdr, 301 - struct virtio_gpu_fence **fence) 301 + struct virtio_gpu_fence *fence) 302 302 { 303 303 struct virtqueue *vq = vgdev->ctrlq.vq; 304 304 int rc; ··· 405 405 406 406 static void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev, 407 407 uint32_t resource_id, 408 - struct virtio_gpu_fence **fence) 408 + struct virtio_gpu_fence *fence) 409 409 { 410 410 struct virtio_gpu_resource_detach_backing *cmd_p; 411 411 struct virtio_gpu_vbuffer *vbuf; ··· 467 467 uint64_t offset, 468 468 __le32 width, __le32 height, 469 469 __le32 x, __le32 y, 470 - struct virtio_gpu_fence **fence) 470 + struct virtio_gpu_fence *fence) 471 471 { 472 472 struct virtio_gpu_transfer_to_host_2d *cmd_p; 473 473 struct virtio_gpu_vbuffer *vbuf; ··· 497 497 uint32_t resource_id, 498 498 struct virtio_gpu_mem_entry *ents, 499 499 uint32_t nents, 500 - struct virtio_gpu_fence **fence) 500 + struct virtio_gpu_fence *fence) 501 501 { 502 502 struct virtio_gpu_resource_attach_backing *cmd_p; 503 503 struct virtio_gpu_vbuffer *vbuf; ··· 820 820 void 821 821 virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev, 822 822 struct virtio_gpu_object *bo, 823 - struct virtio_gpu_resource_create_3d *rc_3d, 824 - struct virtio_gpu_fence **fence) 823 + struct virtio_gpu_resource_create_3d *rc_3d) 825 824 { 826 825 struct virtio_gpu_resource_create_3d *cmd_p; 827 826 struct virtio_gpu_vbuffer *vbuf; ··· 832 833 cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_3D); 833 834 cmd_p->hdr.flags = 0; 834 835 835 - virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence); 836 + virtio_gpu_queue_ctrl_buffer(vgdev, vbuf); 836 837 bo->created = true; 837 838 } 838 839 ··· 841 842 uint32_t ctx_id, 842 843 uint64_t offset, uint32_t level, 843 844 struct virtio_gpu_box *box, 844 - struct virtio_gpu_fence **fence) 845 + struct virtio_gpu_fence *fence) 845 846 { 846 847 struct virtio_gpu_transfer_host_3d *cmd_p; 847 848 struct virtio_gpu_vbuffer *vbuf; ··· 869 870 uint32_t resource_id, uint32_t ctx_id, 870 871 uint64_t offset, uint32_t level, 871 872 struct virtio_gpu_box *box, 872 - struct virtio_gpu_fence **fence) 873 + struct virtio_gpu_fence *fence) 873 874 { 874 875 struct virtio_gpu_transfer_host_3d *cmd_p; 875 876 struct virtio_gpu_vbuffer *vbuf; ··· 889 890 890 891 void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev, 891 892 void *data, uint32_t data_size, 892 - uint32_t ctx_id, struct virtio_gpu_fence **fence) 893 + uint32_t ctx_id, struct virtio_gpu_fence *fence) 893 894 { 894 895 struct virtio_gpu_cmd_submit *cmd_p; 895 896 struct virtio_gpu_vbuffer *vbuf; ··· 909 910 910 911 int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev, 911 912 struct virtio_gpu_object *obj, 912 - struct virtio_gpu_fence **fence) 913 + struct virtio_gpu_fence *fence) 913 914 { 914 915 bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev); 915 916 struct virtio_gpu_mem_entry *ents; ··· 966 967 if (use_dma_api && obj->mapped) { 967 968 struct virtio_gpu_fence *fence = virtio_gpu_fence_alloc(vgdev); 968 969 /* detach backing and wait for the host process it ... */ 969 - virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, &fence); 970 + virtio_gpu_cmd_resource_inval_backing(vgdev, obj->hw_res_handle, fence); 970 971 dma_fence_wait(&fence->f, true); 971 972 dma_fence_put(&fence->f); 972 973
+5 -4
drivers/gpu/drm/vkms/vkms_plane.c
··· 23 23 return NULL; 24 24 25 25 crc_data = kzalloc(sizeof(*crc_data), GFP_KERNEL); 26 - if (WARN_ON(!crc_data)) 27 - DRM_INFO("Couldn't allocate crc_data"); 26 + if (!crc_data) { 27 + DRM_DEBUG_KMS("Couldn't allocate crc_data\n"); 28 + kfree(vkms_state); 29 + return NULL; 30 + } 28 31 29 32 vkms_state->crc_data = crc_data; 30 33 ··· 141 138 struct drm_plane_state *state) 142 139 { 143 140 struct drm_gem_object *gem_obj; 144 - struct vkms_gem_object *vkms_obj; 145 141 int ret; 146 142 147 143 if (!state->fb) 148 144 return 0; 149 145 150 146 gem_obj = drm_gem_fb_get_obj(state->fb, 0); 151 - vkms_obj = drm_gem_to_vkms_gem(gem_obj); 152 147 ret = vkms_gem_vmap(gem_obj); 153 148 if (ret) 154 149 DRM_ERROR("vmap failed: %d\n", ret);
+7
include/drm/drm_atomic_helper.h
··· 127 127 int drm_atomic_helper_disable_all(struct drm_device *dev, 128 128 struct drm_modeset_acquire_ctx *ctx); 129 129 void drm_atomic_helper_shutdown(struct drm_device *dev); 130 + struct drm_atomic_state * 131 + drm_atomic_helper_duplicate_state(struct drm_device *dev, 132 + struct drm_modeset_acquire_ctx *ctx); 130 133 struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); 131 134 int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state, 132 135 struct drm_modeset_acquire_ctx *ctx); ··· 148 145 uint32_t flags, 149 146 uint32_t target, 150 147 struct drm_modeset_acquire_ctx *ctx); 148 + int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, 149 + u16 *red, u16 *green, u16 *blue, 150 + uint32_t size, 151 + struct drm_modeset_acquire_ctx *ctx); 151 152 152 153 /** 153 154 * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
-7
include/drm/drm_atomic_state_helper.h
··· 65 65 struct drm_connector_state *state); 66 66 struct drm_connector_state * 67 67 drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector); 68 - struct drm_atomic_state * 69 - drm_atomic_helper_duplicate_state(struct drm_device *dev, 70 - struct drm_modeset_acquire_ctx *ctx); 71 68 void 72 69 __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state); 73 70 void drm_atomic_helper_connector_destroy_state(struct drm_connector *connector, 74 71 struct drm_connector_state *state); 75 - int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc, 76 - u16 *red, u16 *green, u16 *blue, 77 - uint32_t size, 78 - struct drm_modeset_acquire_ctx *ctx); 79 72 void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj, 80 73 struct drm_private_state *state);
+59
include/drm/drm_modeset_lock.h
··· 130 130 int drm_modeset_lock_all_ctx(struct drm_device *dev, 131 131 struct drm_modeset_acquire_ctx *ctx); 132 132 133 + /** 134 + * DRM_MODESET_LOCK_ALL_BEGIN - Helper to acquire modeset locks 135 + * @dev: drm device 136 + * @ctx: local modeset acquire context, will be dereferenced 137 + * @flags: DRM_MODESET_ACQUIRE_* flags to pass to drm_modeset_acquire_init() 138 + * @ret: local ret/err/etc variable to track error status 139 + * 140 + * Use these macros to simplify grabbing all modeset locks using a local 141 + * context. This has the advantage of reducing boilerplate, but also properly 142 + * checking return values where appropriate. 143 + * 144 + * Any code run between BEGIN and END will be holding the modeset locks. 145 + * 146 + * This must be paired with DRM_MODESET_LOCK_ALL_END(). We will jump back and 147 + * forth between the labels on deadlock and error conditions. 148 + * 149 + * Drivers can acquire additional modeset locks. If any lock acquisition 150 + * fails, the control flow needs to jump to DRM_MODESET_LOCK_ALL_END() with 151 + * the @ret parameter containing the return value of drm_modeset_lock(). 152 + * 153 + * Returns: 154 + * The only possible value of ret immediately after DRM_MODESET_LOCK_ALL_BEGIN() 155 + * is 0, so no error checking is necessary 156 + */ 157 + #define DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret) \ 158 + drm_modeset_acquire_init(&ctx, flags); \ 159 + modeset_lock_retry: \ 160 + ret = drm_modeset_lock_all_ctx(dev, &ctx); \ 161 + if (ret) \ 162 + goto modeset_lock_fail; 163 + 164 + /** 165 + * DRM_MODESET_LOCK_ALL_END - Helper to release and cleanup modeset locks 166 + * @ctx: local modeset acquire context, will be dereferenced 167 + * @ret: local ret/err/etc variable to track error status 168 + * 169 + * The other side of DRM_MODESET_LOCK_ALL_BEGIN(). It will bounce back to BEGIN 170 + * if ret is -EDEADLK. 171 + * 172 + * It's important that you use the same ret variable for begin and end so 173 + * deadlock conditions are properly handled. 174 + * 175 + * Returns: 176 + * ret will be untouched unless it is -EDEADLK on entry. That means that if you 177 + * successfully acquire the locks, ret will be whatever your code sets it to. If 178 + * there is a deadlock or other failure with acquire or backoff, ret will be set 179 + * to that failure. In both of these cases the code between BEGIN/END will not 180 + * be run, so the failure will reflect the inability to grab the locks. 181 + */ 182 + #define DRM_MODESET_LOCK_ALL_END(ctx, ret) \ 183 + modeset_lock_fail: \ 184 + if (ret == -EDEADLK) { \ 185 + ret = drm_modeset_backoff(&ctx); \ 186 + if (!ret) \ 187 + goto modeset_lock_retry; \ 188 + } \ 189 + drm_modeset_drop_locks(&ctx); \ 190 + drm_modeset_acquire_fini(&ctx); 191 + 133 192 #endif /* DRM_MODESET_LOCK_H_ */
+1 -1
include/drm/drm_syncobj.h
··· 131 131 132 132 struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private, 133 133 u32 handle); 134 - void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point, 134 + void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, 135 135 struct dma_fence *fence); 136 136 int drm_syncobj_find_fence(struct drm_file *file_private, 137 137 u32 handle, u64 point, u64 flags,
+1
include/linux/dma-fence.h
··· 541 541 return ret < 0 ? ret : 0; 542 542 } 543 543 544 + struct dma_fence *dma_fence_get_stub(void); 544 545 u64 dma_fence_context_alloc(unsigned num); 545 546 546 547 #define DMA_FENCE_TRACE(f, fmt, args...) \
+25
include/uapi/drm/v3d_drm.h
··· 36 36 #define DRM_V3D_MMAP_BO 0x03 37 37 #define DRM_V3D_GET_PARAM 0x04 38 38 #define DRM_V3D_GET_BO_OFFSET 0x05 39 + #define DRM_V3D_SUBMIT_TFU 0x06 39 40 40 41 #define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl) 41 42 #define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo) ··· 44 43 #define DRM_IOCTL_V3D_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_MMAP_BO, struct drm_v3d_mmap_bo) 45 44 #define DRM_IOCTL_V3D_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_PARAM, struct drm_v3d_get_param) 46 45 #define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset) 46 + #define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu) 47 47 48 48 /** 49 49 * struct drm_v3d_submit_cl - ioctl argument for submitting commands to the 3D ··· 181 179 DRM_V3D_PARAM_V3D_CORE0_IDENT0, 182 180 DRM_V3D_PARAM_V3D_CORE0_IDENT1, 183 181 DRM_V3D_PARAM_V3D_CORE0_IDENT2, 182 + DRM_V3D_PARAM_SUPPORTS_TFU, 184 183 }; 185 184 186 185 struct drm_v3d_get_param { ··· 198 195 struct drm_v3d_get_bo_offset { 199 196 __u32 handle; 200 197 __u32 offset; 198 + }; 199 + 200 + struct drm_v3d_submit_tfu { 201 + __u32 icfg; 202 + __u32 iia; 203 + __u32 iis; 204 + __u32 ica; 205 + __u32 iua; 206 + __u32 ioa; 207 + __u32 ios; 208 + __u32 coef[4]; 209 + /* First handle is the output BO, following are other inputs. 210 + * 0 for unused. 211 + */ 212 + __u32 bo_handles[4]; 213 + /* sync object to block on before running the TFU job. Each TFU 214 + * job will execute in the order submitted to its FD. Synchronization 215 + * against rendering jobs requires using sync objects. 216 + */ 217 + __u32 in_sync; 218 + /* Sync object to signal when the TFU job is done. */ 219 + __u32 out_sync; 201 220 }; 202 221 203 222 #if defined(__cplusplus)