|
29 | 29 | #include "i915_gem_ioctls.h"
|
30 | 30 | #include "i915_trace.h"
|
31 | 31 | #include "i915_user_extensions.h"
|
| 32 | +#include "i915_vma_snapshot.h" |
32 | 33 |
|
33 | 34 | struct eb_vma {
|
34 | 35 | struct i915_vma *vma;
|
@@ -307,11 +308,15 @@ struct i915_execbuffer {
|
307 | 308 |
|
308 | 309 | struct eb_fence *fences;
|
309 | 310 | unsigned long num_fences;
|
| 311 | +#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) |
| 312 | + struct i915_capture_list *capture_lists[MAX_ENGINE_INSTANCE + 1]; |
| 313 | +#endif |
310 | 314 | };
|
311 | 315 |
|
312 | 316 | static int eb_parse(struct i915_execbuffer *eb);
|
313 | 317 | static int eb_pin_engine(struct i915_execbuffer *eb, bool throttle);
|
314 | 318 | static void eb_unpin_engine(struct i915_execbuffer *eb);
|
| 319 | +static void eb_capture_release(struct i915_execbuffer *eb); |
315 | 320 |
|
316 | 321 | static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb)
|
317 | 322 | {
|
@@ -1043,6 +1048,7 @@ static void eb_release_vmas(struct i915_execbuffer *eb, bool final)
|
1043 | 1048 | i915_vma_put(vma);
|
1044 | 1049 | }
|
1045 | 1050 |
|
| 1051 | + eb_capture_release(eb); |
1046 | 1052 | eb_unpin_engine(eb);
|
1047 | 1053 | }
|
1048 | 1054 |
|
@@ -1880,36 +1886,113 @@ eb_find_first_request_added(struct i915_execbuffer *eb)
|
1880 | 1886 | return NULL;
|
1881 | 1887 | }
|
1882 | 1888 |
|
1883 |
| -static int eb_move_to_gpu(struct i915_execbuffer *eb) |
| 1889 | +#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) |
| 1890 | + |
| 1891 | +/* Stage with GFP_KERNEL allocations before we enter the signaling critical path */ |
| 1892 | +static void eb_capture_stage(struct i915_execbuffer *eb) |
1884 | 1893 | {
|
1885 | 1894 | const unsigned int count = eb->buffer_count;
|
1886 |
| - unsigned int i = count; |
1887 |
| - int err = 0, j; |
| 1895 | + unsigned int i = count, j; |
| 1896 | + struct i915_vma_snapshot *vsnap; |
1888 | 1897 |
|
1889 | 1898 | while (i--) {
|
1890 | 1899 | struct eb_vma *ev = &eb->vma[i];
|
1891 | 1900 | struct i915_vma *vma = ev->vma;
|
1892 | 1901 | unsigned int flags = ev->flags;
|
1893 |
| - struct drm_i915_gem_object *obj = vma->obj; |
1894 | 1902 |
|
1895 |
| - assert_vma_held(vma); |
| 1903 | + if (!(flags & EXEC_OBJECT_CAPTURE)) |
| 1904 | + continue; |
1896 | 1905 |
|
1897 |
| - if (flags & EXEC_OBJECT_CAPTURE) { |
| 1906 | + vsnap = i915_vma_snapshot_alloc(GFP_KERNEL); |
| 1907 | + if (!vsnap) |
| 1908 | + continue; |
| 1909 | + |
| 1910 | + i915_vma_snapshot_init(vsnap, vma, "user"); |
| 1911 | + for_each_batch_create_order(eb, j) { |
1898 | 1912 | struct i915_capture_list *capture;
|
1899 | 1913 |
|
1900 |
| - for_each_batch_create_order(eb, j) { |
1901 |
| - if (!eb->requests[j]) |
1902 |
| - break; |
| 1914 | + capture = kmalloc(sizeof(*capture), GFP_KERNEL); |
| 1915 | + if (!capture) |
| 1916 | + continue; |
1903 | 1917 |
|
1904 |
| - capture = kmalloc(sizeof(*capture), GFP_KERNEL); |
1905 |
| - if (capture) { |
1906 |
| - capture->next = |
1907 |
| - eb->requests[j]->capture_list; |
1908 |
| - capture->vma = vma; |
1909 |
| - eb->requests[j]->capture_list = capture; |
1910 |
| - } |
1911 |
| - } |
| 1918 | + capture->next = eb->capture_lists[j]; |
| 1919 | + capture->vma_snapshot = i915_vma_snapshot_get(vsnap); |
| 1920 | + eb->capture_lists[j] = capture; |
| 1921 | + } |
| 1922 | + i915_vma_snapshot_put(vsnap); |
| 1923 | + } |
| 1924 | +} |
| 1925 | + |
| 1926 | +/* Commit once we're in the critical path */ |
| 1927 | +static void eb_capture_commit(struct i915_execbuffer *eb) |
| 1928 | +{ |
| 1929 | + unsigned int j; |
| 1930 | + |
| 1931 | + for_each_batch_create_order(eb, j) { |
| 1932 | + struct i915_request *rq = eb->requests[j]; |
| 1933 | + |
| 1934 | + if (!rq) |
| 1935 | + break; |
| 1936 | + |
| 1937 | + rq->capture_list = eb->capture_lists[j]; |
| 1938 | + eb->capture_lists[j] = NULL; |
| 1939 | + } |
| 1940 | +} |
| 1941 | + |
| 1942 | +/* |
| 1943 | + * Release anything that didn't get committed due to errors. |
| 1944 | + * The capture_list will otherwise be freed at request retire. |
| 1945 | + */ |
| 1946 | +static void eb_capture_release(struct i915_execbuffer *eb) |
| 1947 | +{ |
| 1948 | + unsigned int j; |
| 1949 | + |
| 1950 | + for_each_batch_create_order(eb, j) { |
| 1951 | + if (eb->capture_lists[j]) { |
| 1952 | + i915_request_free_capture_list(eb->capture_lists[j]); |
| 1953 | + eb->capture_lists[j] = NULL; |
1912 | 1954 | }
|
| 1955 | + } |
| 1956 | +} |
| 1957 | + |
| 1958 | +static void eb_capture_list_clear(struct i915_execbuffer *eb) |
| 1959 | +{ |
| 1960 | + memset(eb->capture_lists, 0, sizeof(eb->capture_lists)); |
| 1961 | +} |
| 1962 | + |
| 1963 | +#else |
| 1964 | + |
| 1965 | +static void eb_capture_stage(struct i915_execbuffer *eb) |
| 1966 | +{ |
| 1967 | +} |
| 1968 | + |
| 1969 | +static void eb_capture_commit(struct i915_execbuffer *eb) |
| 1970 | +{ |
| 1971 | +} |
| 1972 | + |
| 1973 | +static void eb_capture_release(struct i915_execbuffer *eb) |
| 1974 | +{ |
| 1975 | +} |
| 1976 | + |
| 1977 | +static void eb_capture_list_clear(struct i915_execbuffer *eb) |
| 1978 | +{ |
| 1979 | +} |
| 1980 | + |
| 1981 | +#endif |
| 1982 | + |
| 1983 | +static int eb_move_to_gpu(struct i915_execbuffer *eb) |
| 1984 | +{ |
| 1985 | + const unsigned int count = eb->buffer_count; |
| 1986 | + unsigned int i = count; |
| 1987 | + int err = 0, j; |
| 1988 | + |
| 1989 | + while (i--) { |
| 1990 | + struct eb_vma *ev = &eb->vma[i]; |
| 1991 | + struct i915_vma *vma = ev->vma; |
| 1992 | + unsigned int flags = ev->flags; |
| 1993 | + struct drm_i915_gem_object *obj = vma->obj; |
| 1994 | + |
| 1995 | + assert_vma_held(vma); |
1913 | 1996 |
|
1914 | 1997 | /*
|
1915 | 1998 | * If the GPU is not _reading_ through the CPU cache, we need
|
@@ -1990,6 +2073,8 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
|
1990 | 2073 |
|
1991 | 2074 | /* Unconditionally flush any chipset caches (for streaming writes). */
|
1992 | 2075 | intel_gt_chipset_flush(eb->gt);
|
| 2076 | + eb_capture_commit(eb); |
| 2077 | + |
1993 | 2078 | return 0;
|
1994 | 2079 |
|
1995 | 2080 | err_skip:
|
@@ -3132,13 +3217,14 @@ eb_requests_create(struct i915_execbuffer *eb, struct dma_fence *in_fence,
|
3132 | 3217 | }
|
3133 | 3218 |
|
3134 | 3219 | /*
|
3135 |
| - * Whilst this request exists, batch_obj will be on the |
3136 |
| - * active_list, and so will hold the active reference. Only when |
3137 |
| - * this request is retired will the batch_obj be moved onto |
3138 |
| - * the inactive_list and lose its active reference. Hence we do |
3139 |
| - * not need to explicitly hold another reference here. |
| 3220 | + * Not really on stack, but we don't want to call |
| 3221 | + * kfree on the batch_snapshot when we put it, so use the |
| 3222 | + * _onstack interface. |
3140 | 3223 | */
|
3141 |
| - eb->requests[i]->batch = eb->batches[i]->vma; |
| 3224 | + if (eb->batches[i]->vma) |
| 3225 | + i915_vma_snapshot_init_onstack(&eb->requests[i]->batch_snapshot, |
| 3226 | + eb->batches[i]->vma, |
| 3227 | + "batch"); |
3142 | 3228 | if (eb->batch_pool) {
|
3143 | 3229 | GEM_BUG_ON(intel_context_is_parallel(eb->context));
|
3144 | 3230 | intel_gt_buffer_pool_mark_active(eb->batch_pool,
|
@@ -3187,6 +3273,8 @@ i915_gem_do_execbuffer(struct drm_device *dev,
|
3187 | 3273 | eb.fences = NULL;
|
3188 | 3274 | eb.num_fences = 0;
|
3189 | 3275 |
|
| 3276 | + eb_capture_list_clear(&eb); |
| 3277 | + |
3190 | 3278 | memset(eb.requests, 0, sizeof(struct i915_request *) *
|
3191 | 3279 | ARRAY_SIZE(eb.requests));
|
3192 | 3280 | eb.composite_fence = NULL;
|
@@ -3273,6 +3361,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
|
3273 | 3361 | }
|
3274 | 3362 |
|
3275 | 3363 | ww_acquire_done(&eb.ww.ctx);
|
| 3364 | + eb_capture_stage(&eb); |
3276 | 3365 |
|
3277 | 3366 | out_fence = eb_requests_create(&eb, in_fence, out_fence_fd);
|
3278 | 3367 | if (IS_ERR(out_fence)) {
|
|
0 commit comments