summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/qxl/qxl_kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/qxl/qxl_kms.c')
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c80
1 files changed, 73 insertions, 7 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index 771250aed78d..e25c589d5f50 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -102,8 +102,10 @@ int qxl_device_init(struct qxl_device *qdev,
int r, sb;
r = drm_dev_init(&qdev->ddev, drv, &pdev->dev);
- if (r)
- return r;
+ if (r) {
+ pr_err("Unable to init drm dev");
+ goto error;
+ }
qdev->ddev.pdev = pdev;
pci_set_drvdata(pdev, &qdev->ddev);
@@ -121,6 +123,11 @@ int qxl_device_init(struct qxl_device *qdev,
qdev->io_base = pci_resource_start(pdev, 3);
qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0));
+ if (!qdev->vram_mapping) {
+ pr_err("Unable to create vram_mapping");
+ r = -ENOMEM;
+ goto error;
+ }
if (pci_resource_len(pdev, 4) > 0) {
/* 64bit surface bar present */
@@ -139,6 +146,11 @@ int qxl_device_init(struct qxl_device *qdev,
qdev->surface_mapping =
io_mapping_create_wc(qdev->surfaceram_base,
qdev->surfaceram_size);
+ if (!qdev->surface_mapping) {
+ pr_err("Unable to create surface_mapping");
+ r = -ENOMEM;
+ goto vram_mapping_free;
+ }
}
DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk, %s)\n",
@@ -155,20 +167,29 @@ int qxl_device_init(struct qxl_device *qdev,
qdev->rom = ioremap(qdev->rom_base, qdev->rom_size);
if (!qdev->rom) {
pr_err("Unable to ioremap ROM\n");
- return -ENOMEM;
+ r = -ENOMEM;
+ goto surface_mapping_free;
}
- qxl_check_device(qdev);
+ if (!qxl_check_device(qdev)) {
+ r = -ENODEV;
+ goto surface_mapping_free;
+ }
r = qxl_bo_init(qdev);
if (r) {
DRM_ERROR("bo init failed %d\n", r);
- return r;
+ goto rom_unmap;
}
qdev->ram_header = ioremap(qdev->vram_base +
qdev->rom->ram_header_offset,
sizeof(*qdev->ram_header));
+ if (!qdev->ram_header) {
+ DRM_ERROR("Unable to ioremap RAM header\n");
+ r = -ENOMEM;
+ goto bo_fini;
+ }
qdev->command_ring = qxl_ring_create(&(qdev->ram_header->cmd_ring_hdr),
sizeof(struct qxl_command),
@@ -176,6 +197,11 @@ int qxl_device_init(struct qxl_device *qdev,
qdev->io_base + QXL_IO_NOTIFY_CMD,
false,
&qdev->display_event);
+ if (!qdev->command_ring) {
+ DRM_ERROR("Unable to create command ring\n");
+ r = -ENOMEM;
+ goto ram_header_unmap;
+ }
qdev->cursor_ring = qxl_ring_create(
&(qdev->ram_header->cursor_ring_hdr),
@@ -185,12 +211,23 @@ int qxl_device_init(struct qxl_device *qdev,
false,
&qdev->cursor_event);
+ if (!qdev->cursor_ring) {
+ DRM_ERROR("Unable to create cursor ring\n");
+ r = -ENOMEM;
+ goto command_ring_free;
+ }
+
qdev->release_ring = qxl_ring_create(
&(qdev->ram_header->release_ring_hdr),
sizeof(uint64_t),
QXL_RELEASE_RING_SIZE, 0, true,
NULL);
+ if (!qdev->release_ring) {
+ DRM_ERROR("Unable to create release ring\n");
+ r = -ENOMEM;
+ goto cursor_ring_free;
+ }
/* TODO - slot initialization should happen on reset. where is our
* reset handler? */
qdev->n_mem_slots = qdev->rom->slots_end;
@@ -203,6 +240,12 @@ int qxl_device_init(struct qxl_device *qdev,
kmalloc_array(qdev->n_mem_slots, sizeof(struct qxl_memslot),
GFP_KERNEL);
+ if (!qdev->mem_slots) {
+ DRM_ERROR("Unable to alloc mem slots\n");
+ r = -ENOMEM;
+ goto release_ring_free;
+ }
+
idr_init(&qdev->release_idr);
spin_lock_init(&qdev->release_idr_lock);
spin_lock_init(&qdev->release_lock);
@@ -218,8 +261,10 @@ int qxl_device_init(struct qxl_device *qdev,
/* must initialize irq before first async io - slot creation */
r = qxl_irq_init(qdev);
- if (r)
- return r;
+ if (r) {
+ DRM_ERROR("Unable to init qxl irq\n");
+ goto mem_slots_free;
+ }
/*
* Note that virtual is surface0. We rely on the single ioremap done
@@ -243,6 +288,27 @@ int qxl_device_init(struct qxl_device *qdev,
INIT_WORK(&qdev->gc_work, qxl_gc_work);
return 0;
+
+mem_slots_free:
+ kfree(qdev->mem_slots);
+release_ring_free:
+ qxl_ring_free(qdev->release_ring);
+cursor_ring_free:
+ qxl_ring_free(qdev->cursor_ring);
+command_ring_free:
+ qxl_ring_free(qdev->command_ring);
+ram_header_unmap:
+ iounmap(qdev->ram_header);
+bo_fini:
+ qxl_bo_fini(qdev);
+rom_unmap:
+ iounmap(qdev->rom);
+surface_mapping_free:
+ io_mapping_free(qdev->surface_mapping);
+vram_mapping_free:
+ io_mapping_free(qdev->vram_mapping);
+error:
+ return r;
}
void qxl_device_fini(struct qxl_device *qdev)