/* This is based on the bucket sort with O(n) time complexity. *Anitemwithpriority"i"isaddedtobucket[i].Thelistsarethen *concatenatedindescendingorder.
*/ struct radeon_cs_buckets { struct list_head bucket[RADEON_CS_NUM_BUCKETS];
};
for (i = 0; i < RADEON_CS_NUM_BUCKETS; i++)
INIT_LIST_HEAD(&b->bucket[i]);
}
staticvoid radeon_cs_buckets_add(struct radeon_cs_buckets *b, struct list_head *item, unsigned priority)
{ /* Since buffers which appear sooner in the relocation list are *likelytobeusedmoreoftenthanbufferswhichappearlater *inthelist,thesortmustn'tchangetheorderingofbuffers *withthesamepriority,i.e.itmustbestable.
*/
list_add_tail(item, &b->bucket[min(priority, RADEON_CS_MAX_PRIORITY)]);
}
/* The userspace buffer priorities are from 0 to 15. A higher *numbermeansthebufferismoreimportant. *Also,thebuffersusedforwritehaveahigherprioritythan *thebuffersusedforreadonly,whichdoublestherange *to0to31.32isreservedforthekerneldriver.
*/
priority = (r->flags & RADEON_RELOC_PRIO_MASK) * 2
+ !!r->write_domain;
/* The first reloc of an UVD job is the msg and that must be in *VRAM,thesecondrelocistheDPBandforWMVthatmustbein *VRAMaswell.AlsoputeverythingintoVRAMonAGPcardsandolder *IGPchipstoavoidimagecorruptions
*/ if (p->ring == R600_RING_TYPE_UVD_INDEX &&
(i <= 0 || pci_find_capability(p->rdev->pdev, PCI_CAP_ID_AGP) ||
p->rdev->family == CHIP_RS780 ||
p->rdev->family == CHIP_RS880)) {
/* TODO: is this still needed for NI+ ? */
p->relocs[i].preferred_domains =
RADEON_GEM_DOMAIN_VRAM;
if (radeon_ttm_tt_has_userptr(p->rdev, p->relocs[i].robj->tbo.ttm)) {
uint32_t domain = p->relocs[i].preferred_domains; if (!(domain & RADEON_GEM_DOMAIN_GTT)) {
DRM_ERROR("Only RADEON_GEM_DOMAIN_GTT is " "allowed for userptr BOs\n"); return -EINVAL;
}
need_mmap_lock = true;
domain = RADEON_GEM_DOMAIN_GTT;
p->relocs[i].preferred_domains = domain;
p->relocs[i].allowed_domains = domain;
}
/* Objects shared as dma-bufs cannot be moved to VRAM */ if (p->relocs[i].robj->prime_shared_count) {
p->relocs[i].allowed_domains &= ~RADEON_GEM_DOMAIN_VRAM; if (!p->relocs[i].allowed_domains) {
DRM_ERROR("BO associated with dma-buf cannot " "be moved to VRAM\n"); return -EINVAL;
}
}
resv = reloc->robj->tbo.base.resv;
r = radeon_sync_resv(p->rdev, &p->ib.sync, resv, reloc->shared); if (r) return r;
} return0;
}
/* XXX: note that this is called from the legacy UMS CS ioctl as well */ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
{ struct drm_radeon_cs *cs = data;
uint64_t *chunk_array_ptr;
u64 size; unsigned i;
u32 ring = RADEON_CS_RING_GFX;
s32 priority = 0;
if (user_chunk.chunk_id == RADEON_CHUNK_ID_IB) { if (!p->rdev || !(p->rdev->flags & RADEON_IS_AGP)) continue;
}
p->chunks[i].kdata = kvmalloc_array(size, sizeof(uint32_t), GFP_KERNEL);
size *= sizeof(uint32_t); if (p->chunks[i].kdata == NULL) { return -ENOMEM;
} if (copy_from_user(p->chunks[i].kdata, cdata, size)) { return -EFAULT;
} if (user_chunk.chunk_id == RADEON_CHUNK_ID_FLAGS) {
p->cs_flags = p->chunks[i].kdata[0]; if (p->chunks[i].length_dw > 1)
ring = p->chunks[i].kdata[1]; if (p->chunks[i].length_dw > 2)
priority = (s32)p->chunks[i].kdata[2];
}
}
/* these are KMS only */ if (p->rdev) { if ((p->cs_flags & RADEON_CS_USE_VM) &&
!p->rdev->vm_manager.enabled) {
DRM_ERROR("VM not active on asic!\n"); return -EINVAL;
}
if (radeon_cs_get_ring(p, ring, priority)) return -EINVAL;
/* we only support VM on some SI+ rings */ if ((p->cs_flags & RADEON_CS_USE_VM) == 0) { if (p->rdev->asic->ring[p->ring]->cs_parse == NULL) {
DRM_ERROR("Ring %d requires VM!\n", p->ring); return -EINVAL;
}
} else { if (p->rdev->asic->ring[p->ring]->ib_parse == NULL) {
DRM_ERROR("VM not supported on ring %d!\n",
p->ring); return -EINVAL;
}
}
}
/* Sort A before B if A is smaller. */ if (la->robj->tbo.base.size > lb->robj->tbo.base.size) return1; if (la->robj->tbo.base.size < lb->robj->tbo.base.size) return -1; return0;
}
if (parser->chunk_ib == NULL) return0; if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) return0;
if (parser->const_ib.length_dw) {
r = radeon_ring_ib_parse(rdev, parser->ring, &parser->const_ib); if (r) { return r;
}
}
r = radeon_ring_ib_parse(rdev, parser->ring, &parser->ib); if (r) { return r;
}
if (parser->ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_note_usage(rdev);
mutex_lock(&vm->mutex);
r = radeon_bo_vm_update_pte(parser, vm); if (r) { goto out;
}
r = radeon_cs_sync_rings(parser); if (r) { if (r != -ERESTARTSYS)
DRM_ERROR("Failed to sync rings: %i\n", r); goto out;
}
if ((rdev->family >= CHIP_TAHITI) &&
(parser->chunk_const_ib != NULL)) {
r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib, true);
} else {
r = radeon_ib_schedule(rdev, &parser->ib, NULL, true);
}
out:
mutex_unlock(&vm->mutex); return r;
}
staticint radeon_cs_handle_lockup(struct radeon_device *rdev, int r)
{ if (r == -EDEADLK) {
r = radeon_gpu_reset(rdev); if (!r)
r = -EAGAIN;
} return r;
}
r = radeon_ib_get(rdev, parser->ring, &parser->ib,
vm, ib_chunk->length_dw * 4); if (r) {
DRM_ERROR("Failed to get ib !\n"); return r;
}
parser->ib.length_dw = ib_chunk->length_dw; if (ib_chunk->kdata)
memcpy(parser->ib.ptr, ib_chunk->kdata, ib_chunk->length_dw * 4); elseif (copy_from_user(parser->ib.ptr, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) return -EFAULT; return0;
}
int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{ struct radeon_device *rdev = dev->dev_private; struct radeon_cs_parser parser; int r;
down_read(&rdev->exclusive_lock); if (!rdev->accel_working) {
up_read(&rdev->exclusive_lock); return -EBUSY;
} if (rdev->in_reset) {
up_read(&rdev->exclusive_lock);
r = radeon_gpu_reset(rdev); if (!r)
r = -EAGAIN; return r;
} /* initialize parser */
memset(&parser, 0, sizeof(struct radeon_cs_parser));
parser.filp = filp;
parser.rdev = rdev;
parser.dev = rdev->dev;
parser.family = rdev->family;
r = radeon_cs_parser_init(&parser, data); if (r) {
DRM_ERROR("Failed to initialize parser !\n");
radeon_cs_parser_fini(&parser, r);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r); return r;
}
r = radeon_cs_ib_fill(rdev, &parser); if (!r) {
r = radeon_cs_parser_relocs(&parser); if (r && r != -ERESTARTSYS)
DRM_ERROR("Failed to parse relocation %d!\n", r);
}
if (r) {
radeon_cs_parser_fini(&parser, r);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r); return r;
}
trace_radeon_cs(&parser);
r = radeon_cs_ib_chunk(rdev, &parser); if (r) { goto out;
}
r = radeon_cs_ib_vm_chunk(rdev, &parser); if (r) { goto out;
}
out:
radeon_cs_parser_fini(&parser, r);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r); return r;
}
r = radeon_cs_packet_parse(p, &p3reloc, p->idx); if (r) returnfalse; if (p3reloc.type != RADEON_PACKET_TYPE3) returnfalse; if (p3reloc.opcode != RADEON_PACKET3_NOP) returnfalse; returntrue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.