| .. | .. |
|---|
| 23 | 23 | * Alon Levy |
|---|
| 24 | 24 | */ |
|---|
| 25 | 25 | |
|---|
| 26 | +#include <linux/io-mapping.h> |
|---|
| 27 | +#include <linux/pci.h> |
|---|
| 28 | + |
|---|
| 29 | +#include <drm/drm_drv.h> |
|---|
| 30 | +#include <drm/drm_managed.h> |
|---|
| 31 | +#include <drm/drm_probe_helper.h> |
|---|
| 32 | + |
|---|
| 26 | 33 | #include "qxl_drv.h" |
|---|
| 27 | 34 | #include "qxl_object.h" |
|---|
| 28 | | - |
|---|
| 29 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 30 | | -#include <linux/io-mapping.h> |
|---|
| 31 | 35 | |
|---|
| 32 | 36 | int qxl_log_level; |
|---|
| 33 | 37 | |
|---|
| .. | .. |
|---|
| 53 | 57 | return true; |
|---|
| 54 | 58 | } |
|---|
| 55 | 59 | |
|---|
| 56 | | -static void setup_hw_slot(struct qxl_device *qdev, int slot_index, |
|---|
| 57 | | - struct qxl_memslot *slot) |
|---|
| 60 | +static void setup_hw_slot(struct qxl_device *qdev, struct qxl_memslot *slot) |
|---|
| 58 | 61 | { |
|---|
| 59 | 62 | qdev->ram_header->mem_slot.mem_start = slot->start_phys_addr; |
|---|
| 60 | | - qdev->ram_header->mem_slot.mem_end = slot->end_phys_addr; |
|---|
| 61 | | - qxl_io_memslot_add(qdev, slot_index); |
|---|
| 63 | + qdev->ram_header->mem_slot.mem_end = slot->start_phys_addr + slot->size; |
|---|
| 64 | + qxl_io_memslot_add(qdev, qdev->rom->slots_start + slot->index); |
|---|
| 62 | 65 | } |
|---|
| 63 | 66 | |
|---|
| 64 | | -static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset, |
|---|
| 65 | | - unsigned long start_phys_addr, unsigned long end_phys_addr) |
|---|
| 67 | +static void setup_slot(struct qxl_device *qdev, |
|---|
| 68 | + struct qxl_memslot *slot, |
|---|
| 69 | + unsigned int slot_index, |
|---|
| 70 | + const char *slot_name, |
|---|
| 71 | + unsigned long start_phys_addr, |
|---|
| 72 | + unsigned long size) |
|---|
| 66 | 73 | { |
|---|
| 67 | 74 | uint64_t high_bits; |
|---|
| 68 | | - struct qxl_memslot *slot; |
|---|
| 69 | | - uint8_t slot_index; |
|---|
| 70 | 75 | |
|---|
| 71 | | - slot_index = qdev->rom->slots_start + slot_index_offset; |
|---|
| 72 | | - slot = &qdev->mem_slots[slot_index]; |
|---|
| 76 | + slot->index = slot_index; |
|---|
| 77 | + slot->name = slot_name; |
|---|
| 73 | 78 | slot->start_phys_addr = start_phys_addr; |
|---|
| 74 | | - slot->end_phys_addr = end_phys_addr; |
|---|
| 79 | + slot->size = size; |
|---|
| 75 | 80 | |
|---|
| 76 | | - setup_hw_slot(qdev, slot_index, slot); |
|---|
| 81 | + setup_hw_slot(qdev, slot); |
|---|
| 77 | 82 | |
|---|
| 78 | 83 | slot->generation = qdev->rom->slot_generation; |
|---|
| 79 | | - high_bits = slot_index << qdev->slot_gen_bits; |
|---|
| 84 | + high_bits = (qdev->rom->slots_start + slot->index) |
|---|
| 85 | + << qdev->rom->slot_gen_bits; |
|---|
| 80 | 86 | high_bits |= slot->generation; |
|---|
| 81 | | - high_bits <<= (64 - (qdev->slot_gen_bits + qdev->slot_id_bits)); |
|---|
| 87 | + high_bits <<= (64 - (qdev->rom->slot_gen_bits + qdev->rom->slot_id_bits)); |
|---|
| 82 | 88 | slot->high_bits = high_bits; |
|---|
| 83 | | - return slot_index; |
|---|
| 89 | + |
|---|
| 90 | + DRM_INFO("slot %d (%s): base 0x%08lx, size 0x%08lx\n", |
|---|
| 91 | + slot->index, slot->name, |
|---|
| 92 | + (unsigned long)slot->start_phys_addr, |
|---|
| 93 | + (unsigned long)slot->size); |
|---|
| 84 | 94 | } |
|---|
| 85 | 95 | |
|---|
| 86 | 96 | void qxl_reinit_memslots(struct qxl_device *qdev) |
|---|
| 87 | 97 | { |
|---|
| 88 | | - setup_hw_slot(qdev, qdev->main_mem_slot, &qdev->mem_slots[qdev->main_mem_slot]); |
|---|
| 89 | | - setup_hw_slot(qdev, qdev->surfaces_mem_slot, &qdev->mem_slots[qdev->surfaces_mem_slot]); |
|---|
| 98 | + setup_hw_slot(qdev, &qdev->main_slot); |
|---|
| 99 | + setup_hw_slot(qdev, &qdev->surfaces_slot); |
|---|
| 90 | 100 | } |
|---|
| 91 | 101 | |
|---|
| 92 | 102 | static void qxl_gc_work(struct work_struct *work) |
|---|
| 93 | 103 | { |
|---|
| 94 | 104 | struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work); |
|---|
| 105 | + |
|---|
| 95 | 106 | qxl_garbage_collect(qdev); |
|---|
| 96 | 107 | } |
|---|
| 97 | 108 | |
|---|
| 98 | 109 | int qxl_device_init(struct qxl_device *qdev, |
|---|
| 99 | | - struct drm_driver *drv, |
|---|
| 100 | 110 | struct pci_dev *pdev) |
|---|
| 101 | 111 | { |
|---|
| 102 | 112 | int r, sb; |
|---|
| 103 | 113 | |
|---|
| 104 | | - r = drm_dev_init(&qdev->ddev, drv, &pdev->dev); |
|---|
| 105 | | - if (r) |
|---|
| 106 | | - return r; |
|---|
| 107 | | - |
|---|
| 108 | 114 | qdev->ddev.pdev = pdev; |
|---|
| 109 | 115 | pci_set_drvdata(pdev, &qdev->ddev); |
|---|
| 110 | | - qdev->ddev.dev_private = qdev; |
|---|
| 111 | 116 | |
|---|
| 112 | 117 | mutex_init(&qdev->gem.mutex); |
|---|
| 113 | 118 | mutex_init(&qdev->update_area_mutex); |
|---|
| .. | .. |
|---|
| 121 | 126 | qdev->io_base = pci_resource_start(pdev, 3); |
|---|
| 122 | 127 | |
|---|
| 123 | 128 | qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0)); |
|---|
| 129 | + if (!qdev->vram_mapping) { |
|---|
| 130 | + pr_err("Unable to create vram_mapping"); |
|---|
| 131 | + return -ENOMEM; |
|---|
| 132 | + } |
|---|
| 124 | 133 | |
|---|
| 125 | 134 | if (pci_resource_len(pdev, 4) > 0) { |
|---|
| 126 | 135 | /* 64bit surface bar present */ |
|---|
| .. | .. |
|---|
| 139 | 148 | qdev->surface_mapping = |
|---|
| 140 | 149 | io_mapping_create_wc(qdev->surfaceram_base, |
|---|
| 141 | 150 | qdev->surfaceram_size); |
|---|
| 151 | + if (!qdev->surface_mapping) { |
|---|
| 152 | + pr_err("Unable to create surface_mapping"); |
|---|
| 153 | + r = -ENOMEM; |
|---|
| 154 | + goto vram_mapping_free; |
|---|
| 155 | + } |
|---|
| 142 | 156 | } |
|---|
| 143 | 157 | |
|---|
| 144 | 158 | DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk, %s)\n", |
|---|
| .. | .. |
|---|
| 155 | 169 | qdev->rom = ioremap(qdev->rom_base, qdev->rom_size); |
|---|
| 156 | 170 | if (!qdev->rom) { |
|---|
| 157 | 171 | pr_err("Unable to ioremap ROM\n"); |
|---|
| 158 | | - return -ENOMEM; |
|---|
| 172 | + r = -ENOMEM; |
|---|
| 173 | + goto surface_mapping_free; |
|---|
| 159 | 174 | } |
|---|
| 160 | 175 | |
|---|
| 161 | | - qxl_check_device(qdev); |
|---|
| 176 | + if (!qxl_check_device(qdev)) { |
|---|
| 177 | + r = -ENODEV; |
|---|
| 178 | + goto rom_unmap; |
|---|
| 179 | + } |
|---|
| 162 | 180 | |
|---|
| 163 | 181 | r = qxl_bo_init(qdev); |
|---|
| 164 | 182 | if (r) { |
|---|
| 165 | 183 | DRM_ERROR("bo init failed %d\n", r); |
|---|
| 166 | | - return r; |
|---|
| 184 | + goto rom_unmap; |
|---|
| 167 | 185 | } |
|---|
| 168 | 186 | |
|---|
| 169 | 187 | qdev->ram_header = ioremap(qdev->vram_base + |
|---|
| 170 | 188 | qdev->rom->ram_header_offset, |
|---|
| 171 | 189 | sizeof(*qdev->ram_header)); |
|---|
| 190 | + if (!qdev->ram_header) { |
|---|
| 191 | + DRM_ERROR("Unable to ioremap RAM header\n"); |
|---|
| 192 | + r = -ENOMEM; |
|---|
| 193 | + goto bo_fini; |
|---|
| 194 | + } |
|---|
| 172 | 195 | |
|---|
| 173 | 196 | qdev->command_ring = qxl_ring_create(&(qdev->ram_header->cmd_ring_hdr), |
|---|
| 174 | 197 | sizeof(struct qxl_command), |
|---|
| .. | .. |
|---|
| 176 | 199 | qdev->io_base + QXL_IO_NOTIFY_CMD, |
|---|
| 177 | 200 | false, |
|---|
| 178 | 201 | &qdev->display_event); |
|---|
| 202 | + if (!qdev->command_ring) { |
|---|
| 203 | + DRM_ERROR("Unable to create command ring\n"); |
|---|
| 204 | + r = -ENOMEM; |
|---|
| 205 | + goto ram_header_unmap; |
|---|
| 206 | + } |
|---|
| 179 | 207 | |
|---|
| 180 | 208 | qdev->cursor_ring = qxl_ring_create( |
|---|
| 181 | 209 | &(qdev->ram_header->cursor_ring_hdr), |
|---|
| .. | .. |
|---|
| 185 | 213 | false, |
|---|
| 186 | 214 | &qdev->cursor_event); |
|---|
| 187 | 215 | |
|---|
| 216 | + if (!qdev->cursor_ring) { |
|---|
| 217 | + DRM_ERROR("Unable to create cursor ring\n"); |
|---|
| 218 | + r = -ENOMEM; |
|---|
| 219 | + goto command_ring_free; |
|---|
| 220 | + } |
|---|
| 221 | + |
|---|
| 188 | 222 | qdev->release_ring = qxl_ring_create( |
|---|
| 189 | 223 | &(qdev->ram_header->release_ring_hdr), |
|---|
| 190 | 224 | sizeof(uint64_t), |
|---|
| 191 | 225 | QXL_RELEASE_RING_SIZE, 0, true, |
|---|
| 192 | 226 | NULL); |
|---|
| 193 | 227 | |
|---|
| 194 | | - /* TODO - slot initialization should happen on reset. where is our |
|---|
| 195 | | - * reset handler? */ |
|---|
| 196 | | - qdev->n_mem_slots = qdev->rom->slots_end; |
|---|
| 197 | | - qdev->slot_gen_bits = qdev->rom->slot_gen_bits; |
|---|
| 198 | | - qdev->slot_id_bits = qdev->rom->slot_id_bits; |
|---|
| 199 | | - qdev->va_slot_mask = |
|---|
| 200 | | - (~(uint64_t)0) >> (qdev->slot_id_bits + qdev->slot_gen_bits); |
|---|
| 201 | | - |
|---|
| 202 | | - qdev->mem_slots = |
|---|
| 203 | | - kmalloc_array(qdev->n_mem_slots, sizeof(struct qxl_memslot), |
|---|
| 204 | | - GFP_KERNEL); |
|---|
| 228 | + if (!qdev->release_ring) { |
|---|
| 229 | + DRM_ERROR("Unable to create release ring\n"); |
|---|
| 230 | + r = -ENOMEM; |
|---|
| 231 | + goto cursor_ring_free; |
|---|
| 232 | + } |
|---|
| 205 | 233 | |
|---|
| 206 | 234 | idr_init(&qdev->release_idr); |
|---|
| 207 | 235 | spin_lock_init(&qdev->release_idr_lock); |
|---|
| .. | .. |
|---|
| 218 | 246 | |
|---|
| 219 | 247 | /* must initialize irq before first async io - slot creation */ |
|---|
| 220 | 248 | r = qxl_irq_init(qdev); |
|---|
| 221 | | - if (r) |
|---|
| 222 | | - return r; |
|---|
| 249 | + if (r) { |
|---|
| 250 | + DRM_ERROR("Unable to init qxl irq\n"); |
|---|
| 251 | + goto release_ring_free; |
|---|
| 252 | + } |
|---|
| 223 | 253 | |
|---|
| 224 | 254 | /* |
|---|
| 225 | 255 | * Note that virtual is surface0. We rely on the single ioremap done |
|---|
| 226 | 256 | * before. |
|---|
| 227 | 257 | */ |
|---|
| 228 | | - qdev->main_mem_slot = setup_slot(qdev, 0, |
|---|
| 229 | | - (unsigned long)qdev->vram_base, |
|---|
| 230 | | - (unsigned long)qdev->vram_base + qdev->rom->ram_header_offset); |
|---|
| 231 | | - qdev->surfaces_mem_slot = setup_slot(qdev, 1, |
|---|
| 232 | | - (unsigned long)qdev->surfaceram_base, |
|---|
| 233 | | - (unsigned long)qdev->surfaceram_base + qdev->surfaceram_size); |
|---|
| 234 | | - DRM_INFO("main mem slot %d [%lx,%x]\n", |
|---|
| 235 | | - qdev->main_mem_slot, |
|---|
| 236 | | - (unsigned long)qdev->vram_base, qdev->rom->ram_header_offset); |
|---|
| 237 | | - DRM_INFO("surface mem slot %d [%lx,%lx]\n", |
|---|
| 238 | | - qdev->surfaces_mem_slot, |
|---|
| 239 | | - (unsigned long)qdev->surfaceram_base, |
|---|
| 240 | | - (unsigned long)qdev->surfaceram_size); |
|---|
| 241 | | - |
|---|
| 258 | + setup_slot(qdev, &qdev->main_slot, 0, "main", |
|---|
| 259 | + (unsigned long)qdev->vram_base, |
|---|
| 260 | + (unsigned long)qdev->rom->ram_header_offset); |
|---|
| 261 | + setup_slot(qdev, &qdev->surfaces_slot, 1, "surfaces", |
|---|
| 262 | + (unsigned long)qdev->surfaceram_base, |
|---|
| 263 | + (unsigned long)qdev->surfaceram_size); |
|---|
| 242 | 264 | |
|---|
| 243 | 265 | INIT_WORK(&qdev->gc_work, qxl_gc_work); |
|---|
| 244 | 266 | |
|---|
| 245 | 267 | return 0; |
|---|
| 268 | + |
|---|
| 269 | +release_ring_free: |
|---|
| 270 | + qxl_ring_free(qdev->release_ring); |
|---|
| 271 | +cursor_ring_free: |
|---|
| 272 | + qxl_ring_free(qdev->cursor_ring); |
|---|
| 273 | +command_ring_free: |
|---|
| 274 | + qxl_ring_free(qdev->command_ring); |
|---|
| 275 | +ram_header_unmap: |
|---|
| 276 | + iounmap(qdev->ram_header); |
|---|
| 277 | +bo_fini: |
|---|
| 278 | + qxl_bo_fini(qdev); |
|---|
| 279 | +rom_unmap: |
|---|
| 280 | + iounmap(qdev->rom); |
|---|
| 281 | +surface_mapping_free: |
|---|
| 282 | + io_mapping_free(qdev->surface_mapping); |
|---|
| 283 | +vram_mapping_free: |
|---|
| 284 | + io_mapping_free(qdev->vram_mapping); |
|---|
| 285 | + return r; |
|---|
| 246 | 286 | } |
|---|
| 247 | 287 | |
|---|
| 248 | 288 | void qxl_device_fini(struct qxl_device *qdev) |
|---|
| 249 | 289 | { |
|---|
| 250 | | - if (qdev->current_release_bo[0]) |
|---|
| 251 | | - qxl_bo_unref(&qdev->current_release_bo[0]); |
|---|
| 252 | | - if (qdev->current_release_bo[1]) |
|---|
| 253 | | - qxl_bo_unref(&qdev->current_release_bo[1]); |
|---|
| 290 | + qxl_bo_unref(&qdev->current_release_bo[0]); |
|---|
| 291 | + qxl_bo_unref(&qdev->current_release_bo[1]); |
|---|
| 292 | + qxl_gem_fini(qdev); |
|---|
| 293 | + qxl_bo_fini(qdev); |
|---|
| 254 | 294 | flush_work(&qdev->gc_work); |
|---|
| 255 | 295 | qxl_ring_free(qdev->command_ring); |
|---|
| 256 | 296 | qxl_ring_free(qdev->cursor_ring); |
|---|
| 257 | 297 | qxl_ring_free(qdev->release_ring); |
|---|
| 258 | | - qxl_gem_fini(qdev); |
|---|
| 259 | | - qxl_bo_fini(qdev); |
|---|
| 260 | 298 | io_mapping_free(qdev->surface_mapping); |
|---|
| 261 | 299 | io_mapping_free(qdev->vram_mapping); |
|---|
| 262 | 300 | iounmap(qdev->ram_header); |
|---|