diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 169 | 
1 files changed, 105 insertions, 64 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 2f7a5efa21c2..2cf6c6b06e3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -52,6 +52,7 @@  #endif  #define FIRMWARE_TONGA		"amdgpu/tonga_uvd.bin"  #define FIRMWARE_CARRIZO	"amdgpu/carrizo_uvd.bin" +#define FIRMWARE_FIJI		"amdgpu/fiji_uvd.bin"  /**   * amdgpu_uvd_cs_ctx - Command submission parser context @@ -81,6 +82,7 @@ MODULE_FIRMWARE(FIRMWARE_MULLINS);  #endif  MODULE_FIRMWARE(FIRMWARE_TONGA);  MODULE_FIRMWARE(FIRMWARE_CARRIZO); +MODULE_FIRMWARE(FIRMWARE_FIJI);  static void amdgpu_uvd_note_usage(struct amdgpu_device *adev);  static void amdgpu_uvd_idle_work_handler(struct work_struct *work); @@ -116,6 +118,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)  	case CHIP_TONGA:  		fw_name = FIRMWARE_TONGA;  		break; +	case CHIP_FIJI: +		fw_name = FIRMWARE_FIJI; +		break;  	case CHIP_CARRIZO:  		fw_name = FIRMWARE_CARRIZO;  		break; @@ -149,7 +154,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)  	bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8)  		 +  AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE;  	r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->uvd.vcpu_bo); +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			     NULL, &adev->uvd.vcpu_bo);  	if (r) {  		dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r);  		return r; @@ -216,31 +223,32 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev)  int amdgpu_uvd_suspend(struct amdgpu_device *adev)  { -	unsigned size; -	void *ptr; -	const struct common_firmware_header *hdr; -	int i; +	struct amdgpu_ring *ring = &adev->uvd.ring; +	int i, r;  	if (adev->uvd.vcpu_bo == NULL)  		return 0; -	for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) -		if (atomic_read(&adev->uvd.handles[i])) -			break; - -	if (i == AMDGPU_MAX_UVD_HANDLES) -		return 0; +	for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) { +		uint32_t handle = atomic_read(&adev->uvd.handles[i]); +		if (handle != 0) { +			struct fence *fence; -	hdr = (const struct common_firmware_header *)adev->uvd.fw->data; +			amdgpu_uvd_note_usage(adev); -	size = amdgpu_bo_size(adev->uvd.vcpu_bo); -	size -= le32_to_cpu(hdr->ucode_size_bytes); +			r = amdgpu_uvd_get_destroy_msg(ring, handle, &fence); +			if (r) { +				DRM_ERROR("Error destroying UVD (%d)!\n", r); +				continue; +			} -	ptr = adev->uvd.cpu_addr; -	ptr += le32_to_cpu(hdr->ucode_size_bytes); +			fence_wait(fence, false); +			fence_put(fence); -	adev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); -	memcpy(adev->uvd.saved_bo, ptr, size); +			adev->uvd.filp[i] = NULL; +			atomic_set(&adev->uvd.handles[i], 0); +		} +	}  	return 0;  } @@ -265,12 +273,7 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev)  	ptr = adev->uvd.cpu_addr;  	ptr += le32_to_cpu(hdr->ucode_size_bytes); -	if (adev->uvd.saved_bo != NULL) { -		memcpy(ptr, adev->uvd.saved_bo, size); -		kfree(adev->uvd.saved_bo); -		adev->uvd.saved_bo = NULL; -	} else -		memset(ptr, 0, size); +	memset(ptr, 0, size);  	return 0;  } @@ -283,7 +286,7 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)  	for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) {  		uint32_t handle = atomic_read(&adev->uvd.handles[i]);  		if (handle != 0 && adev->uvd.filp[i] == filp) { -			struct amdgpu_fence *fence; +			struct fence *fence;  			amdgpu_uvd_note_usage(adev); @@ -293,8 +296,8 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)  				continue;  			} -			amdgpu_fence_wait(fence, false); -			amdgpu_fence_unref(&fence); +			fence_wait(fence, false); +			fence_put(fence);  			adev->uvd.filp[i] = NULL;  			atomic_set(&adev->uvd.handles[i], 0); @@ -375,6 +378,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])  	unsigned fs_in_mb = width_in_mb * height_in_mb;  	unsigned image_size, tmp, min_dpb_size, num_dpb_buffer; +	unsigned min_ctx_size = 0;  	image_size = width * height;  	image_size += image_size / 2; @@ -466,6 +470,8 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])  		num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;  		min_dpb_size = image_size * num_dpb_buffer; +		min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16) +					   * 16 * num_dpb_buffer + 52 * 1024;  		break;  	default: @@ -486,6 +492,7 @@ static int amdgpu_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])  	buf_sizes[0x1] = dpb_size;  	buf_sizes[0x2] = image_size; +	buf_sizes[0x4] = min_ctx_size;  	return 0;  } @@ -504,28 +511,25 @@ static int amdgpu_uvd_cs_msg(struct amdgpu_uvd_cs_ctx *ctx,  {  	struct amdgpu_device *adev = ctx->parser->adev;  	int32_t *msg, msg_type, handle; -	struct fence *f;  	void *ptr; - -	int i, r; +	long r; +	int i;  	if (offset & 0x3F) {  		DRM_ERROR("UVD messages must be 64 byte aligned!\n");  		return -EINVAL;  	} -	f = reservation_object_get_excl(bo->tbo.resv); -	if (f) { -		r = amdgpu_fence_wait((struct amdgpu_fence *)f, false); -		if (r) { -			DRM_ERROR("Failed waiting for UVD message (%d)!\n", r); -			return r; -		} +	r = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, false, +						MAX_SCHEDULE_TIMEOUT); +	if (r < 0) { +		DRM_ERROR("Failed waiting for UVD message (%ld)!\n", r); +		return r;  	}  	r = amdgpu_bo_kmap(bo, &ptr);  	if (r) { -		DRM_ERROR("Failed mapping the UVD message (%d)!\n", r); +		DRM_ERROR("Failed mapping the UVD message (%ld)!\n", r);  		return r;  	} @@ -628,6 +632,13 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)  			return -EINVAL;  		} +	} else if (cmd == 0x206) { +		if ((end - start) < ctx->buf_sizes[4]) { +			DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd, +					  (unsigned)(end - start), +					  ctx->buf_sizes[4]); +			return -EINVAL; +		}  	} else if ((cmd != 0x100) && (cmd != 0x204)) {  		DRM_ERROR("invalid UVD command %X!\n", cmd);  		return -EINVAL; @@ -755,9 +766,10 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)  	struct amdgpu_uvd_cs_ctx ctx = {};  	unsigned buf_sizes[] = {  		[0x00000000]	=	2048, -		[0x00000001]	=	32 * 1024 * 1024, -		[0x00000002]	=	2048 * 1152 * 3, +		[0x00000001]	=	0xFFFFFFFF, +		[0x00000002]	=	0xFFFFFFFF,  		[0x00000003]	=	2048, +		[0x00000004]	=	0xFFFFFFFF,  	};  	struct amdgpu_ib *ib = &parser->ibs[ib_idx];  	int r; @@ -792,14 +804,24 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser, uint32_t ib_idx)  	return 0;  } +static int amdgpu_uvd_free_job( +	struct amdgpu_job *sched_job) +{ +	amdgpu_ib_free(sched_job->adev, sched_job->ibs); +	kfree(sched_job->ibs); +	return 0; +} +  static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring,  			       struct amdgpu_bo *bo, -			       struct amdgpu_fence **fence) +			       struct fence **fence)  {  	struct ttm_validate_buffer tv;  	struct ww_acquire_ctx ticket;  	struct list_head head; -	struct amdgpu_ib ib; +	struct amdgpu_ib *ib = NULL; +	struct fence *f = NULL; +	struct amdgpu_device *adev = ring->adev;  	uint64_t addr;  	int i, r; @@ -821,34 +843,49 @@ static int amdgpu_uvd_send_msg(struct amdgpu_ring *ring,  	r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);  	if (r)  		goto err; - -	r = amdgpu_ib_get(ring, NULL, 64, &ib); -	if (r) +	ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL); +	if (!ib) { +		r = -ENOMEM;  		goto err; +	} +	r = amdgpu_ib_get(ring, NULL, 64, ib); +	if (r) +		goto err1;  	addr = amdgpu_bo_gpu_offset(bo); -	ib.ptr[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0); -	ib.ptr[1] = addr; -	ib.ptr[2] = PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0); -	ib.ptr[3] = addr >> 32; -	ib.ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0); -	ib.ptr[5] = 0; +	ib->ptr[0] = PACKET0(mmUVD_GPCOM_VCPU_DATA0, 0); +	ib->ptr[1] = addr; +	ib->ptr[2] = PACKET0(mmUVD_GPCOM_VCPU_DATA1, 0); +	ib->ptr[3] = addr >> 32; +	ib->ptr[4] = PACKET0(mmUVD_GPCOM_VCPU_CMD, 0); +	ib->ptr[5] = 0;  	for (i = 6; i < 16; ++i) -		ib.ptr[i] = PACKET2(0); -	ib.length_dw = 16; +		ib->ptr[i] = PACKET2(0); +	ib->length_dw = 16; -	r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED); +	r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1, +						 &amdgpu_uvd_free_job, +						 AMDGPU_FENCE_OWNER_UNDEFINED, +						 &f);  	if (r) -		goto err; -	ttm_eu_fence_buffer_objects(&ticket, &head, &ib.fence->base); +		goto err2; -	if (fence) -		*fence = amdgpu_fence_ref(ib.fence); +	ttm_eu_fence_buffer_objects(&ticket, &head, f); -	amdgpu_ib_free(ring->adev, &ib); +	if (fence) +		*fence = fence_get(f);  	amdgpu_bo_unref(&bo); -	return 0; +	fence_put(f); +	if (amdgpu_enable_scheduler) +		return 0; +	amdgpu_ib_free(ring->adev, ib); +	kfree(ib); +	return 0; +err2: +	amdgpu_ib_free(ring->adev, ib); +err1: +	kfree(ib);  err:  	ttm_eu_backoff_reservation(&ticket, &head);  	return r; @@ -858,7 +895,7 @@ err:     crash the vcpu so just try to emmit a dummy create/destroy msg to     avoid this */  int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, -			      struct amdgpu_fence **fence) +			      struct fence **fence)  {  	struct amdgpu_device *adev = ring->adev;  	struct amdgpu_bo *bo; @@ -866,7 +903,9 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,  	int r, i;  	r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo); +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			     NULL, &bo);  	if (r)  		return r; @@ -905,7 +944,7 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,  }  int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, -			       struct amdgpu_fence **fence) +			       struct fence **fence)  {  	struct amdgpu_device *adev = ring->adev;  	struct amdgpu_bo *bo; @@ -913,7 +952,9 @@ int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,  	int r, i;  	r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, -			     AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo); +			     AMDGPU_GEM_DOMAIN_VRAM, +			     AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, +			     NULL, &bo);  	if (r)  		return r;  |