diff options
author | Marek Olšák <maraeo@gmail.com> | 2012-01-27 12:17:59 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-02-13 07:09:11 -0500 |
commit | dd220a00e8bd5ad7f98ecdc3eed699a7cfabdc27 (patch) | |
tree | 8cdedce29665aae1f92ebcccefacda0598d08a1c /drivers/gpu/drm/radeon/r600_cs.c | |
parent | 51a59ac8739b333eaa43a3102b6acaab5037bfa2 (diff) |
drm/radeon/kms: add support for streamout v7
v2: agd5f: add strmout CS checking, copy_dw register checking
v3: agd5f: don't use cs_check_reg() for copy_dw checking as it
will incorrectly patch the command stream for certain regs.
v4: agd5f: add warning if safe reg check fails for copy_dw
v5: agd5f: add stricter checking for 6xx/7xx
v6: agd5f: add range checking for copy_dw on eg+,
add sx_surface_sync to safe reg list for 7xx.
v7: agd5f: add stricter checking for eg+
Signed-off-by: Marek Olšák <maraeo@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/r600_cs.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r600_cs.c | 179 |
1 files changed, 175 insertions, 4 deletions
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 38ce5d0427e3..9f17571eea62 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c | |||
@@ -61,6 +61,10 @@ struct r600_cs_track { | |||
61 | u32 cb_color_size[8]; | 61 | u32 cb_color_size[8]; |
62 | u32 vgt_strmout_en; | 62 | u32 vgt_strmout_en; |
63 | u32 vgt_strmout_buffer_en; | 63 | u32 vgt_strmout_buffer_en; |
64 | struct radeon_bo *vgt_strmout_bo[4]; | ||
65 | u64 vgt_strmout_bo_mc[4]; | ||
66 | u32 vgt_strmout_bo_offset[4]; | ||
67 | u32 vgt_strmout_size[4]; | ||
64 | u32 db_depth_control; | 68 | u32 db_depth_control; |
65 | u32 db_depth_info; | 69 | u32 db_depth_info; |
66 | u32 db_depth_size_idx; | 70 | u32 db_depth_size_idx; |
@@ -310,6 +314,13 @@ static void r600_cs_track_init(struct r600_cs_track *track) | |||
310 | track->db_depth_size = 0xFFFFFFFF; | 314 | track->db_depth_size = 0xFFFFFFFF; |
311 | track->db_depth_size_idx = 0; | 315 | track->db_depth_size_idx = 0; |
312 | track->db_depth_control = 0xFFFFFFFF; | 316 | track->db_depth_control = 0xFFFFFFFF; |
317 | |||
318 | for (i = 0; i < 4; i++) { | ||
319 | track->vgt_strmout_size[i] = 0; | ||
320 | track->vgt_strmout_bo[i] = NULL; | ||
321 | track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF; | ||
322 | track->vgt_strmout_bo_mc[i] = 0xFFFFFFFF; | ||
323 | } | ||
313 | } | 324 | } |
314 | 325 | ||
315 | static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) | 326 | static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) |
@@ -430,11 +441,28 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) | |||
430 | /* on legacy kernel we don't perform advanced check */ | 441 | /* on legacy kernel we don't perform advanced check */ |
431 | if (p->rdev == NULL) | 442 | if (p->rdev == NULL) |
432 | return 0; | 443 | return 0; |
433 | /* we don't support out buffer yet */ | 444 | |
434 | if (track->vgt_strmout_en || track->vgt_strmout_buffer_en) { | 445 | /* check streamout */ |
435 | dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n"); | 446 | if (track->vgt_strmout_en) { |
436 | return -EINVAL; | 447 | for (i = 0; i < 4; i++) { |
448 | if (track->vgt_strmout_buffer_en & (1 << i)) { | ||
449 | if (track->vgt_strmout_bo[i]) { | ||
450 | u64 offset = (u64)track->vgt_strmout_bo_offset[i] + | ||
451 | (u64)track->vgt_strmout_size[i]; | ||
452 | if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) { | ||
453 | DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n", | ||
454 | i, offset, | ||
455 | radeon_bo_size(track->vgt_strmout_bo[i])); | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | } else { | ||
459 | dev_warn(p->dev, "No buffer for streamout %d\n", i); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | } | ||
463 | } | ||
437 | } | 464 | } |
465 | |||
438 | /* check that we have a cb for each enabled target, we don't check | 466 | /* check that we have a cb for each enabled target, we don't check |
439 | * shader_mask because it seems mesa isn't always setting it :( | 467 | * shader_mask because it seems mesa isn't always setting it :( |
440 | */ | 468 | */ |
@@ -975,6 +1003,39 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) | |||
975 | case R_028B20_VGT_STRMOUT_BUFFER_EN: | 1003 | case R_028B20_VGT_STRMOUT_BUFFER_EN: |
976 | track->vgt_strmout_buffer_en = radeon_get_ib_value(p, idx); | 1004 | track->vgt_strmout_buffer_en = radeon_get_ib_value(p, idx); |
977 | break; | 1005 | break; |
1006 | case VGT_STRMOUT_BUFFER_BASE_0: | ||
1007 | case VGT_STRMOUT_BUFFER_BASE_1: | ||
1008 | case VGT_STRMOUT_BUFFER_BASE_2: | ||
1009 | case VGT_STRMOUT_BUFFER_BASE_3: | ||
1010 | r = r600_cs_packet_next_reloc(p, &reloc); | ||
1011 | if (r) { | ||
1012 | dev_warn(p->dev, "bad SET_CONTEXT_REG " | ||
1013 | "0x%04X\n", reg); | ||
1014 | return -EINVAL; | ||
1015 | } | ||
1016 | tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16; | ||
1017 | track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8; | ||
1018 | ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); | ||
1019 | track->vgt_strmout_bo[tmp] = reloc->robj; | ||
1020 | track->vgt_strmout_bo_mc[tmp] = reloc->lobj.gpu_offset; | ||
1021 | break; | ||
1022 | case VGT_STRMOUT_BUFFER_SIZE_0: | ||
1023 | case VGT_STRMOUT_BUFFER_SIZE_1: | ||
1024 | case VGT_STRMOUT_BUFFER_SIZE_2: | ||
1025 | case VGT_STRMOUT_BUFFER_SIZE_3: | ||
1026 | tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16; | ||
1027 | /* size in register is DWs, convert to bytes */ | ||
1028 | track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4; | ||
1029 | break; | ||
1030 | case CP_COHER_BASE: | ||
1031 | r = r600_cs_packet_next_reloc(p, &reloc); | ||
1032 | if (r) { | ||
1033 | dev_warn(p->dev, "missing reloc for CP_COHER_BASE " | ||
1034 | "0x%04X\n", reg); | ||
1035 | return -EINVAL; | ||
1036 | } | ||
1037 | ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); | ||
1038 | break; | ||
978 | case R_028238_CB_TARGET_MASK: | 1039 | case R_028238_CB_TARGET_MASK: |
979 | track->cb_target_mask = radeon_get_ib_value(p, idx); | 1040 | track->cb_target_mask = radeon_get_ib_value(p, idx); |
980 | break; | 1041 | break; |
@@ -1397,6 +1458,22 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, | |||
1397 | return 0; | 1458 | return 0; |
1398 | } | 1459 | } |
1399 | 1460 | ||
1461 | static bool r600_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) | ||
1462 | { | ||
1463 | u32 m, i; | ||
1464 | |||
1465 | i = (reg >> 7); | ||
1466 | if (i >= ARRAY_SIZE(r600_reg_safe_bm)) { | ||
1467 | dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); | ||
1468 | return false; | ||
1469 | } | ||
1470 | m = 1 << ((reg >> 2) & 31); | ||
1471 | if (!(r600_reg_safe_bm[i] & m)) | ||
1472 | return true; | ||
1473 | dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); | ||
1474 | return false; | ||
1475 | } | ||
1476 | |||
1400 | static int r600_packet3_check(struct radeon_cs_parser *p, | 1477 | static int r600_packet3_check(struct radeon_cs_parser *p, |
1401 | struct radeon_cs_packet *pkt) | 1478 | struct radeon_cs_packet *pkt) |
1402 | { | 1479 | { |
@@ -1742,6 +1819,100 @@ static int r600_packet3_check(struct radeon_cs_parser *p, | |||
1742 | return -EINVAL; | 1819 | return -EINVAL; |
1743 | } | 1820 | } |
1744 | break; | 1821 | break; |
1822 | case PACKET3_STRMOUT_BUFFER_UPDATE: | ||
1823 | if (pkt->count != 4) { | ||
1824 | DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n"); | ||
1825 | return -EINVAL; | ||
1826 | } | ||
1827 | /* Updating memory at DST_ADDRESS. */ | ||
1828 | if (idx_value & 0x1) { | ||
1829 | u64 offset; | ||
1830 | r = r600_cs_packet_next_reloc(p, &reloc); | ||
1831 | if (r) { | ||
1832 | DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n"); | ||
1833 | return -EINVAL; | ||
1834 | } | ||
1835 | offset = radeon_get_ib_value(p, idx+1); | ||
1836 | offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; | ||
1837 | if ((offset + 4) > radeon_bo_size(reloc->robj)) { | ||
1838 | DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%llx, 0x%lx\n", | ||
1839 | offset + 4, radeon_bo_size(reloc->robj)); | ||
1840 | return -EINVAL; | ||
1841 | } | ||
1842 | ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); | ||
1843 | ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; | ||
1844 | } | ||
1845 | /* Reading data from SRC_ADDRESS. */ | ||
1846 | if (((idx_value >> 1) & 0x3) == 2) { | ||
1847 | u64 offset; | ||
1848 | r = r600_cs_packet_next_reloc(p, &reloc); | ||
1849 | if (r) { | ||
1850 | DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n"); | ||
1851 | return -EINVAL; | ||
1852 | } | ||
1853 | offset = radeon_get_ib_value(p, idx+3); | ||
1854 | offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; | ||
1855 | if ((offset + 4) > radeon_bo_size(reloc->robj)) { | ||
1856 | DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%llx, 0x%lx\n", | ||
1857 | offset + 4, radeon_bo_size(reloc->robj)); | ||
1858 | return -EINVAL; | ||
1859 | } | ||
1860 | ib[idx+3] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); | ||
1861 | ib[idx+4] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; | ||
1862 | } | ||
1863 | break; | ||
1864 | case PACKET3_COPY_DW: | ||
1865 | if (pkt->count != 4) { | ||
1866 | DRM_ERROR("bad COPY_DW (invalid count)\n"); | ||
1867 | return -EINVAL; | ||
1868 | } | ||
1869 | if (idx_value & 0x1) { | ||
1870 | u64 offset; | ||
1871 | /* SRC is memory. */ | ||
1872 | r = r600_cs_packet_next_reloc(p, &reloc); | ||
1873 | if (r) { | ||
1874 | DRM_ERROR("bad COPY_DW (missing src reloc)\n"); | ||
1875 | return -EINVAL; | ||
1876 | } | ||
1877 | offset = radeon_get_ib_value(p, idx+1); | ||
1878 | offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32; | ||
1879 | if ((offset + 4) > radeon_bo_size(reloc->robj)) { | ||
1880 | DRM_ERROR("bad COPY_DW src bo too small: 0x%llx, 0x%lx\n", | ||
1881 | offset + 4, radeon_bo_size(reloc->robj)); | ||
1882 | return -EINVAL; | ||
1883 | } | ||
1884 | ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); | ||
1885 | ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; | ||
1886 | } else { | ||
1887 | /* SRC is a reg. */ | ||
1888 | reg = radeon_get_ib_value(p, idx+1) << 2; | ||
1889 | if (!r600_is_safe_reg(p, reg, idx+1)) | ||
1890 | return -EINVAL; | ||
1891 | } | ||
1892 | if (idx_value & 0x2) { | ||
1893 | u64 offset; | ||
1894 | /* DST is memory. */ | ||
1895 | r = r600_cs_packet_next_reloc(p, &reloc); | ||
1896 | if (r) { | ||
1897 | DRM_ERROR("bad COPY_DW (missing dst reloc)\n"); | ||
1898 | return -EINVAL; | ||
1899 | } | ||
1900 | offset = radeon_get_ib_value(p, idx+3); | ||
1901 | offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32; | ||
1902 | if ((offset + 4) > radeon_bo_size(reloc->robj)) { | ||
1903 | DRM_ERROR("bad COPY_DW dst bo too small: 0x%llx, 0x%lx\n", | ||
1904 | offset + 4, radeon_bo_size(reloc->robj)); | ||
1905 | return -EINVAL; | ||
1906 | } | ||
1907 | ib[idx+3] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); | ||
1908 | ib[idx+4] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; | ||
1909 | } else { | ||
1910 | /* DST is a reg. */ | ||
1911 | reg = radeon_get_ib_value(p, idx+3) << 2; | ||
1912 | if (!r600_is_safe_reg(p, reg, idx+3)) | ||
1913 | return -EINVAL; | ||
1914 | } | ||
1915 | break; | ||
1745 | case PACKET3_NOP: | 1916 | case PACKET3_NOP: |
1746 | break; | 1917 | break; |
1747 | default: | 1918 | default: |