mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 18:11:56 +00:00
drm/nv04/disp: fix framebuffer pin refcounting
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
6ff8c76a56
commit
78ae0ad403
@ -606,6 +606,24 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
|
|||||||
regp->ramdac_a34 = 0x1;
|
regp->ramdac_a34 = 0x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
|
||||||
|
{
|
||||||
|
struct nv04_display *disp = nv04_display(crtc->dev);
|
||||||
|
struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
|
||||||
|
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (disp->image[nv_crtc->index])
|
||||||
|
nouveau_bo_unpin(disp->image[nv_crtc->index]);
|
||||||
|
nouveau_bo_ref(nvfb->nvbo, &disp->image[nv_crtc->index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up registers for the given mode/adjusted_mode pair.
|
* Sets up registers for the given mode/adjusted_mode pair.
|
||||||
*
|
*
|
||||||
@ -622,10 +640,15 @@ nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|||||||
struct drm_device *dev = crtc->dev;
|
struct drm_device *dev = crtc->dev;
|
||||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index);
|
NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index);
|
||||||
drm_mode_debug_printmodeline(adjusted_mode);
|
drm_mode_debug_printmodeline(adjusted_mode);
|
||||||
|
|
||||||
|
ret = nv_crtc_swap_fbs(crtc, old_fb);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* unlock must come after turning off FP_TG_CONTROL in output_prepare */
|
/* unlock must come after turning off FP_TG_CONTROL in output_prepare */
|
||||||
nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1);
|
nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1);
|
||||||
|
|
||||||
@ -722,6 +745,7 @@ static void nv_crtc_commit(struct drm_crtc *crtc)
|
|||||||
|
|
||||||
static void nv_crtc_destroy(struct drm_crtc *crtc)
|
static void nv_crtc_destroy(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
|
struct nv04_display *disp = nv04_display(crtc->dev);
|
||||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||||
|
|
||||||
if (!nv_crtc)
|
if (!nv_crtc)
|
||||||
@ -729,6 +753,10 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
|
|||||||
|
|
||||||
drm_crtc_cleanup(crtc);
|
drm_crtc_cleanup(crtc);
|
||||||
|
|
||||||
|
if (disp->image[nv_crtc->index])
|
||||||
|
nouveau_bo_unpin(disp->image[nv_crtc->index]);
|
||||||
|
nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
|
||||||
|
|
||||||
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
|
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
|
||||||
nouveau_bo_unpin(nv_crtc->cursor.nvbo);
|
nouveau_bo_unpin(nv_crtc->cursor.nvbo);
|
||||||
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
|
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
|
||||||
@ -753,6 +781,16 @@ nv_crtc_gamma_load(struct drm_crtc *crtc)
|
|||||||
nouveau_hw_load_state_palette(dev, nv_crtc->index, &nv04_display(dev)->mode_reg);
|
nouveau_hw_load_state_palette(dev, nv_crtc->index, &nv04_display(dev)->mode_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nv_crtc_disable(struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct nv04_display *disp = nv04_display(crtc->dev);
|
||||||
|
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||||
|
if (disp->image[nv_crtc->index])
|
||||||
|
nouveau_bo_unpin(disp->image[nv_crtc->index]);
|
||||||
|
nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
|
nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
|
||||||
uint32_t size)
|
uint32_t size)
|
||||||
@ -791,7 +829,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
|
|||||||
struct drm_framebuffer *drm_fb;
|
struct drm_framebuffer *drm_fb;
|
||||||
struct nouveau_framebuffer *fb;
|
struct nouveau_framebuffer *fb;
|
||||||
int arb_burst, arb_lwm;
|
int arb_burst, arb_lwm;
|
||||||
int ret;
|
|
||||||
|
|
||||||
NV_DEBUG(drm, "index %d\n", nv_crtc->index);
|
NV_DEBUG(drm, "index %d\n", nv_crtc->index);
|
||||||
|
|
||||||
@ -801,10 +838,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If atomic, we want to switch to the fb we were passed, so
|
/* If atomic, we want to switch to the fb we were passed, so
|
||||||
* now we update pointers to do that. (We don't pin; just
|
* now we update pointers to do that.
|
||||||
* assume we're already pinned and update the base address.)
|
|
||||||
*/
|
*/
|
||||||
if (atomic) {
|
if (atomic) {
|
||||||
drm_fb = passed_fb;
|
drm_fb = passed_fb;
|
||||||
@ -812,17 +847,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
|
|||||||
} else {
|
} else {
|
||||||
drm_fb = crtc->fb;
|
drm_fb = crtc->fb;
|
||||||
fb = nouveau_framebuffer(crtc->fb);
|
fb = nouveau_framebuffer(crtc->fb);
|
||||||
/* If not atomic, we can go ahead and pin, and unpin the
|
|
||||||
* old fb we were passed.
|
|
||||||
*/
|
|
||||||
ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (passed_fb) {
|
|
||||||
struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
|
|
||||||
nouveau_bo_unpin(ofb->nvbo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nv_crtc->fb.offset = fb->nvbo->bo.offset;
|
nv_crtc->fb.offset = fb->nvbo->bo.offset;
|
||||||
@ -877,6 +901,9 @@ static int
|
|||||||
nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||||
struct drm_framebuffer *old_fb)
|
struct drm_framebuffer *old_fb)
|
||||||
{
|
{
|
||||||
|
int ret = nv_crtc_swap_fbs(crtc, old_fb);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
|
return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,6 +1054,7 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = {
|
|||||||
.mode_set_base = nv04_crtc_mode_set_base,
|
.mode_set_base = nv04_crtc_mode_set_base,
|
||||||
.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
|
.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
|
||||||
.load_lut = nv_crtc_gamma_load,
|
.load_lut = nv_crtc_gamma_load,
|
||||||
|
.disable = nv_crtc_disable,
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -81,6 +81,7 @@ struct nv04_display {
|
|||||||
uint32_t saved_vga_font[4][16384];
|
uint32_t saved_vga_font[4][16384];
|
||||||
uint32_t dac_users[4];
|
uint32_t dac_users[4];
|
||||||
struct nouveau_object *core;
|
struct nouveau_object *core;
|
||||||
|
struct nouveau_bo *image[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct nv04_display *
|
static inline struct nv04_display *
|
||||||
|
@ -577,6 +577,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
|
|||||||
ret = nv50_display_flip_next(crtc, fb, chan, 0);
|
ret = nv50_display_flip_next(crtc, fb, chan, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto fail_unreserve;
|
goto fail_unreserve;
|
||||||
|
} else {
|
||||||
|
struct nv04_display *dispnv04 = nv04_display(dev);
|
||||||
|
nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
|
ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
|
||||||
|
Loading…
Reference in New Issue
Block a user