|
@@ -56,7 +56,6 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work);
|
|
|
|
|
|
int radeon_uvd_init(struct radeon_device *rdev)
|
|
|
{
|
|
|
- const struct firmware *fw;
|
|
|
unsigned long bo_size;
|
|
|
const char *fw_name;
|
|
|
int i, r;
|
|
@@ -105,14 +104,14 @@ int radeon_uvd_init(struct radeon_device *rdev)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- r = request_firmware(&fw, fw_name, rdev->dev);
|
|
|
+ r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev);
|
|
|
if (r) {
|
|
|
dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
|
|
|
fw_name);
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
- bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) +
|
|
|
+ bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
|
|
|
RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
|
|
|
r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
|
|
|
RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
|
|
@@ -145,12 +144,6 @@ int radeon_uvd_init(struct radeon_device *rdev)
|
|
|
|
|
|
radeon_bo_unreserve(rdev->uvd.vcpu_bo);
|
|
|
|
|
|
- rdev->uvd.fw_size = fw->size;
|
|
|
- memset(rdev->uvd.cpu_addr, 0, bo_size);
|
|
|
- memcpy(rdev->uvd.cpu_addr, fw->data, fw->size);
|
|
|
-
|
|
|
- release_firmware(fw);
|
|
|
-
|
|
|
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
|
|
|
atomic_set(&rdev->uvd.handles[i], 0);
|
|
|
rdev->uvd.filp[i] = NULL;
|
|
@@ -174,33 +167,60 @@ void radeon_uvd_fini(struct radeon_device *rdev)
|
|
|
}
|
|
|
|
|
|
radeon_bo_unref(&rdev->uvd.vcpu_bo);
|
|
|
+
|
|
|
+ release_firmware(rdev->uvd_fw);
|
|
|
}
|
|
|
|
|
|
int radeon_uvd_suspend(struct radeon_device *rdev)
|
|
|
{
|
|
|
unsigned size;
|
|
|
+ void *ptr;
|
|
|
+ int i;
|
|
|
|
|
|
if (rdev->uvd.vcpu_bo == NULL)
|
|
|
return 0;
|
|
|
|
|
|
+ for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
|
|
|
+ if (atomic_read(&rdev->uvd.handles[i]))
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (i == RADEON_MAX_UVD_HANDLES)
|
|
|
+ return 0;
|
|
|
+
|
|
|
size = radeon_bo_size(rdev->uvd.vcpu_bo);
|
|
|
+ size -= rdev->uvd_fw->size;
|
|
|
+
|
|
|
+ ptr = rdev->uvd.cpu_addr;
|
|
|
+ ptr += rdev->uvd_fw->size;
|
|
|
+
|
|
|
rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
|
|
|
- memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size);
|
|
|
+ memcpy(rdev->uvd.saved_bo, ptr, size);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int radeon_uvd_resume(struct radeon_device *rdev)
|
|
|
{
|
|
|
+ unsigned size;
|
|
|
+ void *ptr;
|
|
|
+
|
|
|
if (rdev->uvd.vcpu_bo == NULL)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
|
|
|
+
|
|
|
+ size = radeon_bo_size(rdev->uvd.vcpu_bo);
|
|
|
+ size -= rdev->uvd_fw->size;
|
|
|
+
|
|
|
+ ptr = rdev->uvd.cpu_addr;
|
|
|
+ ptr += rdev->uvd_fw->size;
|
|
|
+
|
|
|
if (rdev->uvd.saved_bo != NULL) {
|
|
|
- unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo);
|
|
|
- memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size);
|
|
|
+ memcpy(ptr, rdev->uvd.saved_bo, size);
|
|
|
kfree(rdev->uvd.saved_bo);
|
|
|
rdev->uvd.saved_bo = NULL;
|
|
|
- }
|
|
|
+ } else
|
|
|
+ memset(ptr, 0, size);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -215,8 +235,8 @@ void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
|
|
|
{
|
|
|
int i, r;
|
|
|
for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
|
|
|
- if (rdev->uvd.filp[i] == filp) {
|
|
|
- uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
|
|
|
+ uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
|
|
|
+ if (handle != 0 && rdev->uvd.filp[i] == filp) {
|
|
|
struct radeon_fence *fence;
|
|
|
|
|
|
r = radeon_uvd_get_destroy_msg(rdev,
|
|
@@ -337,8 +357,10 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
|
|
|
}
|
|
|
|
|
|
r = radeon_bo_kmap(bo, &ptr);
|
|
|
- if (r)
|
|
|
+ if (r) {
|
|
|
+ DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
|
|
|
return r;
|
|
|
+ }
|
|
|
|
|
|
msg = ptr + offset;
|
|
|
|
|
@@ -364,8 +386,14 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
|
|
|
radeon_bo_kunmap(bo);
|
|
|
return 0;
|
|
|
} else {
|
|
|
- /* it's a create msg, no special handling needed */
|
|
|
radeon_bo_kunmap(bo);
|
|
|
+
|
|
|
+ if (msg_type != 0) {
|
|
|
+ DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* it's a create msg, no special handling needed */
|
|
|
}
|
|
|
|
|
|
/* create or decode, validate the handle */
|
|
@@ -388,7 +416,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
|
|
|
|
|
|
static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
|
|
|
int data0, int data1,
|
|
|
- unsigned buf_sizes[])
|
|
|
+ unsigned buf_sizes[], bool *has_msg_cmd)
|
|
|
{
|
|
|
struct radeon_cs_chunk *relocs_chunk;
|
|
|
struct radeon_cs_reloc *reloc;
|
|
@@ -417,7 +445,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
|
|
|
|
|
|
if (cmd < 0x4) {
|
|
|
if ((end - start) < buf_sizes[cmd]) {
|
|
|
- DRM_ERROR("buffer to small (%d / %d)!\n",
|
|
|
+ DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
|
|
|
(unsigned)(end - start), buf_sizes[cmd]);
|
|
|
return -EINVAL;
|
|
|
}
|
|
@@ -442,9 +470,17 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
|
|
|
}
|
|
|
|
|
|
if (cmd == 0) {
|
|
|
+ if (*has_msg_cmd) {
|
|
|
+ DRM_ERROR("More than one message in a UVD-IB!\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ *has_msg_cmd = true;
|
|
|
r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes);
|
|
|
if (r)
|
|
|
return r;
|
|
|
+ } else if (!*has_msg_cmd) {
|
|
|
+ DRM_ERROR("Message needed before other commands are send!\n");
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -453,7 +489,8 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
|
|
|
static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
|
|
|
struct radeon_cs_packet *pkt,
|
|
|
int *data0, int *data1,
|
|
|
- unsigned buf_sizes[])
|
|
|
+ unsigned buf_sizes[],
|
|
|
+ bool *has_msg_cmd)
|
|
|
{
|
|
|
int i, r;
|
|
|
|
|
@@ -467,7 +504,8 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
|
|
|
*data1 = p->idx;
|
|
|
break;
|
|
|
case UVD_GPCOM_VCPU_CMD:
|
|
|
- r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes);
|
|
|
+ r = radeon_uvd_cs_reloc(p, *data0, *data1,
|
|
|
+ buf_sizes, has_msg_cmd);
|
|
|
if (r)
|
|
|
return r;
|
|
|
break;
|
|
@@ -488,6 +526,9 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
|
|
|
struct radeon_cs_packet pkt;
|
|
|
int r, data0 = 0, data1 = 0;
|
|
|
|
|
|
+ /* does the IB has a msg command */
|
|
|
+ bool has_msg_cmd = false;
|
|
|
+
|
|
|
/* minimum buffer sizes */
|
|
|
unsigned buf_sizes[] = {
|
|
|
[0x00000000] = 2048,
|
|
@@ -514,8 +555,8 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
|
|
|
return r;
|
|
|
switch (pkt.type) {
|
|
|
case RADEON_PACKET_TYPE0:
|
|
|
- r = radeon_uvd_cs_reg(p, &pkt, &data0,
|
|
|
- &data1, buf_sizes);
|
|
|
+ r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1,
|
|
|
+ buf_sizes, &has_msg_cmd);
|
|
|
if (r)
|
|
|
return r;
|
|
|
break;
|
|
@@ -527,6 +568,12 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
|
|
|
+
|
|
|
+ if (!has_msg_cmd) {
|
|
|
+ DRM_ERROR("UVD-IBs need a msg command!\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|