Skip to content

Commit

Permalink
Merge branch 'drm-nouveau-next' of git://anongit.freedesktop.org/git/…
Browse files Browse the repository at this point in the history
…nouveau/linux-2.6

Fixes for some locking issues, and fence timeouts.

* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6:
  drm/nouveau: do not allow negative sizes for now
  drm/nouveau: add falcon interrupt handler
  drm/nouveau: use dedicated channel for async moves on GT/GF chipsets.
  drm/nouveau: bump fence timeout to 15 seconds
  drm/nouveau: do not unpin in nouveau_gem_object_del
  drm/nv50/kms: fix pin refcnt leaks
  drm/nouveau: fix some error-path leaks in fbcon handling code
  drm/nouveau: fix locking issues in page flipping paths
  • Loading branch information
Dave Airlie committed Jul 22, 2013
2 parents 25f397a + 0108bc8 commit 27ddabc
Show file tree
Hide file tree
Showing 14 changed files with 121 additions and 65 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;

nv_subdev(priv)->unit = 0x00008000;
nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nvc0_bsp_cclass;
nv_engine(priv)->sclass = nvc0_bsp_sclass;
return 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;

nv_subdev(priv)->unit = 0x00008000;
nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nve0_bsp_cclass;
nv_engine(priv)->sclass = nve0_bsp_sclass;
return 0;
Expand Down
19 changes: 19 additions & 0 deletions drivers/gpu/drm/nouveau/core/engine/falcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@
#include <engine/falcon.h>
#include <subdev/timer.h>

void
nouveau_falcon_intr(struct nouveau_subdev *subdev)
{
struct nouveau_falcon *falcon = (void *)subdev;
u32 dispatch = nv_ro32(falcon, 0x01c);
u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);

if (intr & 0x00000010) {
nv_debug(falcon, "ucode halted\n");
nv_wo32(falcon, 0x004, 0x00000010);
intr &= ~0x00000010;
}

if (intr) {
nv_error(falcon, "unhandled intr 0x%08x\n", intr);
nv_wo32(falcon, 0x004, intr);
}
}

u32
_nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
{
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ nvc0_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;

nv_subdev(priv)->unit = 0x00000002;
nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nvc0_ppp_cclass;
nv_engine(priv)->sclass = nvc0_ppp_sclass;
return 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ nvc0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;

nv_subdev(priv)->unit = 0x00020000;
nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nvc0_vp_cclass;
nv_engine(priv)->sclass = nvc0_vp_sclass;
return 0;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ nve0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;

nv_subdev(priv)->unit = 0x00020000;
nv_subdev(priv)->intr = nouveau_falcon_intr;
nv_engine(priv)->cclass = &nve0_vp_cclass;
nv_engine(priv)->sclass = nve0_vp_sclass;
return 0;
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/nouveau/core/include/engine/falcon.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ int nouveau_falcon_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, u32, bool, const char *,
const char *, int, void **);

void nouveau_falcon_intr(struct nouveau_subdev *subdev);

#define _nouveau_falcon_dtor _nouveau_engine_dtor
int _nouveau_falcon_init(struct nouveau_object *);
int _nouveau_falcon_fini(struct nouveau_object *, bool);
Expand Down
21 changes: 15 additions & 6 deletions drivers/gpu/drm/nouveau/nouveau_bo.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)

if (unlikely(nvbo->gem))
DRM_ERROR("bo %p still attached to GEM object\n", bo);
WARN_ON(nvbo->pin_refcnt > 0);
nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
kfree(nvbo);
}
Expand Down Expand Up @@ -197,6 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
size_t acc_size;
int ret;
int type = ttm_bo_type_device;
int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1);

if (size <= 0 || size > max_size) {
nv_warn(drm, "skipped size %x\n", (u32)size);
return -EINVAL;
}

if (sg)
type = ttm_bo_type_sg;
Expand Down Expand Up @@ -340,13 +347,15 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
{
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct ttm_buffer_object *bo = &nvbo->bo;
int ret;
int ret, ref;

ret = ttm_bo_reserve(bo, false, false, false, 0);
if (ret)
return ret;

if (--nvbo->pin_refcnt)
ref = --nvbo->pin_refcnt;
WARN_ON_ONCE(ref < 0);
if (ref)
goto out;

nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
Expand Down Expand Up @@ -578,7 +587,7 @@ nve0_bo_move_init(struct nouveau_channel *chan, u32 handle)
int ret = RING_SPACE(chan, 2);
if (ret == 0) {
BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1);
OUT_RING (chan, handle);
OUT_RING (chan, handle & 0x0000ffff);
FIRE_RING (chan);
}
return ret;
Expand Down Expand Up @@ -973,7 +982,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
struct ttm_mem_reg *old_mem = &bo->mem;
int ret;

mutex_lock(&chan->cli->mutex);
mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING);

/* create temporary vmas for the transfer and attach them to the
* old nouveau_mem node, these will get cleaned up after ttm has
Expand Down Expand Up @@ -1014,7 +1023,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
struct ttm_mem_reg *, struct ttm_mem_reg *);
int (*init)(struct nouveau_channel *, u32 handle);
} _methods[] = {
{ "COPY", 0, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
{ "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
{ "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
{ "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
{ "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
Expand All @@ -1034,7 +1043,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
struct nouveau_channel *chan;
u32 handle = (mthd->engine << 16) | mthd->oclass;

if (mthd->init == nve0_bo_move_init)
if (mthd->engine)
chan = drm->cechan;
else
chan = drm->channel;
Expand Down
69 changes: 31 additions & 38 deletions drivers/gpu/drm/nouveau/nouveau_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,27 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
{
struct nouveau_framebuffer *nouveau_fb;
struct drm_gem_object *gem;
int ret;
int ret = -ENOMEM;

gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
if (!gem)
return ERR_PTR(-ENOENT);

nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
if (!nouveau_fb)
return ERR_PTR(-ENOMEM);
goto err_unref;

ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
if (ret) {
drm_gem_object_unreference(gem);
return ERR_PTR(ret);
}
if (ret)
goto err;

return &nouveau_fb->base;

err:
kfree(nouveau_fb);
err_unref:
drm_gem_object_unreference(gem);
return ERR_PTR(ret);
}

static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
Expand Down Expand Up @@ -524,9 +528,12 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct nouveau_page_flip_state *s;
struct nouveau_channel *chan = NULL;
struct nouveau_fence *fence;
struct list_head res;
struct ttm_validate_buffer res_val[2];
struct ttm_validate_buffer resv[2] = {
{ .bo = &old_bo->bo },
{ .bo = &new_bo->bo },
};
struct ww_acquire_ctx ticket;
LIST_HEAD(res);
int ret;

if (!drm->channel)
Expand All @@ -545,27 +552,19 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
chan = drm->channel;
spin_unlock(&old_bo->bo.bdev->fence_lock);

mutex_lock(&chan->cli->mutex);

if (new_bo != old_bo) {
ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
if (likely(!ret)) {
res_val[0].bo = &old_bo->bo;
res_val[1].bo = &new_bo->bo;
INIT_LIST_HEAD(&res);
list_add_tail(&res_val[0].head, &res);
list_add_tail(&res_val[1].head, &res);
ret = ttm_eu_reserve_buffers(&ticket, &res);
if (ret)
nouveau_bo_unpin(new_bo);
}
} else
ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
if (ret)
goto fail_free;

if (ret) {
mutex_unlock(&chan->cli->mutex);
goto fail_free;
list_add(&resv[1].head, &res);
}
list_add(&resv[0].head, &res);

mutex_lock(&chan->cli->mutex);
ret = ttm_eu_reserve_buffers(&ticket, &res);
if (ret)
goto fail_unpin;

/* Initialize a page flip struct */
*s = (struct nouveau_page_flip_state)
Expand All @@ -576,10 +575,8 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Emit a page flip */
if (nv_device(drm->device)->card_type >= NV_50) {
ret = nv50_display_flip_next(crtc, fb, chan, 0);
if (ret) {
mutex_unlock(&chan->cli->mutex);
if (ret)
goto fail_unreserve;
}
}

ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
Expand All @@ -590,22 +587,18 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Update the crtc struct and cleanup */
crtc->fb = fb;

if (old_bo != new_bo) {
ttm_eu_fence_buffer_objects(&ticket, &res, fence);
ttm_eu_fence_buffer_objects(&ticket, &res, fence);
if (old_bo != new_bo)
nouveau_bo_unpin(old_bo);
} else {
nouveau_bo_fence(new_bo, fence);
ttm_bo_unreserve(&new_bo->bo);
}
nouveau_fence_unref(&fence);
return 0;

fail_unreserve:
if (old_bo != new_bo) {
ttm_eu_backoff_reservation(&ticket, &res);
ttm_eu_backoff_reservation(&ticket, &res);
fail_unpin:
mutex_unlock(&chan->cli->mutex);
if (old_bo != new_bo)
nouveau_bo_unpin(new_bo);
} else
ttm_bo_unreserve(&new_bo->bo);
fail_free:
kfree(s);
return ret;
Expand Down
15 changes: 12 additions & 3 deletions drivers/gpu/drm/nouveau/nouveau_drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,18 @@ nouveau_accel_init(struct nouveau_drm *drm)

arg0 = NVE0_CHANNEL_IND_ENGINE_GR;
arg1 = 1;
} else
if (device->chipset >= 0xa3 &&
device->chipset != 0xaa &&
device->chipset != 0xac) {
ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE,
NVDRM_CHAN + 1, NvDmaFB, NvDmaTT,
&drm->cechan);
if (ret)
NV_ERROR(drm, "failed to create ce channel, %d\n", ret);

arg0 = NvDmaFB;
arg1 = NvDmaTT;
} else {
arg0 = NvDmaFB;
arg1 = NvDmaTT;
Expand Down Expand Up @@ -284,8 +296,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
return 0;
}

static struct lock_class_key drm_client_lock_class_key;

static int
nouveau_drm_load(struct drm_device *dev, unsigned long flags)
{
Expand All @@ -297,7 +307,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
if (ret)
return ret;
lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);

dev->dev_private = drm;
drm->dev = dev;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/nouveau_fbcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
mutex_unlock(&dev->struct_mutex);
if (chan)
nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma);
nouveau_bo_unmap(nvbo);
out_unpin:
nouveau_bo_unpin(nvbo);
out_unref:
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/nouveau/nouveau_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
int ret;

fence->channel = chan;
fence->timeout = jiffies + (3 * DRM_HZ);
fence->timeout = jiffies + (15 * DRM_HZ);
fence->sequence = ++fctx->sequence;

ret = fctx->emit(fence);
Expand Down
6 changes: 0 additions & 6 deletions drivers/gpu/drm/nouveau/nouveau_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,6 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
return;
nvbo->gem = NULL;

/* Lockdep hates you for doing reserve with gem object lock held */
if (WARN_ON_ONCE(nvbo->pin_refcnt)) {
nvbo->pin_refcnt = 1;
nouveau_bo_unpin(nvbo);
}

if (gem->import_attach)
drm_prime_gem_destroy(gem, nvbo->bo.sg);

Expand Down
Loading

0 comments on commit 27ddabc

Please sign in to comment.