File: | dev/pci/drm/i915/display/intel_fbdev.c |
Warning: | line 51, column 9 Access to field 'frontbuffer' results in a dereference of a null pointer (loaded from field 'fb') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright © 2007 David Airlie | |||
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 | |||
21 | * DEALINGS IN THE SOFTWARE. | |||
22 | * | |||
23 | * Authors: | |||
24 | * David Airlie | |||
25 | */ | |||
26 | ||||
27 | #include <linux/async.h> | |||
28 | #include <linux/console.h> | |||
29 | #include <linux/delay.h> | |||
30 | #include <linux/errno.h> | |||
31 | #include <linux/init.h> | |||
32 | #include <linux/kernel.h> | |||
33 | #include <linux/mm.h> | |||
34 | #include <linux/module.h> | |||
35 | #include <linux/string.h> | |||
36 | #include <linux/sysrq.h> | |||
37 | #include <linux/tty.h> | |||
38 | #include <linux/vga_switcheroo.h> | |||
39 | ||||
40 | #include <drm/drm_crtc.h> | |||
41 | #include <drm/drm_fb_helper.h> | |||
42 | #include <drm/drm_fourcc.h> | |||
43 | ||||
44 | #include "i915_drv.h" | |||
45 | #include "intel_display_types.h" | |||
46 | #include "intel_fbdev.h" | |||
47 | #include "intel_frontbuffer.h" | |||
48 | ||||
49 | static struct intel_frontbuffer *to_frontbuffer(struct intel_fbdev *ifbdev) | |||
50 | { | |||
51 | return ifbdev->fb->frontbuffer; | |||
| ||||
52 | } | |||
53 | ||||
54 | static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev) | |||
55 | { | |||
56 | intel_frontbuffer_invalidate(to_frontbuffer(ifbdev), ORIGIN_CPU); | |||
57 | } | |||
58 | ||||
59 | static int intel_fbdev_set_par(struct fb_info *info) | |||
60 | { | |||
61 | struct drm_fb_helper *fb_helper = info->par; | |||
62 | struct intel_fbdev *ifbdev = | |||
63 | container_of(fb_helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (fb_helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); | |||
64 | int ret; | |||
65 | ||||
66 | ret = drm_fb_helper_set_par(info); | |||
67 | if (ret == 0) | |||
68 | intel_fbdev_invalidate(ifbdev); | |||
69 | ||||
70 | return ret; | |||
71 | } | |||
72 | ||||
73 | static int intel_fbdev_blank(int blank, struct fb_info *info) | |||
74 | { | |||
75 | struct drm_fb_helper *fb_helper = info->par; | |||
76 | struct intel_fbdev *ifbdev = | |||
77 | container_of(fb_helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (fb_helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); | |||
78 | int ret; | |||
79 | ||||
80 | ret = drm_fb_helper_blank(blank, info); | |||
81 | if (ret == 0) | |||
82 | intel_fbdev_invalidate(ifbdev); | |||
83 | ||||
84 | return ret; | |||
85 | } | |||
86 | ||||
87 | static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, | |||
88 | struct fb_info *info) | |||
89 | { | |||
90 | struct drm_fb_helper *fb_helper = info->par; | |||
91 | struct intel_fbdev *ifbdev = | |||
92 | container_of(fb_helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (fb_helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); | |||
93 | int ret; | |||
94 | ||||
95 | ret = drm_fb_helper_pan_display(var, info); | |||
96 | if (ret == 0) | |||
97 | intel_fbdev_invalidate(ifbdev); | |||
98 | ||||
99 | return ret; | |||
100 | } | |||
101 | ||||
102 | static const struct fb_ops intelfb_ops = { | |||
103 | #ifdef notyet | |||
104 | .owner = THIS_MODULE((void *)0), | |||
105 | DRM_FB_HELPER_DEFAULT_OPS.fb_set_par = drm_fb_helper_set_par, | |||
106 | #endif | |||
107 | .fb_set_par = intel_fbdev_set_par, | |||
108 | #ifdef notyet | |||
109 | .fb_fillrect = drm_fb_helper_cfb_fillrect, | |||
110 | .fb_copyarea = drm_fb_helper_cfb_copyarea, | |||
111 | .fb_imageblit = drm_fb_helper_cfb_imageblit, | |||
112 | .fb_pan_display = intel_fbdev_pan_display, | |||
113 | .fb_blank = intel_fbdev_blank, | |||
114 | #endif | |||
115 | }; | |||
116 | ||||
117 | static int intelfb_alloc(struct drm_fb_helper *helper, | |||
118 | struct drm_fb_helper_surface_size *sizes) | |||
119 | { | |||
120 | struct intel_fbdev *ifbdev = | |||
121 | container_of(helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); | |||
122 | struct drm_framebuffer *fb; | |||
123 | struct drm_device *dev = helper->dev; | |||
124 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); | |||
125 | struct drm_mode_fb_cmd2 mode_cmd = {}; | |||
126 | struct drm_i915_gem_object *obj; | |||
127 | int size; | |||
128 | ||||
129 | /* we don't do packed 24bpp */ | |||
130 | if (sizes->surface_bpp == 24) | |||
131 | sizes->surface_bpp = 32; | |||
132 | ||||
133 | mode_cmd.width = sizes->surface_width; | |||
134 | mode_cmd.height = sizes->surface_height; | |||
135 | ||||
136 | mode_cmd.pitches[0] = roundup2(mode_cmd.width *(((mode_cmd.width * (((sizes->surface_bpp) + ((8) - 1)) / ( 8))) + ((64) - 1)) & (~((__typeof(mode_cmd.width * (((sizes ->surface_bpp) + ((8) - 1)) / (8))))(64) - 1))) | |||
137 | DIV_ROUND_UP(sizes->surface_bpp, 8), 64)(((mode_cmd.width * (((sizes->surface_bpp) + ((8) - 1)) / ( 8))) + ((64) - 1)) & (~((__typeof(mode_cmd.width * (((sizes ->surface_bpp) + ((8) - 1)) / (8))))(64) - 1))); | |||
138 | mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, | |||
139 | sizes->surface_depth); | |||
140 | ||||
141 | size = mode_cmd.pitches[0] * mode_cmd.height; | |||
142 | size = PAGE_ALIGN(size)(((size) + ((1 << 12) - 1)) & ~((1 << 12) - 1 )); | |||
143 | ||||
144 | /* If the FB is too big, just don't use it since fbdev is not very | |||
145 | * important and we should probably use that space with FBC or other | |||
146 | * features. */ | |||
147 | obj = ERR_PTR(-ENODEV19); | |||
148 | if (size * 2 < dev_priv->stolen_usable_size) | |||
149 | obj = i915_gem_object_create_stolen(dev_priv, size); | |||
150 | if (IS_ERR(obj)) | |||
151 | obj = i915_gem_object_create_shmem(dev_priv, size); | |||
152 | if (IS_ERR(obj)) { | |||
153 | drm_err(&dev_priv->drm, "failed to allocate framebuffer\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "failed to allocate framebuffer\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); | |||
154 | return PTR_ERR(obj); | |||
155 | } | |||
156 | ||||
157 | fb = intel_framebuffer_create(obj, &mode_cmd); | |||
158 | i915_gem_object_put(obj); | |||
159 | if (IS_ERR(fb)) | |||
160 | return PTR_ERR(fb); | |||
161 | ||||
162 | ifbdev->fb = to_intel_framebuffer(fb)({ const __typeof( ((struct intel_framebuffer *)0)->base ) *__mptr = (fb); (struct intel_framebuffer *)( (char *)__mptr - __builtin_offsetof(struct intel_framebuffer, base) );}); | |||
163 | return 0; | |||
164 | } | |||
165 | ||||
166 | static int intelfb_create(struct drm_fb_helper *helper, | |||
167 | struct drm_fb_helper_surface_size *sizes) | |||
168 | { | |||
169 | struct intel_fbdev *ifbdev = | |||
170 | container_of(helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); | |||
171 | struct intel_framebuffer *intel_fb = ifbdev->fb; | |||
172 | struct drm_device *dev = helper->dev; | |||
173 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); | |||
174 | struct pci_dev *pdev = dev_priv->drm.pdev; | |||
175 | struct i915_ggtt *ggtt = &dev_priv->ggtt; | |||
176 | const struct i915_ggtt_view view = { | |||
177 | .type = I915_GGTT_VIEW_NORMAL, | |||
178 | }; | |||
179 | intel_wakeref_t wakeref; | |||
180 | struct fb_info *info; | |||
181 | struct i915_vma *vma; | |||
182 | unsigned long flags = 0; | |||
183 | bool_Bool prealloc = false0; | |||
184 | void __iomem *vaddr; | |||
185 | int ret; | |||
186 | ||||
187 | if (intel_fb && | |||
| ||||
188 | (sizes->fb_width > intel_fb->base.width || | |||
189 | sizes->fb_height > intel_fb->base.height)) { | |||
190 | drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) | |||
191 | "BIOS fb too small (%dx%d), we require (%dx%d),"drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) | |||
192 | " releasing it\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) | |||
193 | intel_fb->base.width, intel_fb->base.height,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) | |||
194 | sizes->fb_width, sizes->fb_height)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height); | |||
195 | drm_framebuffer_put(&intel_fb->base); | |||
196 | intel_fb = ifbdev->fb = NULL((void *)0); | |||
197 | } | |||
198 | if (!intel_fb
&intel_fb->base)->obj[0]) : ((void *)0)))); if (__ret ) printf("%s %s: " "%s", dev_driver_string(((dev))->dev), "" , "drm_WARN_ON(" "!((&intel_fb->base) ? to_intel_bo((&intel_fb->base)->obj[0]) : ((void *)0))" ")"); __builtin_expect(!!(__ret), 0); })) { | |||
199 | drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "no BIOS fb, allocating a new one\n" ) | |||
200 | "no BIOS fb, allocating a new one\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "no BIOS fb, allocating a new one\n" ); | |||
201 | ret = intelfb_alloc(helper, sizes); | |||
202 | if (ret) | |||
203 | return ret; | |||
204 | intel_fb = ifbdev->fb; | |||
205 | } else { | |||
206 | drm_dbg_kms(&dev_priv->drm, "re-using BIOS fb\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "re-using BIOS fb\n" ); | |||
207 | prealloc = true1; | |||
208 | sizes->fb_width = intel_fb->base.width; | |||
209 | sizes->fb_height = intel_fb->base.height; | |||
210 | } | |||
211 | ||||
212 | wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); | |||
213 | ||||
214 | /* Pin the GGTT vma for our access via info->screen_base. | |||
215 | * This also validates that any existing fb inherited from the | |||
216 | * BIOS is suitable for own access. | |||
217 | */ | |||
218 | vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, | |||
219 | &view, false0, &flags); | |||
220 | if (IS_ERR(vma)) { | |||
221 | ret = PTR_ERR(vma); | |||
222 | goto out_unlock; | |||
223 | } | |||
224 | ||||
225 | intel_frontbuffer_flush(to_frontbuffer(ifbdev), ORIGIN_DIRTYFB); | |||
226 | ||||
227 | info = drm_fb_helper_alloc_fbi(helper); | |||
228 | if (IS_ERR(info)) { | |||
229 | drm_err(&dev_priv->drm, "Failed to allocate fb_info\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Failed to allocate fb_info\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); | |||
230 | ret = PTR_ERR(info); | |||
231 | goto out_unpin; | |||
232 | } | |||
233 | ||||
234 | ifbdev->helper.fb = &ifbdev->fb->base; | |||
235 | ||||
236 | info->fbops = &intelfb_ops; | |||
237 | ||||
238 | #ifdef __linux__ | |||
239 | /* setup aperture base/size for vesafb takeover */ | |||
240 | info->apertures->ranges[0].base = ggtt->gmadr.start; | |||
241 | info->apertures->ranges[0].size = ggtt->mappable_end; | |||
242 | ||||
243 | /* Our framebuffer is the entirety of fbdev's system memory */ | |||
244 | info->fix.smem_start = | |||
245 | (unsigned long)(ggtt->gmadr.start + vma->node.start); | |||
246 | info->fix.smem_len = vma->node.size; | |||
247 | ||||
248 | vaddr = i915_vma_pin_iomap(vma); | |||
249 | if (IS_ERR(vaddr)) { | |||
250 | drm_err(&dev_priv->drm,printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Failed to remap framebuffer into virtual memory\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__) | |||
251 | "Failed to remap framebuffer into virtual memory\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Failed to remap framebuffer into virtual memory\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); | |||
252 | ret = PTR_ERR(vaddr); | |||
253 | goto out_unpin; | |||
254 | } | |||
255 | info->screen_base = vaddr; | |||
256 | info->screen_size = vma->node.size; | |||
257 | ||||
258 | drm_fb_helper_fill_info(info, &ifbdev->helper, sizes); | |||
259 | ||||
260 | /* If the object is shmemfs backed, it will have given us zeroed pages. | |||
261 | * If the object is stolen however, it will be full of whatever | |||
262 | * garbage was left in there. | |||
263 | */ | |||
264 | if (vma->obj->stolen && !prealloc) | |||
265 | memset_io(info->screen_base, 0, info->screen_size)__builtin_memset((info->screen_base), (0), (info->screen_size )); | |||
266 | ||||
267 | /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ | |||
268 | #else | |||
269 | { | |||
270 | struct drm_framebuffer *fb = ifbdev->helper.fb; | |||
271 | struct rasops_info *ri = &dev_priv->ro; | |||
272 | bus_space_handle_t bsh; | |||
273 | int err; | |||
274 | ||||
275 | vaddr = i915_vma_pin_iomap(vma); | |||
276 | if (IS_ERR(vaddr)) { | |||
277 | DRM_ERROR("Failed to remap framebuffer into virtual memory\n")__drm_err("Failed to remap framebuffer into virtual memory\n" ); | |||
278 | ret = PTR_ERR(vaddr); | |||
279 | goto out_unpin; | |||
280 | } | |||
281 | ||||
282 | drm_fb_helper_fill_info(info, &ifbdev->helper, sizes); | |||
283 | ||||
284 | ri->ri_bits = vaddr; | |||
285 | ri->ri_depth = fb->format->cpp[0] * 8; | |||
286 | ri->ri_stride = fb->pitches[0]; | |||
287 | ri->ri_width = sizes->fb_width; | |||
288 | ri->ri_height = sizes->fb_height; | |||
289 | ||||
290 | switch (fb->format->format) { | |||
291 | case DRM_FORMAT_XRGB8888((__u32)('X') | ((__u32)('R') << 8) | ((__u32)('2') << 16) | ((__u32)('4') << 24)): | |||
292 | ri->ri_rnum = 8; | |||
293 | ri->ri_rpos = 16; | |||
294 | ri->ri_gnum = 8; | |||
295 | ri->ri_gpos = 8; | |||
296 | ri->ri_bnum = 8; | |||
297 | ri->ri_bpos = 0; | |||
298 | break; | |||
299 | case DRM_FORMAT_RGB565((__u32)('R') | ((__u32)('G') << 8) | ((__u32)('1') << 16) | ((__u32)('6') << 24)): | |||
300 | ri->ri_rnum = 5; | |||
301 | ri->ri_rpos = 11; | |||
302 | ri->ri_gnum = 6; | |||
303 | ri->ri_gpos = 5; | |||
304 | ri->ri_bnum = 5; | |||
305 | ri->ri_bpos = 0; | |||
306 | break; | |||
307 | } | |||
308 | ||||
309 | if (vma->obj->stolen && !prealloc) | |||
310 | memset(ri->ri_bits, 0, vma->node.size)__builtin_memset((ri->ri_bits), (0), (vma->node.size)); | |||
311 | } | |||
312 | #endif | |||
313 | ||||
314 | drm_dbg_kms(&dev_priv->drm, "allocated %dx%d fb: 0x%08x\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "allocated %dx%d fb: 0x%08x\n" , ifbdev->fb->base.width, ifbdev->fb->base.height , i915_ggtt_offset(vma)) | |||
315 | ifbdev->fb->base.width, ifbdev->fb->base.height,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "allocated %dx%d fb: 0x%08x\n" , ifbdev->fb->base.width, ifbdev->fb->base.height , i915_ggtt_offset(vma)) | |||
316 | i915_ggtt_offset(vma))drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "allocated %dx%d fb: 0x%08x\n" , ifbdev->fb->base.width, ifbdev->fb->base.height , i915_ggtt_offset(vma)); | |||
317 | ifbdev->vma = vma; | |||
318 | ifbdev->vma_flags = flags; | |||
319 | ||||
320 | intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); | |||
321 | vga_switcheroo_client_fb_set(pdev, info); | |||
322 | return 0; | |||
323 | ||||
324 | out_unpin: | |||
325 | intel_unpin_fb_vma(vma, flags); | |||
326 | out_unlock: | |||
327 | intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); | |||
328 | return ret; | |||
329 | } | |||
330 | ||||
331 | static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { | |||
332 | .fb_probe = intelfb_create, | |||
333 | }; | |||
334 | ||||
335 | static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) | |||
336 | { | |||
337 | /* We rely on the object-free to release the VMA pinning for | |||
338 | * the info->screen_base mmaping. Leaking the VMA is simpler than | |||
339 | * trying to rectify all the possible error paths leading here. | |||
340 | */ | |||
341 | ||||
342 | drm_fb_helper_fini(&ifbdev->helper); | |||
343 | ||||
344 | if (ifbdev->vma) | |||
345 | intel_unpin_fb_vma(ifbdev->vma, ifbdev->vma_flags); | |||
346 | ||||
347 | if (ifbdev->fb) | |||
348 | drm_framebuffer_remove(&ifbdev->fb->base); | |||
349 | ||||
350 | kfree(ifbdev); | |||
351 | } | |||
352 | ||||
353 | /* | |||
354 | * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible. | |||
355 | * The core display code will have read out the current plane configuration, | |||
356 | * so we use that to figure out if there's an object for us to use as the | |||
357 | * fb, and if so, we re-use it for the fbdev configuration. | |||
358 | * | |||
359 | * Note we only support a single fb shared across pipes for boot (mostly for | |||
360 | * fbcon), so we just find the biggest and use that. | |||
361 | */ | |||
362 | static bool_Bool intel_fbdev_init_bios(struct drm_device *dev, | |||
363 | struct intel_fbdev *ifbdev) | |||
364 | { | |||
365 | struct drm_i915_privateinteldrm_softc *i915 = to_i915(dev); | |||
366 | struct intel_framebuffer *fb = NULL((void *)0); | |||
367 | struct drm_crtc *crtc; | |||
368 | struct intel_crtc *intel_crtc; | |||
369 | unsigned int max_size = 0; | |||
370 | ||||
371 | /* Find the largest fb */ | |||
372 | for_each_crtc(dev, crtc)for (crtc = ({ const __typeof( ((__typeof(*crtc) *)0)->head ) *__mptr = ((&(dev)->mode_config.crtc_list)->next ); (__typeof(*crtc) *)( (char *)__mptr - __builtin_offsetof(__typeof (*crtc), head) );}); &crtc->head != (&(dev)->mode_config .crtc_list); crtc = ({ const __typeof( ((__typeof(*crtc) *)0) ->head ) *__mptr = (crtc->head.next); (__typeof(*crtc) * )( (char *)__mptr - __builtin_offsetof(__typeof(*crtc), head) );})) { | |||
373 | struct drm_i915_gem_object *obj = | |||
374 | intel_fb_obj(crtc->primary->state->fb)((crtc->primary->state->fb) ? to_intel_bo((crtc-> primary->state->fb)->obj[0]) : ((void *)0)); | |||
375 | intel_crtc = to_intel_crtc(crtc)({ const __typeof( ((struct intel_crtc *)0)->base ) *__mptr = (crtc); (struct intel_crtc *)( (char *)__mptr - __builtin_offsetof (struct intel_crtc, base) );}); | |||
376 | ||||
377 | if (!crtc->state->active || !obj) { | |||
378 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active or no fb, skipping\n" , ((intel_crtc->pipe) + 'A')) | |||
379 | "pipe %c not active or no fb, skipping\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active or no fb, skipping\n" , ((intel_crtc->pipe) + 'A')) | |||
380 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active or no fb, skipping\n" , ((intel_crtc->pipe) + 'A')); | |||
381 | continue; | |||
382 | } | |||
383 | ||||
384 | if (obj->base.size > max_size) { | |||
385 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "found possible fb from plane %c\n" , ((intel_crtc->pipe) + 'A')) | |||
386 | "found possible fb from plane %c\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "found possible fb from plane %c\n" , ((intel_crtc->pipe) + 'A')) | |||
387 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "found possible fb from plane %c\n" , ((intel_crtc->pipe) + 'A')); | |||
388 | fb = to_intel_framebuffer(crtc->primary->state->fb)({ const __typeof( ((struct intel_framebuffer *)0)->base ) *__mptr = (crtc->primary->state->fb); (struct intel_framebuffer *)( (char *)__mptr - __builtin_offsetof(struct intel_framebuffer , base) );}); | |||
389 | max_size = obj->base.size; | |||
390 | } | |||
391 | } | |||
392 | ||||
393 | if (!fb) { | |||
394 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "no active fbs found, not using BIOS config\n" ) | |||
395 | "no active fbs found, not using BIOS config\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "no active fbs found, not using BIOS config\n" ); | |||
396 | goto out; | |||
397 | } | |||
398 | ||||
399 | /* Now make sure all the pipes will fit into it */ | |||
400 | for_each_crtc(dev, crtc)for (crtc = ({ const __typeof( ((__typeof(*crtc) *)0)->head ) *__mptr = ((&(dev)->mode_config.crtc_list)->next ); (__typeof(*crtc) *)( (char *)__mptr - __builtin_offsetof(__typeof (*crtc), head) );}); &crtc->head != (&(dev)->mode_config .crtc_list); crtc = ({ const __typeof( ((__typeof(*crtc) *)0) ->head ) *__mptr = (crtc->head.next); (__typeof(*crtc) * )( (char *)__mptr - __builtin_offsetof(__typeof(*crtc), head) );})) { | |||
401 | unsigned int cur_size; | |||
402 | ||||
403 | intel_crtc = to_intel_crtc(crtc)({ const __typeof( ((struct intel_crtc *)0)->base ) *__mptr = (crtc); (struct intel_crtc *)( (char *)__mptr - __builtin_offsetof (struct intel_crtc, base) );}); | |||
404 | ||||
405 | if (!crtc->state->active) { | |||
406 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active, skipping\n" , ((intel_crtc->pipe) + 'A')) | |||
407 | "pipe %c not active, skipping\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active, skipping\n" , ((intel_crtc->pipe) + 'A')) | |||
408 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active, skipping\n" , ((intel_crtc->pipe) + 'A')); | |||
409 | continue; | |||
410 | } | |||
411 | ||||
412 | drm_dbg_kms(&i915->drm, "checking plane %c for BIOS fb\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "checking plane %c for BIOS fb\n" , ((intel_crtc->pipe) + 'A')) | |||
413 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "checking plane %c for BIOS fb\n" , ((intel_crtc->pipe) + 'A')); | |||
414 | ||||
415 | /* | |||
416 | * See if the plane fb we found above will fit on this | |||
417 | * pipe. Note we need to use the selected fb's pitch and bpp | |||
418 | * rather than the current pipe's, since they differ. | |||
419 | */ | |||
420 | cur_size = crtc->state->adjusted_mode.crtc_hdisplay; | |||
421 | cur_size = cur_size * fb->base.format->cpp[0]; | |||
422 | if (fb->base.pitches[0] < cur_size) { | |||
423 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]) | |||
424 | "fb not wide enough for plane %c (%d vs %d)\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]) | |||
425 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]) | |||
426 | cur_size, fb->base.pitches[0])drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]); | |||
427 | fb = NULL((void *)0); | |||
428 | break; | |||
429 | } | |||
430 | ||||
431 | cur_size = crtc->state->adjusted_mode.crtc_vdisplay; | |||
432 | cur_size = intel_fb_align_height(&fb->base, 0, cur_size); | |||
433 | cur_size *= fb->base.pitches[0]; | |||
434 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) | |||
435 | "pipe %c area: %dx%d, bpp: %d, size: %d\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) | |||
436 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) | |||
437 | crtc->state->adjusted_mode.crtc_hdisplay,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) | |||
438 | crtc->state->adjusted_mode.crtc_vdisplay,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) | |||
439 | fb->base.format->cpp[0] * 8,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) | |||
440 | cur_size)drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size); | |||
441 | ||||
442 | if (cur_size > max_size) { | |||
443 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size) | |||
444 | "fb not big enough for plane %c (%d vs %d)\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size) | |||
445 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size) | |||
446 | cur_size, max_size)drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size); | |||
447 | fb = NULL((void *)0); | |||
448 | break; | |||
449 | } | |||
450 | ||||
451 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size) | |||
452 | "fb big enough for plane %c (%d >= %d)\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size) | |||
453 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size) | |||
454 | max_size, cur_size)drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size); | |||
455 | } | |||
456 | ||||
457 | if (!fb) { | |||
458 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "BIOS fb not suitable for all pipes, not using\n" ) | |||
459 | "BIOS fb not suitable for all pipes, not using\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "BIOS fb not suitable for all pipes, not using\n" ); | |||
460 | goto out; | |||
461 | } | |||
462 | ||||
463 | ifbdev->preferred_bpp = fb->base.format->cpp[0] * 8; | |||
464 | ifbdev->fb = fb; | |||
465 | ||||
466 | drm_framebuffer_get(&ifbdev->fb->base); | |||
467 | ||||
468 | /* Final pass to check if any active pipes don't have fbs */ | |||
469 | for_each_crtc(dev, crtc)for (crtc = ({ const __typeof( ((__typeof(*crtc) *)0)->head ) *__mptr = ((&(dev)->mode_config.crtc_list)->next ); (__typeof(*crtc) *)( (char *)__mptr - __builtin_offsetof(__typeof (*crtc), head) );}); &crtc->head != (&(dev)->mode_config .crtc_list); crtc = ({ const __typeof( ((__typeof(*crtc) *)0) ->head ) *__mptr = (crtc->head.next); (__typeof(*crtc) * )( (char *)__mptr - __builtin_offsetof(__typeof(*crtc), head) );})) { | |||
470 | intel_crtc = to_intel_crtc(crtc)({ const __typeof( ((struct intel_crtc *)0)->base ) *__mptr = (crtc); (struct intel_crtc *)( (char *)__mptr - __builtin_offsetof (struct intel_crtc, base) );}); | |||
471 | ||||
472 | if (!crtc->state->active) | |||
473 | continue; | |||
474 | ||||
475 | drm_WARN(dev, !crtc->primary->state->fb,({ int __ret = !!(!crtc->primary->state->fb); if (__ret ) printf("%s %s: " "re-used BIOS config but lost an fb on crtc %d\n" , dev_driver_string((dev)->dev), "", crtc->base.id); __builtin_expect (!!(__ret), 0); }) | |||
476 | "re-used BIOS config but lost an fb on crtc %d\n",({ int __ret = !!(!crtc->primary->state->fb); if (__ret ) printf("%s %s: " "re-used BIOS config but lost an fb on crtc %d\n" , dev_driver_string((dev)->dev), "", crtc->base.id); __builtin_expect (!!(__ret), 0); }) | |||
477 | crtc->base.id)({ int __ret = !!(!crtc->primary->state->fb); if (__ret ) printf("%s %s: " "re-used BIOS config but lost an fb on crtc %d\n" , dev_driver_string((dev)->dev), "", crtc->base.id); __builtin_expect (!!(__ret), 0); }); | |||
478 | } | |||
479 | ||||
480 | ||||
481 | drm_dbg_kms(&i915->drm, "using BIOS fb for initial console\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "using BIOS fb for initial console\n" ); | |||
482 | return true1; | |||
483 | ||||
484 | out: | |||
485 | ||||
486 | return false0; | |||
487 | } | |||
488 | ||||
489 | static void intel_fbdev_suspend_worker(struct work_struct *work) | |||
490 | { | |||
491 | intel_fbdev_set_suspend(&container_of(work,({ const __typeof( ((struct inteldrm_softc *)0)->fbdev_suspend_work ) *__mptr = (work); (struct inteldrm_softc *)( (char *)__mptr - __builtin_offsetof(struct inteldrm_softc, fbdev_suspend_work ) );}) | |||
492 | struct drm_i915_private,({ const __typeof( ((struct inteldrm_softc *)0)->fbdev_suspend_work ) *__mptr = (work); (struct inteldrm_softc *)( (char *)__mptr - __builtin_offsetof(struct inteldrm_softc, fbdev_suspend_work ) );}) | |||
493 | fbdev_suspend_work)({ const __typeof( ((struct inteldrm_softc *)0)->fbdev_suspend_work ) *__mptr = (work); (struct inteldrm_softc *)( (char *)__mptr - __builtin_offsetof(struct inteldrm_softc, fbdev_suspend_work ) );})->drm, | |||
494 | FBINFO_STATE_RUNNING0, | |||
495 | true1); | |||
496 | } | |||
497 | ||||
498 | int intel_fbdev_init(struct drm_device *dev) | |||
499 | { | |||
500 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); | |||
501 | struct intel_fbdev *ifbdev; | |||
502 | int ret; | |||
503 | ||||
504 | if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv))({ int __ret = !!((!((&(dev_priv)->__info)->pipe_mask != 0))); if (__ret) printf("%s %s: " "%s", dev_driver_string (((dev))->dev), "", "drm_WARN_ON(" "!((&(dev_priv)->__info)->pipe_mask != 0)" ")"); __builtin_expect(!!(__ret), 0); })) | |||
505 | return -ENODEV19; | |||
506 | ||||
507 | ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL(0x0001 | 0x0004)); | |||
508 | if (ifbdev == NULL((void *)0)) | |||
509 | return -ENOMEM12; | |||
510 | ||||
511 | rw_init(&ifbdev->hpd_lock, "hdplk")_rw_init_flags(&ifbdev->hpd_lock, "hdplk", 0, ((void * )0)); | |||
512 | drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs); | |||
513 | ||||
514 | if (!intel_fbdev_init_bios(dev, ifbdev)) | |||
515 | ifbdev->preferred_bpp = 32; | |||
516 | ||||
517 | ret = drm_fb_helper_init(dev, &ifbdev->helper); | |||
518 | if (ret) { | |||
519 | kfree(ifbdev); | |||
520 | return ret; | |||
521 | } | |||
522 | ||||
523 | dev_priv->fbdev = ifbdev; | |||
524 | INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); | |||
525 | ||||
526 | return 0; | |||
527 | } | |||
528 | ||||
529 | static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) | |||
530 | { | |||
531 | struct intel_fbdev *ifbdev = data; | |||
532 | ||||
533 | /* Due to peculiar init order wrt to hpd handling this is separate. */ | |||
534 | if (drm_fb_helper_initial_config(&ifbdev->helper, | |||
535 | ifbdev->preferred_bpp)) | |||
536 | intel_fbdev_unregister(to_i915(ifbdev->helper.dev)); | |||
537 | } | |||
538 | ||||
539 | void intel_fbdev_initial_config_async(struct drm_device *dev) | |||
540 | { | |||
541 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; | |||
542 | ||||
543 | if (!ifbdev) | |||
544 | return; | |||
545 | ||||
546 | ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev); | |||
547 | } | |||
548 | ||||
549 | static void intel_fbdev_sync(struct intel_fbdev *ifbdev) | |||
550 | { | |||
551 | #ifdef __linux__ | |||
552 | if (!ifbdev->cookie) | |||
553 | return; | |||
554 | ||||
555 | /* Only serialises with all preceding async calls, hence +1 */ | |||
556 | async_synchronize_cookie(ifbdev->cookie + 1); | |||
557 | ifbdev->cookie = 0; | |||
558 | #endif | |||
559 | } | |||
560 | ||||
561 | void intel_fbdev_unregister(struct drm_i915_privateinteldrm_softc *dev_priv) | |||
562 | { | |||
563 | struct intel_fbdev *ifbdev = dev_priv->fbdev; | |||
564 | ||||
565 | if (!ifbdev) | |||
566 | return; | |||
567 | ||||
568 | cancel_work_sync(&dev_priv->fbdev_suspend_work); | |||
569 | #ifdef __linux__ | |||
570 | if (!current_is_async()) | |||
571 | intel_fbdev_sync(ifbdev); | |||
572 | #endif | |||
573 | ||||
574 | drm_fb_helper_unregister_fbi(&ifbdev->helper); | |||
575 | } | |||
576 | ||||
577 | void intel_fbdev_fini(struct drm_i915_privateinteldrm_softc *dev_priv) | |||
578 | { | |||
579 | struct intel_fbdev *ifbdev = fetch_and_zero(&dev_priv->fbdev)({ typeof(*&dev_priv->fbdev) __T = *(&dev_priv-> fbdev); *(&dev_priv->fbdev) = (typeof(*&dev_priv-> fbdev))0; __T; }); | |||
580 | ||||
581 | if (!ifbdev) | |||
582 | return; | |||
583 | ||||
584 | intel_fbdev_destroy(ifbdev); | |||
585 | } | |||
586 | ||||
587 | /* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD | |||
588 | * processing, fbdev will perform a full connector reprobe if a hotplug event | |||
589 | * was received while HPD was suspended. | |||
590 | */ | |||
591 | static void intel_fbdev_hpd_set_suspend(struct drm_i915_privateinteldrm_softc *i915, int state) | |||
592 | { | |||
593 | struct intel_fbdev *ifbdev = i915->fbdev; | |||
594 | bool_Bool send_hpd = false0; | |||
595 | ||||
596 | mutex_lock(&ifbdev->hpd_lock)rw_enter_write(&ifbdev->hpd_lock); | |||
597 | ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED1; | |||
598 | send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting; | |||
599 | ifbdev->hpd_waiting = false0; | |||
600 | mutex_unlock(&ifbdev->hpd_lock)rw_exit_write(&ifbdev->hpd_lock); | |||
601 | ||||
602 | if (send_hpd) { | |||
603 | drm_dbg_kms(&i915->drm, "Handling delayed fbcon HPD event\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "Handling delayed fbcon HPD event\n" ); | |||
604 | drm_fb_helper_hotplug_event(&ifbdev->helper); | |||
605 | } | |||
606 | } | |||
607 | ||||
608 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool_Bool synchronous) | |||
609 | { | |||
610 | #ifdef __linux__ | |||
611 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); | |||
612 | struct intel_fbdev *ifbdev = dev_priv->fbdev; | |||
613 | struct fb_info *info; | |||
614 | ||||
615 | if (!ifbdev || !ifbdev->vma) | |||
616 | return; | |||
617 | ||||
618 | info = ifbdev->helper.fbdev; | |||
619 | ||||
620 | if (synchronous) { | |||
621 | /* Flush any pending work to turn the console on, and then | |||
622 | * wait to turn it off. It must be synchronous as we are | |||
623 | * about to suspend or unload the driver. | |||
624 | * | |||
625 | * Note that from within the work-handler, we cannot flush | |||
626 | * ourselves, so only flush outstanding work upon suspend! | |||
627 | */ | |||
628 | if (state != FBINFO_STATE_RUNNING0) | |||
629 | flush_work(&dev_priv->fbdev_suspend_work); | |||
630 | ||||
631 | console_lock(); | |||
632 | } else { | |||
633 | /* | |||
634 | * The console lock can be pretty contented on resume due | |||
635 | * to all the printk activity. Try to keep it out of the hot | |||
636 | * path of resume if possible. | |||
637 | */ | |||
638 | drm_WARN_ON(dev, state != FBINFO_STATE_RUNNING)({ int __ret = !!((state != 0)); if (__ret) printf("%s %s: " "%s" , dev_driver_string(((dev))->dev), "", "drm_WARN_ON(" "state != 0" ")"); __builtin_expect(!!(__ret), 0); }); | |||
639 | if (!console_trylock()1) { | |||
640 | /* Don't block our own workqueue as this can | |||
641 | * be run in parallel with other i915.ko tasks. | |||
642 | */ | |||
643 | schedule_work(&dev_priv->fbdev_suspend_work); | |||
644 | return; | |||
645 | } | |||
646 | } | |||
647 | ||||
648 | /* On resume from hibernation: If the object is shmemfs backed, it has | |||
649 | * been restored from swap. If the object is stolen however, it will be | |||
650 | * full of whatever garbage was left in there. | |||
651 | */ | |||
652 | if (state == FBINFO_STATE_RUNNING0 && | |||
653 | intel_fb_obj(&ifbdev->fb->base)((&ifbdev->fb->base) ? to_intel_bo((&ifbdev-> fb->base)->obj[0]) : ((void *)0))->stolen) | |||
654 | memset_io(info->screen_base, 0, info->screen_size)__builtin_memset((info->screen_base), (0), (info->screen_size )); | |||
655 | ||||
656 | drm_fb_helper_set_suspend(&ifbdev->helper, state); | |||
657 | console_unlock(); | |||
658 | ||||
659 | intel_fbdev_hpd_set_suspend(dev_priv, state); | |||
660 | #endif | |||
661 | } | |||
662 | ||||
663 | void intel_fbdev_output_poll_changed(struct drm_device *dev) | |||
664 | { | |||
665 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; | |||
666 | bool_Bool send_hpd; | |||
667 | ||||
668 | if (!ifbdev) | |||
669 | return; | |||
670 | ||||
671 | intel_fbdev_sync(ifbdev); | |||
672 | ||||
673 | mutex_lock(&ifbdev->hpd_lock)rw_enter_write(&ifbdev->hpd_lock); | |||
674 | send_hpd = !ifbdev->hpd_suspended; | |||
675 | ifbdev->hpd_waiting = true1; | |||
676 | mutex_unlock(&ifbdev->hpd_lock)rw_exit_write(&ifbdev->hpd_lock); | |||
677 | ||||
678 | if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup)) | |||
679 | drm_fb_helper_hotplug_event(&ifbdev->helper); | |||
680 | } | |||
681 | ||||
682 | void intel_fbdev_restore_mode(struct drm_device *dev) | |||
683 | { | |||
684 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; | |||
685 | ||||
686 | if (!ifbdev) | |||
687 | return; | |||
688 | ||||
689 | intel_fbdev_sync(ifbdev); | |||
690 | if (!ifbdev->vma) | |||
691 | return; | |||
692 | ||||
693 | if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper) == 0) | |||
694 | intel_fbdev_invalidate(ifbdev); | |||
695 | } |