/** * cik_sdma_ib_test - test an IB on the DMA engine * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information * * Test a simple IB in the DMA ring (CIK). * Returns 0 on success, error on failure. */ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) { struct radeon_ib ib; unsigned i; unsigned index; int r; u32 tmp = 0; u64 gpu_addr; if (ring->idx == R600_RING_TYPE_DMA_INDEX) index = R600_WB_DMA_RING_TEST_OFFSET; else index = CAYMAN_WB_DMA1_RING_TEST_OFFSET; gpu_addr = rdev->wb.gpu_addr + index; tmp = 0xCAFEDEAD; rdev->wb.wb[index/4] = cpu_to_le32(tmp); r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); if (r) { DRM_ERROR("radeon: failed to get ib (%d).\n", r); return r; } ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0); ib.ptr[1] = lower_32_bits(gpu_addr); ib.ptr[2] = upper_32_bits(gpu_addr); ib.ptr[3] = 1; ib.ptr[4] = 0xDEADBEEF; ib.length_dw = 5; r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { radeon_ib_free(rdev, &ib); DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); return r; } r = radeon_fence_wait(ib.fence, false); if (r) { DRM_ERROR("radeon: fence wait failed (%d).\n", r); return r; } for (i = 0; i < rdev->usec_timeout; i++) { tmp = le32_to_cpu(rdev->wb.wb[index/4]); if (tmp == 0xDEADBEEF) break; DRM_UDELAY(1); } if (i < rdev->usec_timeout) { DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i); } else { DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp); r = -EINVAL; } radeon_ib_free(rdev, &ib); return r; }
/** * cik_sdma_ib_test - test an IB on the DMA engine * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information * * Test a simple IB in the DMA ring (CIK). * Returns 0 on success, error on failure. */ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) { struct radeon_ib ib; unsigned i; int r; void __iomem *ptr = (void *)rdev->vram_scratch.ptr; u32 tmp = 0; if (!ptr) { DRM_ERROR("invalid vram scratch pointer\n"); return -EINVAL; } tmp = 0xCAFEDEAD; writel(tmp, ptr); r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256); if (r) { DRM_ERROR("radeon: failed to get ib (%d).\n", r); return r; } ib.ptr[0] = SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0); ib.ptr[1] = rdev->vram_scratch.gpu_addr & 0xfffffffc; ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr); ib.ptr[3] = 1; ib.ptr[4] = 0xDEADBEEF; ib.length_dw = 5; r = radeon_ib_schedule(rdev, &ib, NULL); if (r) { radeon_ib_free(rdev, &ib); DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); return r; } r = radeon_fence_wait(ib.fence, false); if (r) { DRM_ERROR("radeon: fence wait failed (%d).\n", r); return r; } for (i = 0; i < rdev->usec_timeout; i++) { tmp = readl(ptr); if (tmp == 0xDEADBEEF) break; DRM_UDELAY(1); } if (i < rdev->usec_timeout) { DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i); } else { DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp); r = -EINVAL; } radeon_ib_free(rdev, &ib); return r; }
/** * cs_parser_fini() - clean parser states * @parser: parser structure holding parsing context. * @error: error number * * If error is set than unvalidate buffer, otherwise just free memory * used by parsing context. **/ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) { unsigned i; if (!error && parser->ib) ttm_eu_fence_buffer_objects(&parser->validated, parser->ib->fence); else ttm_eu_backoff_reservation(&parser->validated); if (parser->relocs != NULL) { for (i = 0; i < parser->nrelocs; i++) { if (parser->relocs[i].gobj) drm_gem_object_unreference_unlocked(parser->relocs[i].gobj); } } kfree(parser->track); kfree(parser->relocs); kfree(parser->relocs_ptr); for (i = 0; i < parser->nchunks; i++) { kfree(parser->chunks[i].kdata); kfree(parser->chunks[i].kpage[0]); kfree(parser->chunks[i].kpage[1]); } kfree(parser->chunks); kfree(parser->chunks_array); radeon_ib_free(parser->rdev, &parser->ib); }
/** * cs_parser_fini() - clean parser states * @parser: parser structure holding parsing context. * @error: error number * * If error is set than unvalidate buffer, otherwise just free memory * used by parsing context. **/ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error) { unsigned i; if (error) { radeon_object_list_unvalidate(&parser->validated); } else { radeon_object_list_clean(&parser->validated); } for (i = 0; i < parser->nrelocs; i++) { if (parser->relocs[i].gobj) { mutex_lock(&parser->rdev->ddev->struct_mutex); drm_gem_object_unreference(parser->relocs[i].gobj); mutex_unlock(&parser->rdev->ddev->struct_mutex); } } kfree(parser->track); kfree(parser->relocs); kfree(parser->relocs_ptr); for (i = 0; i < parser->nchunks; i++) { kfree(parser->chunks[i].kdata); kfree(parser->chunks[i].kpage[0]); kfree(parser->chunks[i].kpage[1]); } kfree(parser->chunks); kfree(parser->chunks_array); radeon_ib_free(parser->rdev, &parser->ib); }
/** * radeon_vce_get_create_msg - generate a VCE create msg * * @rdev: radeon_device pointer * @ring: ring we should submit the msg to * @handle: VCE session handle to use * @fence: optional fence to return * * Open up a stream for HW test */ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence) { const unsigned ib_size_dw = 1024; struct radeon_ib ib; uint64_t dummy; int i, r; r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); if (r) { DRM_ERROR("radeon: failed to get ib (%d).\n", r); return r; } dummy = ib.gpu_addr + 1024; /* stitch together an VCE create msg */ ib.length_dw = 0; ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ ib.ptr[ib.length_dw++] = handle; ib.ptr[ib.length_dw++] = 0x00000030; /* len */ ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ ib.ptr[ib.length_dw++] = 0x00000000; ib.ptr[ib.length_dw++] = 0x00000042; ib.ptr[ib.length_dw++] = 0x0000000a; ib.ptr[ib.length_dw++] = 0x00000001; ib.ptr[ib.length_dw++] = 0x00000080; ib.ptr[ib.length_dw++] = 0x00000060; ib.ptr[ib.length_dw++] = 0x00000100; ib.ptr[ib.length_dw++] = 0x00000100; ib.ptr[ib.length_dw++] = 0x0000000c; ib.ptr[ib.length_dw++] = 0x00000000; ib.ptr[ib.length_dw++] = 0x00000014; /* len */ ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ ib.ptr[ib.length_dw++] = upper_32_bits(dummy); ib.ptr[ib.length_dw++] = dummy; ib.ptr[ib.length_dw++] = 0x00000001; for (i = ib.length_dw; i < ib_size_dw; ++i) ib.ptr[i] = 0x0; r = radeon_ib_schedule(rdev, &ib, NULL); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); } if (fence) *fence = radeon_fence_ref(ib.fence); radeon_ib_free(rdev, &ib); return r; }
/** * cs_parser_fini() - clean parser states * @parser: parser structure holding parsing context. * @error: error number * * If error is set than unvalidate buffer, otherwise just free memory * used by parsing context. **/ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bool backoff) { unsigned i; if (!error) { /* Sort the buffer list from the smallest to largest buffer, * which affects the order of buffers in the LRU list. * This assures that the smallest buffers are added first * to the LRU list, so they are likely to be later evicted * first, instead of large buffers whose eviction is more * expensive. * * This slightly lowers the number of bytes moved by TTM * per frame under memory pressure. */ list_sort(NULL, &parser->validated, cmp_size_smaller_first); ttm_eu_fence_buffer_objects(&parser->ticket, &parser->validated, parser->ib.fence); } else if (backoff) { ttm_eu_backoff_reservation(&parser->ticket, &parser->validated); } if (parser->relocs != NULL) { for (i = 0; i < parser->nrelocs; i++) { if (parser->relocs[i].gobj) drm_gem_object_unreference_unlocked(parser->relocs[i].gobj); } } kfree(parser->track); kfree(parser->relocs); kfree(parser->relocs_ptr); kfree(parser->vm_bos); for (i = 0; i < parser->nchunks; i++) drm_free_large(parser->chunks[i].kdata); kfree(parser->chunks); kfree(parser->chunks_array); radeon_ib_free(parser->rdev, &parser->ib); radeon_ib_free(parser->rdev, &parser->const_ib); }
/** * radeon_vce_get_destroy_msg - generate a VCE destroy msg * * @rdev: radeon_device pointer * @ring: ring we should submit the msg to * @handle: VCE session handle to use * @fence: optional fence to return * * Close up a stream for HW test or if userspace failed to do so */ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, uint32_t handle, struct radeon_fence **fence) { const unsigned ib_size_dw = 1024; struct radeon_ib ib; uint64_t dummy; int i, r; r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); if (r) { DRM_ERROR("radeon: failed to get ib (%d).\n", r); return r; } dummy = ib.gpu_addr + 1024; /* stitch together an VCE destroy msg */ ib.length_dw = 0; ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ ib.ptr[ib.length_dw++] = cpu_to_le32(handle); ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */ ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */ for (i = ib.length_dw; i < ib_size_dw; ++i) ib.ptr[i] = cpu_to_le32(0x0); r = radeon_ib_schedule(rdev, &ib, NULL, false); if (r) { DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); } if (fence) *fence = radeon_fence_ref(ib.fence); radeon_ib_free(rdev, &ib); return r; }