1 | /* |
2 | * Copyright © 2016 Intel Corporation |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice (including the next |
12 | * paragraph) shall be included in all copies or substantial portions of the |
13 | * Software. |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
21 | * IN THE SOFTWARE. |
22 | * |
23 | */ |
24 | |
25 | #include <linux/pm_domain.h> |
26 | #include <linux/pm_runtime.h> |
27 | #include <linux/iommu.h> |
28 | |
29 | #include <drm/drm_managed.h> |
30 | |
31 | #include "gt/intel_gt.h" |
32 | #include "gt/intel_gt_requests.h" |
33 | #include "gt/mock_engine.h" |
34 | #include "intel_memory_region.h" |
35 | #include "intel_region_ttm.h" |
36 | |
37 | #include "mock_request.h" |
38 | #include "mock_gem_device.h" |
39 | #include "mock_gtt.h" |
40 | #include "mock_uncore.h" |
41 | #include "mock_region.h" |
42 | |
43 | #include "gem/selftests/mock_context.h" |
44 | #include "gem/selftests/mock_gem_object.h" |
45 | |
46 | void mock_device_flush(struct drm_i915_private *i915) |
47 | { |
48 | struct intel_gt *gt = to_gt(i915); |
49 | struct intel_engine_cs *engine; |
50 | enum intel_engine_id id; |
51 | |
52 | do { |
53 | for_each_engine(engine, gt, id) |
54 | mock_engine_flush(engine); |
55 | } while (intel_gt_retire_requests_timeout(gt, MAX_SCHEDULE_TIMEOUT, |
56 | NULL)); |
57 | } |
58 | |
59 | static void mock_device_release(struct drm_device *dev) |
60 | { |
61 | struct drm_i915_private *i915 = to_i915(dev); |
62 | |
63 | if (!i915->do_release) |
64 | goto out; |
65 | |
66 | mock_device_flush(i915); |
67 | intel_gt_driver_remove(gt: to_gt(i915)); |
68 | |
69 | i915_gem_drain_workqueue(i915); |
70 | |
71 | mock_fini_ggtt(ggtt: to_gt(i915)->ggtt); |
72 | destroy_workqueue(wq: i915->unordered_wq); |
73 | destroy_workqueue(wq: i915->wq); |
74 | |
75 | intel_region_ttm_device_fini(dev_priv: i915); |
76 | intel_gt_driver_late_release_all(i915); |
77 | intel_memory_regions_driver_release(i915); |
78 | |
79 | drm_mode_config_cleanup(dev: &i915->drm); |
80 | |
81 | out: |
82 | i915_params_free(params: &i915->params); |
83 | } |
84 | |
85 | static const struct drm_driver mock_driver = { |
86 | .name = "mock" , |
87 | .driver_features = DRIVER_GEM, |
88 | .release = mock_device_release, |
89 | }; |
90 | |
91 | static void release_dev(struct device *dev) |
92 | { |
93 | struct pci_dev *pdev = to_pci_dev(dev); |
94 | |
95 | kfree(objp: pdev); |
96 | } |
97 | |
98 | static int pm_domain_resume(struct device *dev) |
99 | { |
100 | return pm_generic_runtime_resume(dev); |
101 | } |
102 | |
103 | static int pm_domain_suspend(struct device *dev) |
104 | { |
105 | return pm_generic_runtime_suspend(dev); |
106 | } |
107 | |
108 | static struct dev_pm_domain pm_domain = { |
109 | .ops = { |
110 | .runtime_suspend = pm_domain_suspend, |
111 | .runtime_resume = pm_domain_resume, |
112 | }, |
113 | }; |
114 | |
115 | static void mock_gt_probe(struct drm_i915_private *i915) |
116 | { |
117 | i915->gt[0]->name = "Mock GT" ; |
118 | } |
119 | |
120 | static const struct intel_device_info mock_info = { |
121 | .__runtime.graphics.ip.ver = -1, |
122 | .__runtime.page_sizes = (I915_GTT_PAGE_SIZE_4K | |
123 | I915_GTT_PAGE_SIZE_64K | |
124 | I915_GTT_PAGE_SIZE_2M), |
125 | .memory_regions = REGION_SMEM, |
126 | .platform_engine_mask = BIT(0), |
127 | |
128 | /* simply use legacy cache level for mock device */ |
129 | .max_pat_index = 3, |
130 | .cachelevel_to_pat = { |
131 | [I915_CACHE_NONE] = 0, |
132 | [I915_CACHE_LLC] = 1, |
133 | [I915_CACHE_L3_LLC] = 2, |
134 | [I915_CACHE_WT] = 3, |
135 | }, |
136 | }; |
137 | |
138 | struct drm_i915_private *mock_gem_device(void) |
139 | { |
140 | #if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU) |
141 | static struct dev_iommu fake_iommu = { .priv = (void *)-1 }; |
142 | #endif |
143 | struct drm_i915_private *i915; |
144 | struct pci_dev *pdev; |
145 | int ret; |
146 | |
147 | pdev = kzalloc(size: sizeof(*pdev), GFP_KERNEL); |
148 | if (!pdev) |
149 | return NULL; |
150 | device_initialize(dev: &pdev->dev); |
151 | pdev->class = PCI_BASE_CLASS_DISPLAY << 16; |
152 | pdev->dev.release = release_dev; |
153 | dev_set_name(dev: &pdev->dev, name: "mock" ); |
154 | dma_coerce_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(64)); |
155 | |
156 | #if IS_ENABLED(CONFIG_IOMMU_API) && defined(CONFIG_INTEL_IOMMU) |
157 | /* HACK to disable iommu for the fake device; force identity mapping */ |
158 | pdev->dev.iommu = &fake_iommu; |
159 | #endif |
160 | if (!devres_open_group(dev: &pdev->dev, NULL, GFP_KERNEL)) { |
161 | put_device(dev: &pdev->dev); |
162 | return NULL; |
163 | } |
164 | |
165 | i915 = devm_drm_dev_alloc(&pdev->dev, &mock_driver, |
166 | struct drm_i915_private, drm); |
167 | if (IS_ERR(ptr: i915)) { |
168 | pr_err("Failed to allocate mock GEM device: err=%ld\n" , PTR_ERR(i915)); |
169 | devres_release_group(dev: &pdev->dev, NULL); |
170 | put_device(dev: &pdev->dev); |
171 | |
172 | return NULL; |
173 | } |
174 | |
175 | pci_set_drvdata(pdev, data: i915); |
176 | |
177 | /* Device parameters start as a copy of module parameters. */ |
178 | i915_params_copy(dest: &i915->params, src: &i915_modparams); |
179 | |
180 | /* Set up device info and initial runtime info. */ |
181 | intel_device_info_driver_create(i915, device_id: pdev->device, match_info: &mock_info); |
182 | |
183 | intel_display_device_probe(i915); |
184 | |
185 | dev_pm_domain_set(dev: &pdev->dev, pd: &pm_domain); |
186 | pm_runtime_enable(dev: &pdev->dev); |
187 | pm_runtime_dont_use_autosuspend(dev: &pdev->dev); |
188 | if (pm_runtime_enabled(dev: &pdev->dev)) |
189 | WARN_ON(pm_runtime_get_sync(&pdev->dev)); |
190 | |
191 | intel_runtime_pm_init_early(rpm: &i915->runtime_pm); |
192 | /* wakeref tracking has significant overhead */ |
193 | i915->runtime_pm.no_wakeref_tracking = true; |
194 | |
195 | /* Using the global GTT may ask questions about KMS users, so prepare */ |
196 | drm_mode_config_init(dev: &i915->drm); |
197 | |
198 | intel_memory_regions_hw_probe(i915); |
199 | |
200 | spin_lock_init(&i915->gpu_error.lock); |
201 | |
202 | i915_gem_init__mm(i915); |
203 | intel_root_gt_init_early(i915); |
204 | mock_uncore_init(uncore: &i915->uncore, i915); |
205 | atomic_inc(v: &to_gt(i915)->wakeref.count); /* disable; no hw support */ |
206 | to_gt(i915)->awake = -ENODEV; |
207 | mock_gt_probe(i915); |
208 | |
209 | ret = intel_region_ttm_device_init(dev_priv: i915); |
210 | if (ret) |
211 | goto err_ttm; |
212 | |
213 | i915->wq = alloc_ordered_workqueue("mock" , 0); |
214 | if (!i915->wq) |
215 | goto err_drv; |
216 | |
217 | i915->unordered_wq = alloc_workqueue(fmt: "mock-unordered" , flags: 0, max_active: 0); |
218 | if (!i915->unordered_wq) |
219 | goto err_wq; |
220 | |
221 | mock_init_contexts(i915); |
222 | |
223 | /* allocate the ggtt */ |
224 | ret = intel_gt_assign_ggtt(gt: to_gt(i915)); |
225 | if (ret) |
226 | goto err_unlock; |
227 | |
228 | mock_init_ggtt(gt: to_gt(i915)); |
229 | to_gt(i915)->vm = i915_vm_get(vm: &to_gt(i915)->ggtt->vm); |
230 | |
231 | to_gt(i915)->info.engine_mask = BIT(0); |
232 | |
233 | to_gt(i915)->engine[RCS0] = mock_engine(i915, name: "mock" , id: RCS0); |
234 | if (!to_gt(i915)->engine[RCS0]) |
235 | goto err_unlock; |
236 | |
237 | if (mock_engine_init(engine: to_gt(i915)->engine[RCS0])) |
238 | goto err_context; |
239 | |
240 | __clear_bit(I915_WEDGED, &to_gt(i915)->reset.flags); |
241 | intel_engines_driver_register(i915); |
242 | |
243 | i915->do_release = true; |
244 | ida_init(ida: &i915->selftest.mock_region_instances); |
245 | |
246 | return i915; |
247 | |
248 | err_context: |
249 | intel_gt_driver_remove(gt: to_gt(i915)); |
250 | err_unlock: |
251 | destroy_workqueue(wq: i915->unordered_wq); |
252 | err_wq: |
253 | destroy_workqueue(wq: i915->wq); |
254 | err_drv: |
255 | intel_region_ttm_device_fini(dev_priv: i915); |
256 | err_ttm: |
257 | intel_gt_driver_late_release_all(i915); |
258 | intel_memory_regions_driver_release(i915); |
259 | drm_mode_config_cleanup(dev: &i915->drm); |
260 | mock_destroy_device(i915); |
261 | |
262 | return NULL; |
263 | } |
264 | |
265 | void mock_destroy_device(struct drm_i915_private *i915) |
266 | { |
267 | struct device *dev = i915->drm.dev; |
268 | |
269 | devres_release_group(dev, NULL); |
270 | put_device(dev); |
271 | } |
272 | |