aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/qxl/qxl_cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/qxl/qxl_cmd.c')
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c88
1 files changed, 48 insertions, 40 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 08b0823c93d..eb89653a7a1 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -49,6 +49,11 @@ void qxl_ring_free(struct qxl_ring *ring)
kfree(ring);
}
+void qxl_ring_init_hdr(struct qxl_ring *ring)
+{
+ ring->ring->header.notify_on_prod = ring->n_elements;
+}
+
struct qxl_ring *
qxl_ring_create(struct qxl_ring_header *header,
int element_size,
@@ -69,7 +74,7 @@ qxl_ring_create(struct qxl_ring_header *header,
ring->prod_notify = prod_notify;
ring->push_event = push_event;
if (set_prod_notify)
- header->notify_on_prod = ring->n_elements;
+ qxl_ring_init_hdr(ring);
spin_lock_init(&ring->lock);
return ring;
}
@@ -87,7 +92,7 @@ static int qxl_check_header(struct qxl_ring *ring)
return ret;
}
-static int qxl_check_idle(struct qxl_ring *ring)
+int qxl_check_idle(struct qxl_ring *ring)
{
int ret;
struct qxl_ring_header *header = &(ring->ring->header);
@@ -174,9 +179,10 @@ qxl_push_command_ring_release(struct qxl_device *qdev, struct qxl_release *relea
uint32_t type, bool interruptible)
{
struct qxl_command cmd;
+ struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
cmd.type = type;
- cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset);
+ cmd.data = qxl_bo_physical_address(qdev, to_qxl_bo(entry->tv.bo), release->release_offset);
return qxl_ring_push(qdev->command_ring, &cmd, interruptible);
}
@@ -186,9 +192,10 @@ qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *releas
uint32_t type, bool interruptible)
{
struct qxl_command cmd;
+ struct qxl_bo_list *entry = list_first_entry(&release->bos, struct qxl_bo_list, tv.head);
cmd.type = type;
- cmd.data = qxl_bo_physical_address(qdev, release->bos[0], release->release_offset);
+ cmd.data = qxl_bo_physical_address(qdev, to_qxl_bo(entry->tv.bo), release->release_offset);
return qxl_ring_push(qdev->cursor_ring, &cmd, interruptible);
}
@@ -209,7 +216,6 @@ int qxl_garbage_collect(struct qxl_device *qdev)
struct qxl_release *release;
uint64_t id, next_id;
int i = 0;
- int ret;
union qxl_release_info *info;
while (qxl_ring_pop(qdev->release_ring, &id)) {
@@ -219,17 +225,10 @@ int qxl_garbage_collect(struct qxl_device *qdev)
if (release == NULL)
break;
- ret = qxl_release_reserve(qdev, release, false);
- if (ret) {
- qxl_io_log(qdev, "failed to reserve release on garbage collect %lld\n", id);
- DRM_ERROR("failed to reserve release %lld\n", id);
- }
-
info = qxl_release_map(qdev, release);
next_id = info->next;
qxl_release_unmap(qdev, release, info);
- qxl_release_unreserve(qdev, release);
QXL_INFO(qdev, "popped %lld, next %lld\n", id,
next_id);
@@ -254,30 +253,32 @@ int qxl_garbage_collect(struct qxl_device *qdev)
return i;
}
-int qxl_alloc_bo_reserved(struct qxl_device *qdev, unsigned long size,
+int qxl_alloc_bo_reserved(struct qxl_device *qdev,
+ struct qxl_release *release,
+ unsigned long size,
struct qxl_bo **_bo)
{
struct qxl_bo *bo;
int ret;
ret = qxl_bo_create(qdev, size, false /* not kernel - device */,
- QXL_GEM_DOMAIN_VRAM, NULL, &bo);
+ false, QXL_GEM_DOMAIN_VRAM, NULL, &bo);
if (ret) {
DRM_ERROR("failed to allocate VRAM BO\n");
return ret;
}
- ret = qxl_bo_reserve(bo, false);
- if (unlikely(ret != 0))
+ ret = qxl_release_list_add(release, bo);
+ if (ret)
goto out_unref;
*_bo = bo;
return 0;
out_unref:
qxl_bo_unref(&bo);
- return 0;
+ return ret;
}
-static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port)
+static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, bool intr)
{
int irq_num;
long addr = qdev->io_base + port;
@@ -285,20 +286,29 @@ static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port)
mutex_lock(&qdev->async_io_mutex);
irq_num = atomic_read(&qdev->irq_received_io_cmd);
-
-
if (qdev->last_sent_io_cmd > irq_num) {
- ret = wait_event_interruptible(qdev->io_cmd_event,
- atomic_read(&qdev->irq_received_io_cmd) > irq_num);
- if (ret)
+ if (intr)
+ ret = wait_event_interruptible_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
+ else
+ ret = wait_event_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
+ /* 0 is timeout, just bail the "hw" has gone away */
+ if (ret <= 0)
goto out;
irq_num = atomic_read(&qdev->irq_received_io_cmd);
}
outb(val, addr);
qdev->last_sent_io_cmd = irq_num + 1;
- ret = wait_event_interruptible(qdev->io_cmd_event,
- atomic_read(&qdev->irq_received_io_cmd) > irq_num);
+ if (intr)
+ ret = wait_event_interruptible_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
+ else
+ ret = wait_event_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
out:
+ if (ret > 0)
+ ret = 0;
mutex_unlock(&qdev->async_io_mutex);
return ret;
}
@@ -308,7 +318,7 @@ static void wait_for_io_cmd(struct qxl_device *qdev, uint8_t val, long port)
int ret;
restart:
- ret = wait_for_io_cmd_user(qdev, val, port);
+ ret = wait_for_io_cmd_user(qdev, val, port, false);
if (ret == -ERESTARTSYS)
goto restart;
}
@@ -340,7 +350,7 @@ int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf,
mutex_lock(&qdev->update_area_mutex);
qdev->ram_header->update_area = *area;
qdev->ram_header->update_surface = surface_id;
- ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC);
+ ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC, true);
mutex_unlock(&qdev->update_area_mutex);
return ret;
}
@@ -366,8 +376,8 @@ void qxl_io_destroy_primary(struct qxl_device *qdev)
wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
}
-void qxl_io_create_primary(struct qxl_device *qdev, unsigned width,
- unsigned height, unsigned offset, struct qxl_bo *bo)
+void qxl_io_create_primary(struct qxl_device *qdev,
+ unsigned offset, struct qxl_bo *bo)
{
struct qxl_surface_create *create;
@@ -375,8 +385,8 @@ void qxl_io_create_primary(struct qxl_device *qdev, unsigned width,
qdev->ram_header);
create = &qdev->ram_header->create_surface;
create->format = bo->surf.format;
- create->width = width;
- create->height = height;
+ create->width = bo->surf.width;
+ create->height = bo->surf.height;
create->stride = bo->surf.stride;
create->mem = qxl_bo_physical_address(qdev, bo, offset);
@@ -489,6 +499,10 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
if (ret)
return ret;
+ ret = qxl_release_reserve_list(release, true);
+ if (ret)
+ return ret;
+
cmd = (struct qxl_surface_cmd *)qxl_release_map(qdev, release);
cmd->type = QXL_SURFACE_CMD_CREATE;
cmd->u.surface_create.format = surf->surf.format;
@@ -510,14 +524,11 @@ int qxl_hw_surface_alloc(struct qxl_device *qdev,
surf->surf_create = release;
- /* no need to add a release to the fence for this bo,
+ /* no need to add a release to the fence for this surface bo,
since it is only released when we ask to destroy the surface
and it would never signal otherwise */
- qxl_fence_releaseable(qdev, release);
-
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
-
- qxl_release_unreserve(qdev, release);
+ qxl_release_fence_buffer_objects(release);
surf->hw_surf_alloc = true;
spin_lock(&qdev->surf_id_idr_lock);
@@ -559,12 +570,9 @@ int qxl_hw_surface_dealloc(struct qxl_device *qdev,
cmd->surface_id = id;
qxl_release_unmap(qdev, release, &cmd->release_info);
- qxl_fence_releaseable(qdev, release);
-
qxl_push_command_ring_release(qdev, release, QXL_CMD_SURFACE, false);
- qxl_release_unreserve(qdev, release);
-
+ qxl_release_fence_buffer_objects(release);
return 0;
}