aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/r600_cs.c
diff options
context:
space:
mode:
authorMarek Olšák <maraeo@gmail.com>2012-01-27 12:17:59 -0500
committerDave Airlie <airlied@redhat.com>2012-02-13 07:09:11 -0500
commitdd220a00e8bd5ad7f98ecdc3eed699a7cfabdc27 (patch)
tree8cdedce29665aae1f92ebcccefacda0598d08a1c /drivers/gpu/drm/radeon/r600_cs.c
parent51a59ac8739b333eaa43a3102b6acaab5037bfa2 (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.c179
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
315static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) 326static 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
1461static 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
1400static int r600_packet3_check(struct radeon_cs_parser *p, 1477static 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: