1 1.6 riastrad /* $NetBSD: radeon_cs.c,v 1.6 2021/12/18 23:45:43 riastradh Exp $ */ 2 1.2 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2008 Jerome Glisse. 5 1.1 riastrad * All Rights Reserved. 6 1.1 riastrad * 7 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 8 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 9 1.1 riastrad * to deal in the Software without restriction, including without limitation 10 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 12 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 13 1.1 riastrad * 14 1.1 riastrad * The above copyright notice and this permission notice (including the next 15 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 16 1.1 riastrad * Software. 17 1.1 riastrad * 18 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 1.1 riastrad * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 1.1 riastrad * DEALINGS IN THE SOFTWARE. 25 1.1 riastrad * 26 1.1 riastrad * Authors: 27 1.1 riastrad * Jerome Glisse <glisse (at) freedesktop.org> 28 1.1 riastrad */ 29 1.6 riastrad 30 1.2 riastrad #include <sys/cdefs.h> 31 1.6 riastrad __KERNEL_RCSID(0, "$NetBSD: radeon_cs.c,v 1.6 2021/12/18 23:45:43 riastradh Exp $"); 32 1.2 riastrad 33 1.1 riastrad #include <linux/list_sort.h> 34 1.6 riastrad #include <linux/pci.h> 35 1.6 riastrad #include <linux/uaccess.h> 36 1.6 riastrad 37 1.6 riastrad #include <drm/drm_device.h> 38 1.6 riastrad #include <drm/drm_file.h> 39 1.1 riastrad #include <drm/radeon_drm.h> 40 1.6 riastrad 41 1.6 riastrad #include "radeon.h" 42 1.1 riastrad #include "radeon_reg.h" 43 1.1 riastrad #include "radeon_trace.h" 44 1.1 riastrad 45 1.1 riastrad #define RADEON_CS_MAX_PRIORITY 32u 46 1.1 riastrad #define RADEON_CS_NUM_BUCKETS (RADEON_CS_MAX_PRIORITY + 1) 47 1.1 riastrad 48 1.1 riastrad /* This is based on the bucket sort with O(n) time complexity. 49 1.1 riastrad * An item with priority "i" is added to bucket[i]. The lists are then 50 1.1 riastrad * concatenated in descending order. 51 1.1 riastrad */ 52 1.1 riastrad struct radeon_cs_buckets { 53 1.1 riastrad struct list_head bucket[RADEON_CS_NUM_BUCKETS]; 54 1.1 riastrad }; 55 1.1 riastrad 56 1.1 riastrad static void radeon_cs_buckets_init(struct radeon_cs_buckets *b) 57 1.1 riastrad { 58 1.1 riastrad unsigned i; 59 1.1 riastrad 60 1.1 riastrad for (i = 0; i < RADEON_CS_NUM_BUCKETS; i++) 61 1.1 riastrad INIT_LIST_HEAD(&b->bucket[i]); 62 1.1 riastrad } 63 1.1 riastrad 64 1.1 riastrad static void radeon_cs_buckets_add(struct radeon_cs_buckets *b, 65 1.1 riastrad struct list_head *item, unsigned priority) 66 1.1 riastrad { 67 1.1 riastrad /* Since buffers which appear sooner in the relocation list are 68 1.1 riastrad * likely to be used more often than buffers which appear later 69 1.1 riastrad * in the list, the sort mustn't change the ordering of buffers 70 1.1 riastrad * with the same priority, i.e. it must be stable. 71 1.1 riastrad */ 72 1.1 riastrad list_add_tail(item, &b->bucket[min(priority, RADEON_CS_MAX_PRIORITY)]); 73 1.1 riastrad } 74 1.1 riastrad 75 1.1 riastrad static void radeon_cs_buckets_get_list(struct radeon_cs_buckets *b, 76 1.1 riastrad struct list_head *out_list) 77 1.1 riastrad { 78 1.1 riastrad unsigned i; 79 1.1 riastrad 80 1.1 riastrad /* Connect the sorted buckets in the output list. */ 81 1.1 riastrad for (i = 0; i < RADEON_CS_NUM_BUCKETS; i++) { 82 1.1 riastrad list_splice(&b->bucket[i], out_list); 83 1.1 riastrad } 84 1.1 riastrad } 85 1.1 riastrad 86 1.1 riastrad static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) 87 1.1 riastrad { 88 1.1 riastrad struct radeon_cs_chunk *chunk; 89 1.1 riastrad struct radeon_cs_buckets buckets; 90 1.2 riastrad unsigned i; 91 1.5 riastrad bool need_mmap_lock = false; 92 1.2 riastrad int r; 93 1.1 riastrad 94 1.2 riastrad if (p->chunk_relocs == NULL) { 95 1.1 riastrad return 0; 96 1.1 riastrad } 97 1.2 riastrad chunk = p->chunk_relocs; 98 1.1 riastrad p->dma_reloc_idx = 0; 99 1.1 riastrad /* FIXME: we assume that each relocs use 4 dwords */ 100 1.1 riastrad p->nrelocs = chunk->length_dw / 4; 101 1.6 riastrad p->relocs = kvmalloc_array(p->nrelocs, sizeof(struct radeon_bo_list), 102 1.6 riastrad GFP_KERNEL | __GFP_ZERO); 103 1.1 riastrad if (p->relocs == NULL) { 104 1.1 riastrad return -ENOMEM; 105 1.1 riastrad } 106 1.1 riastrad 107 1.1 riastrad radeon_cs_buckets_init(&buckets); 108 1.1 riastrad 109 1.1 riastrad for (i = 0; i < p->nrelocs; i++) { 110 1.1 riastrad struct drm_radeon_cs_reloc *r; 111 1.2 riastrad struct drm_gem_object *gobj; 112 1.1 riastrad unsigned priority; 113 1.1 riastrad 114 1.1 riastrad r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4]; 115 1.6 riastrad gobj = drm_gem_object_lookup(p->filp, r->handle); 116 1.2 riastrad if (gobj == NULL) { 117 1.1 riastrad DRM_ERROR("gem object lookup failed 0x%x\n", 118 1.1 riastrad r->handle); 119 1.1 riastrad return -ENOENT; 120 1.1 riastrad } 121 1.2 riastrad p->relocs[i].robj = gem_to_radeon_bo(gobj); 122 1.1 riastrad 123 1.1 riastrad /* The userspace buffer priorities are from 0 to 15. A higher 124 1.1 riastrad * number means the buffer is more important. 125 1.1 riastrad * Also, the buffers used for write have a higher priority than 126 1.1 riastrad * the buffers used for read only, which doubles the range 127 1.1 riastrad * to 0 to 31. 32 is reserved for the kernel driver. 128 1.1 riastrad */ 129 1.2 riastrad priority = (r->flags & RADEON_RELOC_PRIO_MASK) * 2 130 1.2 riastrad + !!r->write_domain; 131 1.1 riastrad 132 1.6 riastrad /* The first reloc of an UVD job is the msg and that must be in 133 1.6 riastrad * VRAM, the second reloc is the DPB and for WMV that must be in 134 1.6 riastrad * VRAM as well. Also put everything into VRAM on AGP cards and older 135 1.6 riastrad * IGP chips to avoid image corruptions 136 1.6 riastrad */ 137 1.1 riastrad if (p->ring == R600_RING_TYPE_UVD_INDEX && 138 1.6 riastrad (i <= 0 || pci_find_capability(p->rdev->ddev->pdev, 139 1.6 riastrad PCI_CAP_ID_AGP) || 140 1.2 riastrad p->rdev->family == CHIP_RS780 || 141 1.2 riastrad p->rdev->family == CHIP_RS880)) { 142 1.2 riastrad 143 1.1 riastrad /* TODO: is this still needed for NI+ ? */ 144 1.6 riastrad p->relocs[i].preferred_domains = 145 1.1 riastrad RADEON_GEM_DOMAIN_VRAM; 146 1.1 riastrad 147 1.2 riastrad p->relocs[i].allowed_domains = 148 1.1 riastrad RADEON_GEM_DOMAIN_VRAM; 149 1.1 riastrad 150 1.1 riastrad /* prioritize this over any other relocation */ 151 1.1 riastrad priority = RADEON_CS_MAX_PRIORITY; 152 1.1 riastrad } else { 153 1.1 riastrad uint32_t domain = r->write_domain ? 154 1.1 riastrad r->write_domain : r->read_domains; 155 1.1 riastrad 156 1.1 riastrad if (domain & RADEON_GEM_DOMAIN_CPU) { 157 1.1 riastrad DRM_ERROR("RADEON_GEM_DOMAIN_CPU is not valid " 158 1.1 riastrad "for command submission\n"); 159 1.1 riastrad return -EINVAL; 160 1.1 riastrad } 161 1.1 riastrad 162 1.6 riastrad p->relocs[i].preferred_domains = domain; 163 1.1 riastrad if (domain == RADEON_GEM_DOMAIN_VRAM) 164 1.1 riastrad domain |= RADEON_GEM_DOMAIN_GTT; 165 1.2 riastrad p->relocs[i].allowed_domains = domain; 166 1.2 riastrad } 167 1.2 riastrad 168 1.2 riastrad if (radeon_ttm_tt_has_userptr(p->relocs[i].robj->tbo.ttm)) { 169 1.6 riastrad uint32_t domain = p->relocs[i].preferred_domains; 170 1.2 riastrad if (!(domain & RADEON_GEM_DOMAIN_GTT)) { 171 1.2 riastrad DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is " 172 1.2 riastrad "allowed for userptr BOs\n"); 173 1.2 riastrad return -EINVAL; 174 1.2 riastrad } 175 1.2 riastrad need_mmap_lock = true; 176 1.2 riastrad domain = RADEON_GEM_DOMAIN_GTT; 177 1.6 riastrad p->relocs[i].preferred_domains = domain; 178 1.2 riastrad p->relocs[i].allowed_domains = domain; 179 1.1 riastrad } 180 1.1 riastrad 181 1.6 riastrad /* Objects shared as dma-bufs cannot be moved to VRAM */ 182 1.6 riastrad if (p->relocs[i].robj->prime_shared_count) { 183 1.6 riastrad p->relocs[i].allowed_domains &= ~RADEON_GEM_DOMAIN_VRAM; 184 1.6 riastrad if (!p->relocs[i].allowed_domains) { 185 1.6 riastrad DRM_ERROR("BO associated with dma-buf cannot " 186 1.6 riastrad "be moved to VRAM\n"); 187 1.6 riastrad return -EINVAL; 188 1.6 riastrad } 189 1.6 riastrad } 190 1.6 riastrad 191 1.1 riastrad p->relocs[i].tv.bo = &p->relocs[i].robj->tbo; 192 1.6 riastrad p->relocs[i].tv.num_shared = !r->write_domain; 193 1.1 riastrad 194 1.1 riastrad radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head, 195 1.1 riastrad priority); 196 1.1 riastrad } 197 1.1 riastrad 198 1.1 riastrad radeon_cs_buckets_get_list(&buckets, &p->validated); 199 1.1 riastrad 200 1.1 riastrad if (p->cs_flags & RADEON_CS_USE_VM) 201 1.1 riastrad p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm, 202 1.1 riastrad &p->validated); 203 1.3 riastrad #ifdef __NetBSD__ 204 1.5 riastrad if (need_mmap_lock) 205 1.5 riastrad vm_map_lock_read(&curproc->p_vmspace->vm_map); 206 1.3 riastrad #else 207 1.2 riastrad if (need_mmap_lock) 208 1.2 riastrad down_read(¤t->mm->mmap_sem); 209 1.3 riastrad #endif 210 1.1 riastrad 211 1.2 riastrad r = radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring); 212 1.2 riastrad 213 1.5 riastrad #ifdef __NetBSD__ 214 1.5 riastrad if (need_mmap_lock) 215 1.5 riastrad vm_map_unlock_read(&curproc->p_vmspace->vm_map); 216 1.5 riastrad #else 217 1.2 riastrad if (need_mmap_lock) 218 1.2 riastrad up_read(¤t->mm->mmap_sem); 219 1.3 riastrad #endif 220 1.2 riastrad 221 1.2 riastrad return r; 222 1.1 riastrad } 223 1.1 riastrad 224 1.1 riastrad static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority) 225 1.1 riastrad { 226 1.1 riastrad p->priority = priority; 227 1.1 riastrad 228 1.1 riastrad switch (ring) { 229 1.1 riastrad default: 230 1.1 riastrad DRM_ERROR("unknown ring id: %d\n", ring); 231 1.1 riastrad return -EINVAL; 232 1.1 riastrad case RADEON_CS_RING_GFX: 233 1.1 riastrad p->ring = RADEON_RING_TYPE_GFX_INDEX; 234 1.1 riastrad break; 235 1.1 riastrad case RADEON_CS_RING_COMPUTE: 236 1.1 riastrad if (p->rdev->family >= CHIP_TAHITI) { 237 1.1 riastrad if (p->priority > 0) 238 1.1 riastrad p->ring = CAYMAN_RING_TYPE_CP1_INDEX; 239 1.1 riastrad else 240 1.1 riastrad p->ring = CAYMAN_RING_TYPE_CP2_INDEX; 241 1.1 riastrad } else 242 1.1 riastrad p->ring = RADEON_RING_TYPE_GFX_INDEX; 243 1.1 riastrad break; 244 1.1 riastrad case RADEON_CS_RING_DMA: 245 1.1 riastrad if (p->rdev->family >= CHIP_CAYMAN) { 246 1.1 riastrad if (p->priority > 0) 247 1.1 riastrad p->ring = R600_RING_TYPE_DMA_INDEX; 248 1.1 riastrad else 249 1.1 riastrad p->ring = CAYMAN_RING_TYPE_DMA1_INDEX; 250 1.1 riastrad } else if (p->rdev->family >= CHIP_RV770) { 251 1.1 riastrad p->ring = R600_RING_TYPE_DMA_INDEX; 252 1.1 riastrad } else { 253 1.1 riastrad return -EINVAL; 254 1.1 riastrad } 255 1.1 riastrad break; 256 1.1 riastrad case RADEON_CS_RING_UVD: 257 1.1 riastrad p->ring = R600_RING_TYPE_UVD_INDEX; 258 1.1 riastrad break; 259 1.1 riastrad case RADEON_CS_RING_VCE: 260 1.1 riastrad /* TODO: only use the low priority ring for now */ 261 1.1 riastrad p->ring = TN_RING_TYPE_VCE1_INDEX; 262 1.1 riastrad break; 263 1.1 riastrad } 264 1.1 riastrad return 0; 265 1.1 riastrad } 266 1.1 riastrad 267 1.2 riastrad static int radeon_cs_sync_rings(struct radeon_cs_parser *p) 268 1.1 riastrad { 269 1.2 riastrad struct radeon_bo_list *reloc; 270 1.2 riastrad int r; 271 1.1 riastrad 272 1.2 riastrad list_for_each_entry(reloc, &p->validated, tv.head) { 273 1.6 riastrad struct dma_resv *resv; 274 1.1 riastrad 275 1.6 riastrad resv = reloc->robj->tbo.base.resv; 276 1.2 riastrad r = radeon_sync_resv(p->rdev, &p->ib.sync, resv, 277 1.6 riastrad reloc->tv.num_shared); 278 1.2 riastrad if (r) 279 1.2 riastrad return r; 280 1.1 riastrad } 281 1.2 riastrad return 0; 282 1.1 riastrad } 283 1.1 riastrad 284 1.1 riastrad /* XXX: note that this is called from the legacy UMS CS ioctl as well */ 285 1.1 riastrad int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) 286 1.1 riastrad { 287 1.1 riastrad struct drm_radeon_cs *cs = data; 288 1.1 riastrad uint64_t *chunk_array_ptr; 289 1.1 riastrad unsigned size, i; 290 1.1 riastrad u32 ring = RADEON_CS_RING_GFX; 291 1.1 riastrad s32 priority = 0; 292 1.1 riastrad 293 1.2 riastrad INIT_LIST_HEAD(&p->validated); 294 1.2 riastrad 295 1.1 riastrad if (!cs->num_chunks) { 296 1.1 riastrad return 0; 297 1.1 riastrad } 298 1.2 riastrad 299 1.1 riastrad /* get chunks */ 300 1.1 riastrad p->idx = 0; 301 1.1 riastrad p->ib.sa_bo = NULL; 302 1.1 riastrad p->const_ib.sa_bo = NULL; 303 1.2 riastrad p->chunk_ib = NULL; 304 1.2 riastrad p->chunk_relocs = NULL; 305 1.2 riastrad p->chunk_flags = NULL; 306 1.2 riastrad p->chunk_const_ib = NULL; 307 1.1 riastrad p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL); 308 1.1 riastrad if (p->chunks_array == NULL) { 309 1.1 riastrad return -ENOMEM; 310 1.1 riastrad } 311 1.1 riastrad chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks); 312 1.1 riastrad if (copy_from_user(p->chunks_array, chunk_array_ptr, 313 1.1 riastrad sizeof(uint64_t)*cs->num_chunks)) { 314 1.1 riastrad return -EFAULT; 315 1.1 riastrad } 316 1.1 riastrad p->cs_flags = 0; 317 1.1 riastrad p->nchunks = cs->num_chunks; 318 1.1 riastrad p->chunks = kcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL); 319 1.1 riastrad if (p->chunks == NULL) { 320 1.1 riastrad return -ENOMEM; 321 1.1 riastrad } 322 1.1 riastrad for (i = 0; i < p->nchunks; i++) { 323 1.1 riastrad struct drm_radeon_cs_chunk __user **chunk_ptr = NULL; 324 1.1 riastrad struct drm_radeon_cs_chunk user_chunk; 325 1.1 riastrad uint32_t __user *cdata; 326 1.1 riastrad 327 1.1 riastrad chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i]; 328 1.1 riastrad if (copy_from_user(&user_chunk, chunk_ptr, 329 1.1 riastrad sizeof(struct drm_radeon_cs_chunk))) { 330 1.1 riastrad return -EFAULT; 331 1.1 riastrad } 332 1.1 riastrad p->chunks[i].length_dw = user_chunk.length_dw; 333 1.2 riastrad if (user_chunk.chunk_id == RADEON_CHUNK_ID_RELOCS) { 334 1.2 riastrad p->chunk_relocs = &p->chunks[i]; 335 1.1 riastrad } 336 1.2 riastrad if (user_chunk.chunk_id == RADEON_CHUNK_ID_IB) { 337 1.2 riastrad p->chunk_ib = &p->chunks[i]; 338 1.1 riastrad /* zero length IB isn't useful */ 339 1.1 riastrad if (p->chunks[i].length_dw == 0) 340 1.1 riastrad return -EINVAL; 341 1.1 riastrad } 342 1.2 riastrad if (user_chunk.chunk_id == RADEON_CHUNK_ID_CONST_IB) { 343 1.2 riastrad p->chunk_const_ib = &p->chunks[i]; 344 1.1 riastrad /* zero length CONST IB isn't useful */ 345 1.1 riastrad if (p->chunks[i].length_dw == 0) 346 1.1 riastrad return -EINVAL; 347 1.1 riastrad } 348 1.2 riastrad if (user_chunk.chunk_id == RADEON_CHUNK_ID_FLAGS) { 349 1.2 riastrad p->chunk_flags = &p->chunks[i]; 350 1.1 riastrad /* zero length flags aren't useful */ 351 1.1 riastrad if (p->chunks[i].length_dw == 0) 352 1.1 riastrad return -EINVAL; 353 1.1 riastrad } 354 1.1 riastrad 355 1.1 riastrad size = p->chunks[i].length_dw; 356 1.1 riastrad cdata = (void __user *)(unsigned long)user_chunk.chunk_data; 357 1.1 riastrad p->chunks[i].user_ptr = cdata; 358 1.2 riastrad if (user_chunk.chunk_id == RADEON_CHUNK_ID_CONST_IB) 359 1.1 riastrad continue; 360 1.1 riastrad 361 1.2 riastrad if (user_chunk.chunk_id == RADEON_CHUNK_ID_IB) { 362 1.1 riastrad if (!p->rdev || !(p->rdev->flags & RADEON_IS_AGP)) 363 1.1 riastrad continue; 364 1.1 riastrad } 365 1.1 riastrad 366 1.6 riastrad p->chunks[i].kdata = kvmalloc_array(size, sizeof(uint32_t), GFP_KERNEL); 367 1.1 riastrad size *= sizeof(uint32_t); 368 1.1 riastrad if (p->chunks[i].kdata == NULL) { 369 1.1 riastrad return -ENOMEM; 370 1.1 riastrad } 371 1.1 riastrad if (copy_from_user(p->chunks[i].kdata, cdata, size)) { 372 1.1 riastrad return -EFAULT; 373 1.1 riastrad } 374 1.2 riastrad if (user_chunk.chunk_id == RADEON_CHUNK_ID_FLAGS) { 375 1.1 riastrad p->cs_flags = p->chunks[i].kdata[0]; 376 1.1 riastrad if (p->chunks[i].length_dw > 1) 377 1.1 riastrad ring = p->chunks[i].kdata[1]; 378 1.1 riastrad if (p->chunks[i].length_dw > 2) 379 1.1 riastrad priority = (s32)p->chunks[i].kdata[2]; 380 1.1 riastrad } 381 1.1 riastrad } 382 1.1 riastrad 383 1.1 riastrad /* these are KMS only */ 384 1.1 riastrad if (p->rdev) { 385 1.1 riastrad if ((p->cs_flags & RADEON_CS_USE_VM) && 386 1.1 riastrad !p->rdev->vm_manager.enabled) { 387 1.1 riastrad DRM_ERROR("VM not active on asic!\n"); 388 1.1 riastrad return -EINVAL; 389 1.1 riastrad } 390 1.1 riastrad 391 1.1 riastrad if (radeon_cs_get_ring(p, ring, priority)) 392 1.1 riastrad return -EINVAL; 393 1.1 riastrad 394 1.1 riastrad /* we only support VM on some SI+ rings */ 395 1.1 riastrad if ((p->cs_flags & RADEON_CS_USE_VM) == 0) { 396 1.1 riastrad if (p->rdev->asic->ring[p->ring]->cs_parse == NULL) { 397 1.1 riastrad DRM_ERROR("Ring %d requires VM!\n", p->ring); 398 1.1 riastrad return -EINVAL; 399 1.1 riastrad } 400 1.1 riastrad } else { 401 1.1 riastrad if (p->rdev->asic->ring[p->ring]->ib_parse == NULL) { 402 1.1 riastrad DRM_ERROR("VM not supported on ring %d!\n", 403 1.1 riastrad p->ring); 404 1.1 riastrad return -EINVAL; 405 1.1 riastrad } 406 1.1 riastrad } 407 1.1 riastrad } 408 1.1 riastrad 409 1.1 riastrad return 0; 410 1.1 riastrad } 411 1.1 riastrad 412 1.1 riastrad static int cmp_size_smaller_first(void *priv, struct list_head *a, 413 1.1 riastrad struct list_head *b) 414 1.1 riastrad { 415 1.2 riastrad struct radeon_bo_list *la = list_entry(a, struct radeon_bo_list, tv.head); 416 1.2 riastrad struct radeon_bo_list *lb = list_entry(b, struct radeon_bo_list, tv.head); 417 1.1 riastrad 418 1.1 riastrad /* Sort A before B if A is smaller. */ 419 1.1 riastrad return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages; 420 1.1 riastrad } 421 1.1 riastrad 422 1.1 riastrad /** 423 1.1 riastrad * cs_parser_fini() - clean parser states 424 1.1 riastrad * @parser: parser structure holding parsing context. 425 1.1 riastrad * @error: error number 426 1.1 riastrad * 427 1.1 riastrad * If error is set than unvalidate buffer, otherwise just free memory 428 1.1 riastrad * used by parsing context. 429 1.1 riastrad **/ 430 1.1 riastrad static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bool backoff) 431 1.1 riastrad { 432 1.1 riastrad unsigned i; 433 1.1 riastrad 434 1.1 riastrad if (!error) { 435 1.1 riastrad /* Sort the buffer list from the smallest to largest buffer, 436 1.1 riastrad * which affects the order of buffers in the LRU list. 437 1.1 riastrad * This assures that the smallest buffers are added first 438 1.1 riastrad * to the LRU list, so they are likely to be later evicted 439 1.1 riastrad * first, instead of large buffers whose eviction is more 440 1.1 riastrad * expensive. 441 1.1 riastrad * 442 1.1 riastrad * This slightly lowers the number of bytes moved by TTM 443 1.1 riastrad * per frame under memory pressure. 444 1.1 riastrad */ 445 1.1 riastrad list_sort(NULL, &parser->validated, cmp_size_smaller_first); 446 1.1 riastrad 447 1.1 riastrad ttm_eu_fence_buffer_objects(&parser->ticket, 448 1.1 riastrad &parser->validated, 449 1.2 riastrad &parser->ib.fence->base); 450 1.1 riastrad } else if (backoff) { 451 1.1 riastrad ttm_eu_backoff_reservation(&parser->ticket, 452 1.1 riastrad &parser->validated); 453 1.1 riastrad } 454 1.1 riastrad 455 1.1 riastrad if (parser->relocs != NULL) { 456 1.1 riastrad for (i = 0; i < parser->nrelocs; i++) { 457 1.2 riastrad struct radeon_bo *bo = parser->relocs[i].robj; 458 1.2 riastrad if (bo == NULL) 459 1.2 riastrad continue; 460 1.2 riastrad 461 1.6 riastrad drm_gem_object_put_unlocked(&bo->tbo.base); 462 1.1 riastrad } 463 1.1 riastrad } 464 1.1 riastrad kfree(parser->track); 465 1.6 riastrad kvfree(parser->relocs); 466 1.6 riastrad kvfree(parser->vm_bos); 467 1.1 riastrad for (i = 0; i < parser->nchunks; i++) 468 1.6 riastrad kvfree(parser->chunks[i].kdata); 469 1.1 riastrad kfree(parser->chunks); 470 1.1 riastrad kfree(parser->chunks_array); 471 1.1 riastrad radeon_ib_free(parser->rdev, &parser->ib); 472 1.1 riastrad radeon_ib_free(parser->rdev, &parser->const_ib); 473 1.1 riastrad } 474 1.1 riastrad 475 1.1 riastrad static int radeon_cs_ib_chunk(struct radeon_device *rdev, 476 1.1 riastrad struct radeon_cs_parser *parser) 477 1.1 riastrad { 478 1.1 riastrad int r; 479 1.1 riastrad 480 1.2 riastrad if (parser->chunk_ib == NULL) 481 1.1 riastrad return 0; 482 1.1 riastrad 483 1.1 riastrad if (parser->cs_flags & RADEON_CS_USE_VM) 484 1.1 riastrad return 0; 485 1.1 riastrad 486 1.1 riastrad r = radeon_cs_parse(rdev, parser->ring, parser); 487 1.1 riastrad if (r || parser->parser_error) { 488 1.1 riastrad DRM_ERROR("Invalid command stream !\n"); 489 1.1 riastrad return r; 490 1.1 riastrad } 491 1.1 riastrad 492 1.2 riastrad r = radeon_cs_sync_rings(parser); 493 1.2 riastrad if (r) { 494 1.2 riastrad if (r != -ERESTARTSYS) 495 1.2 riastrad DRM_ERROR("Failed to sync rings: %i\n", r); 496 1.2 riastrad return r; 497 1.2 riastrad } 498 1.2 riastrad 499 1.1 riastrad if (parser->ring == R600_RING_TYPE_UVD_INDEX) 500 1.1 riastrad radeon_uvd_note_usage(rdev); 501 1.1 riastrad else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) || 502 1.1 riastrad (parser->ring == TN_RING_TYPE_VCE2_INDEX)) 503 1.1 riastrad radeon_vce_note_usage(rdev); 504 1.1 riastrad 505 1.2 riastrad r = radeon_ib_schedule(rdev, &parser->ib, NULL, true); 506 1.1 riastrad if (r) { 507 1.1 riastrad DRM_ERROR("Failed to schedule IB !\n"); 508 1.1 riastrad } 509 1.1 riastrad return r; 510 1.1 riastrad } 511 1.1 riastrad 512 1.1 riastrad static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p, 513 1.1 riastrad struct radeon_vm *vm) 514 1.1 riastrad { 515 1.1 riastrad struct radeon_device *rdev = p->rdev; 516 1.2 riastrad struct radeon_bo_va *bo_va; 517 1.1 riastrad int i, r; 518 1.1 riastrad 519 1.1 riastrad r = radeon_vm_update_page_directory(rdev, vm); 520 1.1 riastrad if (r) 521 1.1 riastrad return r; 522 1.1 riastrad 523 1.2 riastrad r = radeon_vm_clear_freed(rdev, vm); 524 1.2 riastrad if (r) 525 1.2 riastrad return r; 526 1.2 riastrad 527 1.2 riastrad if (vm->ib_bo_va == NULL) { 528 1.2 riastrad DRM_ERROR("Tmp BO not in VM!\n"); 529 1.2 riastrad return -EINVAL; 530 1.2 riastrad } 531 1.2 riastrad 532 1.2 riastrad r = radeon_vm_bo_update(rdev, vm->ib_bo_va, 533 1.1 riastrad &rdev->ring_tmp_bo.bo->tbo.mem); 534 1.1 riastrad if (r) 535 1.1 riastrad return r; 536 1.1 riastrad 537 1.1 riastrad for (i = 0; i < p->nrelocs; i++) { 538 1.1 riastrad struct radeon_bo *bo; 539 1.1 riastrad 540 1.2 riastrad bo = p->relocs[i].robj; 541 1.2 riastrad bo_va = radeon_vm_bo_find(vm, bo); 542 1.2 riastrad if (bo_va == NULL) { 543 1.2 riastrad dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm); 544 1.2 riastrad return -EINVAL; 545 1.2 riastrad } 546 1.1 riastrad 547 1.2 riastrad r = radeon_vm_bo_update(rdev, bo_va, &bo->tbo.mem); 548 1.1 riastrad if (r) 549 1.1 riastrad return r; 550 1.2 riastrad 551 1.2 riastrad radeon_sync_fence(&p->ib.sync, bo_va->last_pt_update); 552 1.1 riastrad } 553 1.2 riastrad 554 1.2 riastrad return radeon_vm_clear_invalids(rdev, vm); 555 1.1 riastrad } 556 1.1 riastrad 557 1.1 riastrad static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev, 558 1.1 riastrad struct radeon_cs_parser *parser) 559 1.1 riastrad { 560 1.1 riastrad struct radeon_fpriv *fpriv = parser->filp->driver_priv; 561 1.1 riastrad struct radeon_vm *vm = &fpriv->vm; 562 1.1 riastrad int r; 563 1.1 riastrad 564 1.2 riastrad if (parser->chunk_ib == NULL) 565 1.1 riastrad return 0; 566 1.1 riastrad if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) 567 1.1 riastrad return 0; 568 1.1 riastrad 569 1.1 riastrad if (parser->const_ib.length_dw) { 570 1.1 riastrad r = radeon_ring_ib_parse(rdev, parser->ring, &parser->const_ib); 571 1.1 riastrad if (r) { 572 1.1 riastrad return r; 573 1.1 riastrad } 574 1.1 riastrad } 575 1.1 riastrad 576 1.1 riastrad r = radeon_ring_ib_parse(rdev, parser->ring, &parser->ib); 577 1.1 riastrad if (r) { 578 1.1 riastrad return r; 579 1.1 riastrad } 580 1.1 riastrad 581 1.1 riastrad if (parser->ring == R600_RING_TYPE_UVD_INDEX) 582 1.1 riastrad radeon_uvd_note_usage(rdev); 583 1.1 riastrad 584 1.1 riastrad mutex_lock(&vm->mutex); 585 1.1 riastrad r = radeon_bo_vm_update_pte(parser, vm); 586 1.1 riastrad if (r) { 587 1.1 riastrad goto out; 588 1.1 riastrad } 589 1.2 riastrad 590 1.2 riastrad r = radeon_cs_sync_rings(parser); 591 1.2 riastrad if (r) { 592 1.2 riastrad if (r != -ERESTARTSYS) 593 1.2 riastrad DRM_ERROR("Failed to sync rings: %i\n", r); 594 1.2 riastrad goto out; 595 1.2 riastrad } 596 1.1 riastrad 597 1.1 riastrad if ((rdev->family >= CHIP_TAHITI) && 598 1.2 riastrad (parser->chunk_const_ib != NULL)) { 599 1.2 riastrad r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib, true); 600 1.1 riastrad } else { 601 1.2 riastrad r = radeon_ib_schedule(rdev, &parser->ib, NULL, true); 602 1.1 riastrad } 603 1.1 riastrad 604 1.1 riastrad out: 605 1.1 riastrad mutex_unlock(&vm->mutex); 606 1.1 riastrad return r; 607 1.1 riastrad } 608 1.1 riastrad 609 1.1 riastrad static int radeon_cs_handle_lockup(struct radeon_device *rdev, int r) 610 1.1 riastrad { 611 1.1 riastrad if (r == -EDEADLK) { 612 1.1 riastrad r = radeon_gpu_reset(rdev); 613 1.1 riastrad if (!r) 614 1.1 riastrad r = -EAGAIN; 615 1.1 riastrad } 616 1.1 riastrad return r; 617 1.1 riastrad } 618 1.1 riastrad 619 1.1 riastrad static int radeon_cs_ib_fill(struct radeon_device *rdev, struct radeon_cs_parser *parser) 620 1.1 riastrad { 621 1.1 riastrad struct radeon_cs_chunk *ib_chunk; 622 1.1 riastrad struct radeon_vm *vm = NULL; 623 1.1 riastrad int r; 624 1.1 riastrad 625 1.2 riastrad if (parser->chunk_ib == NULL) 626 1.1 riastrad return 0; 627 1.1 riastrad 628 1.1 riastrad if (parser->cs_flags & RADEON_CS_USE_VM) { 629 1.1 riastrad struct radeon_fpriv *fpriv = parser->filp->driver_priv; 630 1.1 riastrad vm = &fpriv->vm; 631 1.1 riastrad 632 1.1 riastrad if ((rdev->family >= CHIP_TAHITI) && 633 1.2 riastrad (parser->chunk_const_ib != NULL)) { 634 1.2 riastrad ib_chunk = parser->chunk_const_ib; 635 1.1 riastrad if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) { 636 1.1 riastrad DRM_ERROR("cs IB CONST too big: %d\n", ib_chunk->length_dw); 637 1.1 riastrad return -EINVAL; 638 1.1 riastrad } 639 1.1 riastrad r = radeon_ib_get(rdev, parser->ring, &parser->const_ib, 640 1.1 riastrad vm, ib_chunk->length_dw * 4); 641 1.1 riastrad if (r) { 642 1.1 riastrad DRM_ERROR("Failed to get const ib !\n"); 643 1.1 riastrad return r; 644 1.1 riastrad } 645 1.1 riastrad parser->const_ib.is_const_ib = true; 646 1.1 riastrad parser->const_ib.length_dw = ib_chunk->length_dw; 647 1.1 riastrad if (copy_from_user(parser->const_ib.ptr, 648 1.1 riastrad ib_chunk->user_ptr, 649 1.1 riastrad ib_chunk->length_dw * 4)) 650 1.1 riastrad return -EFAULT; 651 1.1 riastrad } 652 1.1 riastrad 653 1.2 riastrad ib_chunk = parser->chunk_ib; 654 1.1 riastrad if (ib_chunk->length_dw > RADEON_IB_VM_MAX_SIZE) { 655 1.1 riastrad DRM_ERROR("cs IB too big: %d\n", ib_chunk->length_dw); 656 1.1 riastrad return -EINVAL; 657 1.1 riastrad } 658 1.1 riastrad } 659 1.2 riastrad ib_chunk = parser->chunk_ib; 660 1.1 riastrad 661 1.1 riastrad r = radeon_ib_get(rdev, parser->ring, &parser->ib, 662 1.1 riastrad vm, ib_chunk->length_dw * 4); 663 1.1 riastrad if (r) { 664 1.1 riastrad DRM_ERROR("Failed to get ib !\n"); 665 1.1 riastrad return r; 666 1.1 riastrad } 667 1.1 riastrad parser->ib.length_dw = ib_chunk->length_dw; 668 1.1 riastrad if (ib_chunk->kdata) 669 1.1 riastrad memcpy(parser->ib.ptr, ib_chunk->kdata, ib_chunk->length_dw * 4); 670 1.1 riastrad else if (copy_from_user(parser->ib.ptr, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) 671 1.1 riastrad return -EFAULT; 672 1.1 riastrad return 0; 673 1.1 riastrad } 674 1.1 riastrad 675 1.1 riastrad int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) 676 1.1 riastrad { 677 1.1 riastrad struct radeon_device *rdev = dev->dev_private; 678 1.1 riastrad struct radeon_cs_parser parser; 679 1.1 riastrad int r; 680 1.1 riastrad 681 1.1 riastrad down_read(&rdev->exclusive_lock); 682 1.1 riastrad if (!rdev->accel_working) { 683 1.1 riastrad up_read(&rdev->exclusive_lock); 684 1.1 riastrad return -EBUSY; 685 1.1 riastrad } 686 1.2 riastrad if (rdev->in_reset) { 687 1.2 riastrad up_read(&rdev->exclusive_lock); 688 1.2 riastrad r = radeon_gpu_reset(rdev); 689 1.2 riastrad if (!r) 690 1.2 riastrad r = -EAGAIN; 691 1.2 riastrad return r; 692 1.2 riastrad } 693 1.1 riastrad /* initialize parser */ 694 1.1 riastrad memset(&parser, 0, sizeof(struct radeon_cs_parser)); 695 1.1 riastrad parser.filp = filp; 696 1.1 riastrad parser.rdev = rdev; 697 1.1 riastrad parser.dev = rdev->dev; 698 1.1 riastrad parser.family = rdev->family; 699 1.1 riastrad r = radeon_cs_parser_init(&parser, data); 700 1.1 riastrad if (r) { 701 1.1 riastrad DRM_ERROR("Failed to initialize parser !\n"); 702 1.1 riastrad radeon_cs_parser_fini(&parser, r, false); 703 1.1 riastrad up_read(&rdev->exclusive_lock); 704 1.1 riastrad r = radeon_cs_handle_lockup(rdev, r); 705 1.1 riastrad return r; 706 1.1 riastrad } 707 1.1 riastrad 708 1.1 riastrad r = radeon_cs_ib_fill(rdev, &parser); 709 1.1 riastrad if (!r) { 710 1.1 riastrad r = radeon_cs_parser_relocs(&parser); 711 1.1 riastrad if (r && r != -ERESTARTSYS) 712 1.1 riastrad DRM_ERROR("Failed to parse relocation %d!\n", r); 713 1.1 riastrad } 714 1.1 riastrad 715 1.1 riastrad if (r) { 716 1.1 riastrad radeon_cs_parser_fini(&parser, r, false); 717 1.1 riastrad up_read(&rdev->exclusive_lock); 718 1.1 riastrad r = radeon_cs_handle_lockup(rdev, r); 719 1.1 riastrad return r; 720 1.1 riastrad } 721 1.1 riastrad 722 1.1 riastrad trace_radeon_cs(&parser); 723 1.1 riastrad 724 1.1 riastrad r = radeon_cs_ib_chunk(rdev, &parser); 725 1.1 riastrad if (r) { 726 1.1 riastrad goto out; 727 1.1 riastrad } 728 1.1 riastrad r = radeon_cs_ib_vm_chunk(rdev, &parser); 729 1.1 riastrad if (r) { 730 1.1 riastrad goto out; 731 1.1 riastrad } 732 1.1 riastrad out: 733 1.1 riastrad radeon_cs_parser_fini(&parser, r, true); 734 1.1 riastrad up_read(&rdev->exclusive_lock); 735 1.1 riastrad r = radeon_cs_handle_lockup(rdev, r); 736 1.1 riastrad return r; 737 1.1 riastrad } 738 1.1 riastrad 739 1.1 riastrad /** 740 1.1 riastrad * radeon_cs_packet_parse() - parse cp packet and point ib index to next packet 741 1.1 riastrad * @parser: parser structure holding parsing context. 742 1.1 riastrad * @pkt: where to store packet information 743 1.1 riastrad * 744 1.1 riastrad * Assume that chunk_ib_index is properly set. Will return -EINVAL 745 1.1 riastrad * if packet is bigger than remaining ib size. or if packets is unknown. 746 1.1 riastrad **/ 747 1.1 riastrad int radeon_cs_packet_parse(struct radeon_cs_parser *p, 748 1.1 riastrad struct radeon_cs_packet *pkt, 749 1.1 riastrad unsigned idx) 750 1.1 riastrad { 751 1.2 riastrad struct radeon_cs_chunk *ib_chunk = p->chunk_ib; 752 1.1 riastrad struct radeon_device *rdev = p->rdev; 753 1.1 riastrad uint32_t header; 754 1.2 riastrad int ret = 0, i; 755 1.1 riastrad 756 1.1 riastrad if (idx >= ib_chunk->length_dw) { 757 1.1 riastrad DRM_ERROR("Can not parse packet at %d after CS end %d !\n", 758 1.1 riastrad idx, ib_chunk->length_dw); 759 1.1 riastrad return -EINVAL; 760 1.1 riastrad } 761 1.1 riastrad header = radeon_get_ib_value(p, idx); 762 1.1 riastrad pkt->idx = idx; 763 1.1 riastrad pkt->type = RADEON_CP_PACKET_GET_TYPE(header); 764 1.1 riastrad pkt->count = RADEON_CP_PACKET_GET_COUNT(header); 765 1.1 riastrad pkt->one_reg_wr = 0; 766 1.1 riastrad switch (pkt->type) { 767 1.1 riastrad case RADEON_PACKET_TYPE0: 768 1.1 riastrad if (rdev->family < CHIP_R600) { 769 1.1 riastrad pkt->reg = R100_CP_PACKET0_GET_REG(header); 770 1.1 riastrad pkt->one_reg_wr = 771 1.1 riastrad RADEON_CP_PACKET0_GET_ONE_REG_WR(header); 772 1.1 riastrad } else 773 1.1 riastrad pkt->reg = R600_CP_PACKET0_GET_REG(header); 774 1.1 riastrad break; 775 1.1 riastrad case RADEON_PACKET_TYPE3: 776 1.1 riastrad pkt->opcode = RADEON_CP_PACKET3_GET_OPCODE(header); 777 1.1 riastrad break; 778 1.1 riastrad case RADEON_PACKET_TYPE2: 779 1.1 riastrad pkt->count = -1; 780 1.1 riastrad break; 781 1.1 riastrad default: 782 1.1 riastrad DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); 783 1.2 riastrad ret = -EINVAL; 784 1.2 riastrad goto dump_ib; 785 1.1 riastrad } 786 1.1 riastrad if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { 787 1.1 riastrad DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", 788 1.1 riastrad pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); 789 1.2 riastrad ret = -EINVAL; 790 1.2 riastrad goto dump_ib; 791 1.1 riastrad } 792 1.1 riastrad return 0; 793 1.2 riastrad 794 1.2 riastrad dump_ib: 795 1.2 riastrad for (i = 0; i < ib_chunk->length_dw; i++) { 796 1.2 riastrad if (i == idx) 797 1.2 riastrad printk("\t0x%08x <---\n", radeon_get_ib_value(p, i)); 798 1.2 riastrad else 799 1.2 riastrad printk("\t0x%08x\n", radeon_get_ib_value(p, i)); 800 1.2 riastrad } 801 1.2 riastrad return ret; 802 1.1 riastrad } 803 1.1 riastrad 804 1.1 riastrad /** 805 1.1 riastrad * radeon_cs_packet_next_is_pkt3_nop() - test if the next packet is P3 NOP 806 1.1 riastrad * @p: structure holding the parser context. 807 1.1 riastrad * 808 1.1 riastrad * Check if the next packet is NOP relocation packet3. 809 1.1 riastrad **/ 810 1.1 riastrad bool radeon_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) 811 1.1 riastrad { 812 1.1 riastrad struct radeon_cs_packet p3reloc; 813 1.1 riastrad int r; 814 1.1 riastrad 815 1.1 riastrad r = radeon_cs_packet_parse(p, &p3reloc, p->idx); 816 1.1 riastrad if (r) 817 1.1 riastrad return false; 818 1.1 riastrad if (p3reloc.type != RADEON_PACKET_TYPE3) 819 1.1 riastrad return false; 820 1.1 riastrad if (p3reloc.opcode != RADEON_PACKET3_NOP) 821 1.1 riastrad return false; 822 1.1 riastrad return true; 823 1.1 riastrad } 824 1.1 riastrad 825 1.1 riastrad /** 826 1.1 riastrad * radeon_cs_dump_packet() - dump raw packet context 827 1.1 riastrad * @p: structure holding the parser context. 828 1.1 riastrad * @pkt: structure holding the packet. 829 1.1 riastrad * 830 1.1 riastrad * Used mostly for debugging and error reporting. 831 1.1 riastrad **/ 832 1.1 riastrad void radeon_cs_dump_packet(struct radeon_cs_parser *p, 833 1.1 riastrad struct radeon_cs_packet *pkt) 834 1.1 riastrad { 835 1.1 riastrad volatile uint32_t *ib; 836 1.1 riastrad unsigned i; 837 1.1 riastrad unsigned idx; 838 1.1 riastrad 839 1.1 riastrad ib = p->ib.ptr; 840 1.1 riastrad idx = pkt->idx; 841 1.1 riastrad for (i = 0; i <= (pkt->count + 1); i++, idx++) 842 1.1 riastrad DRM_INFO("ib[%d]=0x%08X\n", idx, ib[idx]); 843 1.1 riastrad } 844 1.1 riastrad 845 1.1 riastrad /** 846 1.1 riastrad * radeon_cs_packet_next_reloc() - parse next (should be reloc) packet 847 1.1 riastrad * @parser: parser structure holding parsing context. 848 1.1 riastrad * @data: pointer to relocation data 849 1.1 riastrad * @offset_start: starting offset 850 1.1 riastrad * @offset_mask: offset mask (to align start offset on) 851 1.1 riastrad * @reloc: reloc informations 852 1.1 riastrad * 853 1.1 riastrad * Check if next packet is relocation packet3, do bo validation and compute 854 1.1 riastrad * GPU offset using the provided start. 855 1.1 riastrad **/ 856 1.1 riastrad int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p, 857 1.2 riastrad struct radeon_bo_list **cs_reloc, 858 1.1 riastrad int nomm) 859 1.1 riastrad { 860 1.1 riastrad struct radeon_cs_chunk *relocs_chunk; 861 1.1 riastrad struct radeon_cs_packet p3reloc; 862 1.1 riastrad unsigned idx; 863 1.1 riastrad int r; 864 1.1 riastrad 865 1.2 riastrad if (p->chunk_relocs == NULL) { 866 1.1 riastrad DRM_ERROR("No relocation chunk !\n"); 867 1.1 riastrad return -EINVAL; 868 1.1 riastrad } 869 1.1 riastrad *cs_reloc = NULL; 870 1.2 riastrad relocs_chunk = p->chunk_relocs; 871 1.1 riastrad r = radeon_cs_packet_parse(p, &p3reloc, p->idx); 872 1.1 riastrad if (r) 873 1.1 riastrad return r; 874 1.1 riastrad p->idx += p3reloc.count + 2; 875 1.1 riastrad if (p3reloc.type != RADEON_PACKET_TYPE3 || 876 1.1 riastrad p3reloc.opcode != RADEON_PACKET3_NOP) { 877 1.1 riastrad DRM_ERROR("No packet3 for relocation for packet at %d.\n", 878 1.1 riastrad p3reloc.idx); 879 1.1 riastrad radeon_cs_dump_packet(p, &p3reloc); 880 1.1 riastrad return -EINVAL; 881 1.1 riastrad } 882 1.1 riastrad idx = radeon_get_ib_value(p, p3reloc.idx + 1); 883 1.1 riastrad if (idx >= relocs_chunk->length_dw) { 884 1.1 riastrad DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 885 1.1 riastrad idx, relocs_chunk->length_dw); 886 1.1 riastrad radeon_cs_dump_packet(p, &p3reloc); 887 1.1 riastrad return -EINVAL; 888 1.1 riastrad } 889 1.1 riastrad /* FIXME: we assume reloc size is 4 dwords */ 890 1.1 riastrad if (nomm) { 891 1.1 riastrad *cs_reloc = p->relocs; 892 1.1 riastrad (*cs_reloc)->gpu_offset = 893 1.1 riastrad (u64)relocs_chunk->kdata[idx + 3] << 32; 894 1.1 riastrad (*cs_reloc)->gpu_offset |= relocs_chunk->kdata[idx + 0]; 895 1.1 riastrad } else 896 1.2 riastrad *cs_reloc = &p->relocs[(idx / 4)]; 897 1.1 riastrad return 0; 898 1.1 riastrad } 899