| @@ -1957,207 +1957,14 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data) · 1956 unmodified lines |
| 1957 | return ctx_setparam(arg->fpriv, arg->ctx, &local.param); | 1957 | return ctx_setparam(arg->fpriv, arg->ctx, &local.param); |
| 1958 | } | 1958 | } |
| 1959 | | 1959 | |
| 1960 | static int clone_engines(struct i915_gem_context *dst, | 1960 | static int invalid_ext(struct i915_user_extension __user *ext, void *data) |
| 1961 | struct i915_gem_context *src) | | |
| 1962 | { | 1961 | { |
| 1963 | struct i915_gem_engines *clone, *e; | 1962 | return -EINVAL; |
| 1964 | bool user_engines; | | |
| 1965 | unsigned long n; | | |
| 1966 | | | |
| 1967 | e = __context_engines_await(src, &user_engines); | | |
| 1968 | if (!e) | | |
| 1969 | return -ENOENT; | | |
| 1970 | | | |
| 1971 | clone = alloc_engines(e->num_engines); | | |
| 1972 | if (!clone) | | |
| 1973 | goto err_unlock; | | |
| 1974 | | | |
| 1975 | for (n = 0; n < e->num_engines; n++) { | | |
| 1976 | struct intel_engine_cs *engine; | | |
| 1977 | | | |
| 1978 | if (!e->engines[n]) { | | |
| 1979 | clone->engines[n] = NULL; | | |
| 1980 | continue; | | |
| 1981 | } | | |
| 1982 | engine = e->engines[n]->engine; | | |
| 1983 | | | |
| 1984 | /* | | |
| 1985 | * Virtual engines are singletons; they can only exist | | |
| 1986 | * inside a single context, because they embed their | | |
| 1987 | * HW context... As each virtual context implies a single | | |
| 1988 | * timeline (each engine can only dequeue a single request | | |
| 1989 | * at any time), it would be surprising for two contexts | | |
| 1990 | * to use the same engine. So let's create a copy of | | |
| 1991 | * the virtual engine instead. | | |
| 1992 | */ | | |
| 1993 | if (intel_engine_is_virtual(engine)) | | |
| 1994 | clone->engines[n] = | | |
| 1995 | intel_execlists_clone_virtual(engine); | | |
| 1996 | else | | |
| 1997 | clone->engines[n] = intel_context_create(engine); | | |
| 1998 | if (IS_ERR_OR_NULL(clone->engines[n])) { | | |
| 1999 | __free_engines(clone, n); | | |
| 2000 | goto err_unlock; | | |
| 2001 | } | | |
| 2002 | | | |
| 2003 | intel_context_set_gem(clone->engines[n], dst); | | |
| 2004 | } | | |
| 2005 | clone->num_engines = n; | | |
| 2006 | i915_sw_fence_complete(&e->fence); | | |
| 2007 | | | |
| 2008 | /* Serialised by constructor */ | | |
| 2009 | engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1)); | | |
| 2010 | if (user_engines) | | |
| 2011 | i915_gem_context_set_user_engines(dst); | | |
| 2012 | else | | |
| 2013 | i915_gem_context_clear_user_engines(dst); | | |
| 2014 | return 0; | | |
| 2015 | | | |
| 2016 | err_unlock: | | |
| 2017 | i915_sw_fence_complete(&e->fence); | | |
| 2018 | return -ENOMEM; | | |
| 2019 | } | | |
| 2020 | | | |
| 2021 | static int clone_flags(struct i915_gem_context *dst, | | |
| 2022 | struct i915_gem_context *src) | | |
| 2023 | { | | |
| 2024 | dst->user_flags = src->user_flags; | | |
| 2025 | return 0; | | |
| 2026 | } | | |
| 2027 | | | |
| 2028 | static int clone_schedattr(struct i915_gem_context *dst, | | |
| 2029 | struct i915_gem_context *src) | | |
| 2030 | { | | |
| 2031 | dst->sched = src->sched; | | |
| 2032 | return 0; | | |
| 2033 | } | | |
| 2034 | | | |
| 2035 | static int clone_sseu(struct i915_gem_context *dst, | | |
| 2036 | struct i915_gem_context *src) | | |
| 2037 | { | | |
| 2038 | struct i915_gem_engines *e = i915_gem_context_lock_engines(src); | | |
| 2039 | struct i915_gem_engines *clone; | | |
| 2040 | unsigned long n; | | |
| 2041 | int err; | | |
| 2042 | | | |
| 2043 | /* no locking required; sole access under constructor*/ | | |
| 2044 | clone = __context_engines_static(dst); | | |
| 2045 | if (e->num_engines != clone->num_engines) { | | |
| 2046 | err = -EINVAL; | | |
| 2047 | goto unlock; | | |
| 2048 | } | | |
| 2049 | | | |
| 2050 | for (n = 0; n < e->num_engines; n++) { | | |
| 2051 | struct intel_context *ce = e->engines[n]; | | |
| 2052 | | | |
| 2053 | if (clone->engines[n]->engine->class != ce->engine->class) { | | |
| 2054 | /* Must have compatible engine maps! */ | | |
| 2055 | err = -EINVAL; | | |
| 2056 | goto unlock; | | |
| 2057 | } | | |
| 2058 | | | |
| 2059 | /* serialises with set_sseu */ | | |
| 2060 | err = intel_context_lock_pinned(ce); | | |
| 2061 | if (err) | | |
| 2062 | goto unlock; | | |
| 2063 | | | |
| 2064 | clone->engines[n]->sseu = ce->sseu; | | |
| 2065 | intel_context_unlock_pinned(ce); | | |
| 2066 | } | | |
| 2067 | | | |
| 2068 | err = 0; | | |
| 2069 | unlock: | | |
| 2070 | i915_gem_context_unlock_engines(src); | | |
| 2071 | return err; | | |
| 2072 | } | | |
| 2073 | | | |
| 2074 | static int clone_timeline(struct i915_gem_context *dst, | | |
| 2075 | struct i915_gem_context *src) | | |
| 2076 | { | | |
| 2077 | if (src->timeline) | | |
| 2078 | __assign_timeline(dst, src->timeline); | | |
| 2079 | | | |
| 2080 | return 0; | | |
| 2081 | } | | |
| 2082 | | | |
| 2083 | static int clone_vm(struct i915_gem_context *dst, | | |
| 2084 | struct i915_gem_context *src) | | |
| 2085 | { | | |
| 2086 | struct i915_address_space *vm; | | |
| 2087 | int err = 0; | | |
| 2088 | | | |
| 2089 | if (!rcu_access_pointer(src->vm)) | | |
| 2090 | return 0; | | |
| 2091 | | | |
| 2092 | rcu_read_lock(); | | |
| 2093 | vm = context_get_vm_rcu(src); | | |
| 2094 | rcu_read_unlock(); | | |
| 2095 | | | |
| 2096 | if (!mutex_lock_interruptible(&dst->mutex)) { | | |
| 2097 | __assign_ppgtt(dst, vm); | | |
| 2098 | mutex_unlock(&dst->mutex); | | |
| 2099 | } else { | | |
| 2100 | err = -EINTR; | | |
| 2101 | } | | |
| 2102 | | | |
| 2103 | i915_vm_put(vm); | | |
| 2104 | return err; | | |
| 2105 | } | | |
| 2106 | | | |
| 2107 | static int create_clone(struct i915_user_extension __user *ext, void *data) | | |
| 2108 | { | | |
| 2109 | static int (* const fn[])(struct i915_gem_context *dst, | | |
| 2110 | struct i915_gem_context *src) = { | | |
| 2111 | #define MAP(x, y) [ilog2(I915_CONTEXT_CLONE_##x)] = y | | |
| 2112 | MAP(ENGINES, clone_engines), | | |
| 2113 | MAP(FLAGS, clone_flags), | | |
| 2114 | MAP(SCHEDATTR, clone_schedattr), | | |
| 2115 | MAP(SSEU, clone_sseu), | | |
| 2116 | MAP(TIMELINE, clone_timeline), | | |
| 2117 | MAP(VM, clone_vm), | | |
| 2118 | #undef MAP | | |
| 2119 | }; | | |
| 2120 | struct drm_i915_gem_context_create_ext_clone local; | | |
| 2121 | const struct create_ext *arg = data; | | |
| 2122 | struct i915_gem_context *dst = arg->ctx; | | |
| 2123 | struct i915_gem_context *src; | | |
| 2124 | int err, bit; | | |
| 2125 | | | |
| 2126 | if (copy_from_user(&local, ext, sizeof(local))) | | |
| 2127 | return -EFAULT; | | |
| 2128 | | | |
| 2129 | BUILD_BUG_ON(GENMASK(BITS_PER_TYPE(local.flags) - 1, ARRAY_SIZE(fn)) != | | |
| 2130 | I915_CONTEXT_CLONE_UNKNOWN); | | |
| 2131 | | | |
| 2132 | if (local.flags & I915_CONTEXT_CLONE_UNKNOWN) | | |
| 2133 | return -EINVAL; | | |
| 2134 | | | |
| 2135 | if (local.rsvd) | | |
| 2136 | return -EINVAL; | | |
| 2137 | | | |
| 2138 | rcu_read_lock(); | | |
| 2139 | src = __i915_gem_context_lookup_rcu(arg->fpriv, local.clone_id); | | |
| 2140 | rcu_read_unlock(); | | |
| 2141 | if (!src) | | |
| 2142 | return -ENOENT; | | |
| 2143 | | | |
| 2144 | GEM_BUG_ON(src == dst); | | |
| 2145 | | | |
| 2146 | for (bit = 0; bit < ARRAY_SIZE(fn); bit++) { | | |
| 2147 | if (!(local.flags & BIT(bit))) | | |
| 2148 | continue; | | |
| 2149 | | | |
| 2150 | err = fn[bit](dst, src); | | |
| 2151 | if (err) | | |
| 2152 | return err; | | |
| 2153 | } | | |
| 2154 | | | |
| 2155 | return 0; | | |
| 2156 | } | 1963 | } |
| 2157 | | 1964 | |
| 2158 | static const i915_user_extension_fn create_extensions[] = { | 1965 | static const i915_user_extension_fn create_extensions[] = { |
| 2159 | [I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam, | 1966 | [I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam, |
| 2160 | [I915_CONTEXT_CREATE_EXT_CLONE] = create_clone, | 1967 | [I915_CONTEXT_CREATE_EXT_CLONE] = invalid_ext, |
| 2161 | }; | 1968 | }; |
| 2162 | | 1969 | |
| 2163 | static bool client_is_banned(struct drm_i915_file_private *file_priv) | 1970 | static bool client_is_banned(struct drm_i915_file_private *file_priv) |