Skip to content

Commit

Permalink
drm/ttm: make ttm reservation calls behave like reservation calls
Browse files Browse the repository at this point in the history
This commit converts the source of the val_seq counter to
the ww_mutex api. The reservation objects are converted later,
because there is still a lockdep splat in nouveau that has to
resolved first.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Reviewed-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
mlankhorst authored and airlied committed Jun 28, 2013
1 parent 786d725 commit ecff665
Show file tree
Hide file tree
Showing 13 changed files with 172 additions and 112 deletions.
38 changes: 25 additions & 13 deletions drivers/gpu/drm/nouveau/nouveau_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,12 @@ struct validate_op {
struct list_head vram_list;
struct list_head gart_list;
struct list_head both_list;
struct ww_acquire_ctx ticket;
};

static void
validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
validate_fini_list(struct list_head *list, struct nouveau_fence *fence,
struct ww_acquire_ctx *ticket)
{
struct list_head *entry, *tmp;
struct nouveau_bo *nvbo;
Expand All @@ -297,17 +299,24 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)

list_del(&nvbo->entry);
nvbo->reserved_by = NULL;
ttm_bo_unreserve(&nvbo->bo);
ttm_bo_unreserve_ticket(&nvbo->bo, ticket);
drm_gem_object_unreference_unlocked(nvbo->gem);
}
}

static void
validate_fini(struct validate_op *op, struct nouveau_fence* fence)
validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence)
{
validate_fini_list(&op->vram_list, fence);
validate_fini_list(&op->gart_list, fence);
validate_fini_list(&op->both_list, fence);
validate_fini_list(&op->vram_list, fence, &op->ticket);
validate_fini_list(&op->gart_list, fence, &op->ticket);
validate_fini_list(&op->both_list, fence, &op->ticket);
}

static void
validate_fini(struct validate_op *op, struct nouveau_fence *fence)
{
validate_fini_no_ticket(op, fence);
ww_acquire_fini(&op->ticket);
}

static int
Expand All @@ -317,13 +326,11 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
{
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct drm_device *dev = chan->drm->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
uint32_t sequence;
int trycnt = 0;
int ret, i;
struct nouveau_bo *res_bo = NULL;

sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
ww_acquire_init(&op->ticket, &reservation_ww_class);
retry:
if (++trycnt > 100000) {
NV_ERROR(cli, "%s failed and gave up.\n", __func__);
Expand All @@ -338,6 +345,7 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
gem = drm_gem_object_lookup(dev, file_priv, b->handle);
if (!gem) {
NV_ERROR(cli, "Unknown handle 0x%08x\n", b->handle);
ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -ENOENT;
}
Expand All @@ -352,21 +360,23 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
NV_ERROR(cli, "multiple instances of buffer %d on "
"validation list\n", b->handle);
drm_gem_object_unreference_unlocked(gem);
ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -EINVAL;
}

ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence);
ret = ttm_bo_reserve(&nvbo->bo, true, false, true, &op->ticket);
if (ret) {
validate_fini(op, NULL);
validate_fini_no_ticket(op, NULL);
if (unlikely(ret == -EAGAIN)) {
sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
ret = ttm_bo_reserve_slowpath(&nvbo->bo, true,
sequence);
&op->ticket);
if (!ret)
res_bo = nvbo;
}
if (unlikely(ret)) {
ww_acquire_done(&op->ticket);
ww_acquire_fini(&op->ticket);
drm_gem_object_unreference_unlocked(gem);
if (ret != -ERESTARTSYS)
NV_ERROR(cli, "fail reserve\n");
Expand All @@ -390,13 +400,15 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
NV_ERROR(cli, "invalid valid domains: 0x%08x\n",
b->valid_domains);
list_add_tail(&nvbo->entry, &op->both_list);
ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -EINVAL;
}
if (nvbo == res_bo)
goto retry;
}

ww_acquire_done(&op->ticket);
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ struct radeon_cs_parser {
u32 cs_flags;
u32 ring;
s32 priority;
struct ww_acquire_ctx ticket;
};

extern int radeon_cs_finish_pages(struct radeon_cs_parser *p);
Expand Down
18 changes: 10 additions & 8 deletions drivers/gpu/drm/radeon/radeon_cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
radeon_bo_list_add_object(&p->relocs[i].lobj,
&p->validated);
}
return radeon_bo_list_validate(&p->validated, p->ring);
return radeon_bo_list_validate(&p->ticket, &p->validated, p->ring);
}

static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority)
Expand Down Expand Up @@ -314,15 +314,17 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
* If error is set than unvalidate buffer, otherwise just free memory
* used by parsing context.
**/
static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bool backoff)
{
unsigned i;

if (!error) {
ttm_eu_fence_buffer_objects(&parser->validated,
ttm_eu_fence_buffer_objects(&parser->ticket,
&parser->validated,
parser->ib.fence);
} else {
ttm_eu_backoff_reservation(&parser->validated);
} else if (backoff) {
ttm_eu_backoff_reservation(&parser->ticket,
&parser->validated);
}

if (parser->relocs != NULL) {
Expand Down Expand Up @@ -535,7 +537,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
r = radeon_cs_parser_init(&parser, data);
if (r) {
DRM_ERROR("Failed to initialize parser !\n");
radeon_cs_parser_fini(&parser, r);
radeon_cs_parser_fini(&parser, r, false);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r);
return r;
Expand All @@ -544,7 +546,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to parse relocation %d!\n", r);
radeon_cs_parser_fini(&parser, r);
radeon_cs_parser_fini(&parser, r, false);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r);
return r;
Expand All @@ -563,7 +565,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
goto out;
}
out:
radeon_cs_parser_fini(&parser, r);
radeon_cs_parser_fini(&parser, r, true);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r);
return r;
Expand Down
5 changes: 3 additions & 2 deletions drivers/gpu/drm/radeon/radeon_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,14 +349,15 @@ void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
}
}

int radeon_bo_list_validate(struct list_head *head, int ring)
int radeon_bo_list_validate(struct ww_acquire_ctx *ticket,
struct list_head *head, int ring)
{
struct radeon_bo_list *lobj;
struct radeon_bo *bo;
u32 domain;
int r;

r = ttm_eu_reserve_buffers(head);
r = ttm_eu_reserve_buffers(ticket, head);
if (unlikely(r != 0)) {
return r;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/radeon/radeon_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ extern int radeon_bo_init(struct radeon_device *rdev);
extern void radeon_bo_fini(struct radeon_device *rdev);
extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
struct list_head *head);
extern int radeon_bo_list_validate(struct list_head *head, int ring);
extern int radeon_bo_list_validate(struct ww_acquire_ctx *ticket,
struct list_head *head, int ring);
extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
struct vm_area_struct *vma);
extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
Expand Down
27 changes: 13 additions & 14 deletions drivers/gpu/drm/radeon/radeon_uvd.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
struct radeon_fence **fence)
{
struct ttm_validate_buffer tv;
struct ww_acquire_ctx ticket;
struct list_head head;
struct radeon_ib ib;
uint64_t addr;
Expand All @@ -561,24 +562,20 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
INIT_LIST_HEAD(&head);
list_add(&tv.head, &head);

r = ttm_eu_reserve_buffers(&head);
r = ttm_eu_reserve_buffers(&ticket, &head);
if (r)
return r;

radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM);
radeon_uvd_force_into_uvd_segment(bo);

r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
if (r) {
ttm_eu_backoff_reservation(&head);
return r;
}
if (r)
goto err;

r = radeon_ib_get(rdev, ring, &ib, NULL, 16);
if (r) {
ttm_eu_backoff_reservation(&head);
return r;
}
if (r)
goto err;

addr = radeon_bo_gpu_offset(bo);
ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0);
Expand All @@ -592,18 +589,20 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
ib.length_dw = 16;

r = radeon_ib_schedule(rdev, &ib, NULL);
if (r) {
ttm_eu_backoff_reservation(&head);
return r;
}
ttm_eu_fence_buffer_objects(&head, ib.fence);
if (r)
goto err;
ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);

if (fence)
*fence = radeon_fence_ref(ib.fence);

radeon_ib_free(rdev, &ib);
radeon_bo_unref(&bo);
return 0;

err:
ttm_eu_backoff_reservation(&ticket, &head);
return r;
}

/* multiple fence commands without any stream commands in between can
Expand Down
Loading

0 comments on commit ecff665

Please sign in to comment.