diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50/crc.c')
| -rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/crc.c | 98 |
1 files changed, 50 insertions, 48 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c index b8c31b697797..deb6af40ef32 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT +#include <linux/debugfs.h> #include <linux/string.h> + #include <drm/drm_crtc.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_vblank.h> @@ -84,7 +86,10 @@ static void nv50_crc_ctx_flip_work(struct kthread_work *base) struct nv50_crc *crc = container_of(work, struct nv50_crc, flip_work); struct nv50_head *head = container_of(crc, struct nv50_head, crc); struct drm_crtc *crtc = &head->base.base; - struct nv50_disp *disp = nv50_disp(crtc->dev); + struct drm_device *dev = crtc->dev; + struct nv50_disp *disp = nv50_disp(dev); + const uint64_t start_vbl = drm_crtc_vblank_count(crtc); + uint64_t end_vbl; u8 new_idx = crc->ctx_idx ^ 1; /* @@ -92,23 +97,24 @@ static void nv50_crc_ctx_flip_work(struct kthread_work *base) * try again for the next vblank if we don't grab the lock */ if (!mutex_trylock(&disp->mutex)) { - DRM_DEV_DEBUG_KMS(crtc->dev->dev, - "Lock contended, delaying CRC ctx flip for head-%d\n", - head->base.index); - drm_vblank_work_schedule(work, - drm_crtc_vblank_count(crtc) + 1, - true); + drm_dbg_kms(dev, "Lock contended, delaying CRC ctx flip for %s\n", crtc->name); + drm_vblank_work_schedule(work, start_vbl + 1, true); return; } - DRM_DEV_DEBUG_KMS(crtc->dev->dev, - "Flipping notifier ctx for head %d (%d -> %d)\n", - drm_crtc_index(crtc), crc->ctx_idx, new_idx); + drm_dbg_kms(dev, "Flipping notifier ctx for %s (%d -> %d)\n", + crtc->name, crc->ctx_idx, new_idx); nv50_crc_program_ctx(head, NULL); nv50_crc_program_ctx(head, &crc->ctx[new_idx]); mutex_unlock(&disp->mutex); + end_vbl = drm_crtc_vblank_count(crtc); + if (unlikely(end_vbl != start_vbl)) + NV_ERROR(nouveau_drm(dev), + "Failed to flip CRC context on %s on time (%llu > %llu)\n", + crtc->name, end_vbl, start_vbl); + spin_lock_irq(&crc->lock); crc->ctx_changed = true; spin_unlock_irq(&crc->lock); @@ -189,9 +195,9 @@ void nv50_crc_handle_vblank(struct nv50_head *head) * updates back-to-back without waiting, we'll just be * optimistic and assume we always miss exactly one frame. */ - DRM_DEV_DEBUG_KMS(head->base.base.dev->dev, - "Notifier ctx flip for head-%d finished, lost CRC for frame %llu\n", - head->base.index, crc->frame); + drm_dbg_kms(head->base.base.dev, + "Notifier ctx flip for head-%d finished, lost CRC for frame %llu\n", + head->base.index, crc->frame); crc->frame++; nv50_crc_reset_ctx(ctx); @@ -347,8 +353,6 @@ int nv50_crc_atomic_check_head(struct nv50_head *head, struct nv50_head_atom *armh) { struct nv50_atom *atom = nv50_atom(asyh->state.state); - struct drm_device *dev = head->base.base.dev; - struct nv50_disp *disp = nv50_disp(dev); bool changed = armh->crc.src != asyh->crc.src; if (!armh->crc.src && !asyh->crc.src) { @@ -357,30 +361,7 @@ int nv50_crc_atomic_check_head(struct nv50_head *head, return 0; } - /* While we don't care about entry tags, Volta+ hw always needs the - * controlling wndw channel programmed to a wndw that's owned by our - * head - */ - if (asyh->crc.src && disp->disp->object.oclass >= GV100_DISP && - !(BIT(asyh->crc.wndw) & asyh->wndw.owned)) { - if (!asyh->wndw.owned) { - /* TODO: once we support flexible channel ownership, - * we should write some code here to handle attempting - * to "steal" a plane: e.g. take a plane that is - * currently not-visible and owned by another head, - * and reassign it to this head. If we fail to do so, - * we shuld reject the mode outright as CRC capture - * then becomes impossible. - */ - NV_ATOMIC(nouveau_drm(dev), - "No available wndws for CRC readback\n"); - return -EINVAL; - } - asyh->crc.wndw = ffs(asyh->wndw.owned) - 1; - } - - if (drm_atomic_crtc_needs_modeset(&asyh->state) || changed || - armh->crc.wndw != asyh->crc.wndw) { + if (drm_atomic_crtc_needs_modeset(&asyh->state) || changed) { asyh->clr.crc = armh->crc.src && armh->state.active; asyh->set.crc = asyh->crc.src && asyh->state.active; if (changed) @@ -411,9 +392,18 @@ void nv50_crc_atomic_check_outp(struct nv50_atom *atom) struct nv50_head_atom *armh = nv50_head_atom(old_crtc_state); struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state); struct nv50_outp_atom *outp_atom; - struct nouveau_encoder *outp = - nv50_real_outp(nv50_head_atom_get_encoder(armh)); - struct drm_encoder *encoder = &outp->base.base; + struct nouveau_encoder *outp; + struct drm_encoder *encoder, *enc; + + enc = nv50_head_atom_get_encoder(armh); + if (!enc) + continue; + + outp = nv50_real_outp(enc); + if (!outp) + continue; + + encoder = &outp->base.base; if (!asyh->clr.crc) continue; @@ -464,12 +454,19 @@ void nv50_crc_atomic_set(struct nv50_head *head, struct drm_device *dev = crtc->dev; struct nv50_crc *crc = &head->crc; const struct nv50_crc_func *func = nv50_disp(dev)->core->func->crc; - struct nouveau_encoder *outp = - nv50_real_outp(nv50_head_atom_get_encoder(asyh)); + struct nouveau_encoder *outp; + struct drm_encoder *encoder; - func->set_src(head, outp->or, - nv50_crc_source_type(outp, asyh->crc.src), - &crc->ctx[crc->ctx_idx], asyh->crc.wndw); + encoder = nv50_head_atom_get_encoder(asyh); + if (!encoder) + return; + + outp = nv50_real_outp(encoder); + if (!outp) + return; + + func->set_src(head, outp->outp.or.id, nv50_crc_source_type(outp, asyh->crc.src), + &crc->ctx[crc->ctx_idx]); } void nv50_crc_atomic_clr(struct nv50_head *head) @@ -477,7 +474,7 @@ void nv50_crc_atomic_clr(struct nv50_head *head) const struct nv50_crc_func *func = nv50_disp(head->base.base.dev)->core->func->crc; - func->set_src(head, 0, NV50_CRC_SOURCE_TYPE_NONE, NULL, 0); + func->set_src(head, 0, NV50_CRC_SOURCE_TYPE_NONE, NULL); } static inline int @@ -512,6 +509,10 @@ nv50_crc_ctx_init(struct nv50_head *head, struct nvif_mmu *mmu, if (ret) return ret; + /* No CTXDMAs on Blackwell. */ + if (core->chan.base.user.oclass >= GB202_DISP_CORE_CHANNEL_DMA) + return 0; + ret = nvif_object_ctor(&core->chan.base.user, "kmsCrcNtfyCtxDma", NV50_DISP_HANDLE_CRC_CTX(head, idx), NV_DMA_IN_MEMORY, @@ -704,6 +705,7 @@ static const struct file_operations nv50_crc_flip_threshold_fops = { .open = nv50_crc_debugfs_flip_threshold_open, .read = seq_read, .write = nv50_crc_debugfs_flip_threshold_set, + .release = single_release, }; int nv50_head_crc_late_register(struct nv50_head *head) |
