diff options
author | Dave Airlie <airlied@redhat.com> | 2018-03-22 16:18:48 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-03-22 16:18:48 -0400 |
commit | 2a2553cc45c889f15a1df0355891a809f17ca43d (patch) | |
tree | e5664857265d4c1d47c5191ea0b71d569ba69613 | |
parent | f3924ae723d84746546bd74bdefc99c17da2a467 (diff) | |
parent | 43bfefedd0281ef476f8154397cd283a710d8baf (diff) |
Merge branch 'vmwgfx-next' of git://people.freedesktop.org/~thomash/linux into drm-next
A relative large set of various improvements for vmwgfx. Some of them
have been around for a while, some are relatively new, but functionality
should have been tested in our standalone repo.
* 'vmwgfx-next' of git://people.freedesktop.org/~thomash/linux:
drm/vmwgfx: Bump version patchlevel and date
drm/vmwgfx: use monotonic event timestamps
drm/vmwgfx: Unpin the screen object backup buffer when not used
drm/vmwgfx: Stricter count of legacy surface device resources
drm/vmwgfx: Use kasprintf
drm/vmwgfx: Get rid of the device-private suspended member
drm/vmwgfx: Improve on hibernation
drm/vmwgfx: Avoid pinning fbdev framebuffers
drm/vmwgfx: Fix multiple command buffer context use
drm/vmwgfx: Use the cpu blit utility for framebuffer to screen target blits
drm/vmwgfx: Add a cpu blit utility that can be used for page-backed bos
drm/ttm: Export the ttm_k[un]map_atomic_prot API.
drm/ttm: Clean up kmap_atomic_prot selection code
drm/vmwgfx: Cursor update fixes
drm/vmwgfx: Send the correct nonblock option for atomic_commit
drm/vmwgfx: Move the stdu vblank event to atomic function
drm/vmwgfx: Move screen object page flip to atomic function
drm/vmwgfx: Remove drm_crtc_arm_vblank_event from atomic flush
drm/vmwgfx: Move surface copy cmd to atomic function
drm/vmwgfx: Avoid iterating over display unit if crtc is available
-rw-r--r-- | drivers/gpu/drm/ttm/ttm_bo_util.c | 85 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/device_include/svga_reg.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_blit.c | 506 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 57 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 80 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 177 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 163 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 280 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 8 | ||||
-rw-r--r-- | include/drm/ttm/ttm_bo_api.h | 4 |
19 files changed, 1227 insertions, 456 deletions
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 1f730b3f18e5..2ebbae6067ab 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c | |||
@@ -255,6 +255,54 @@ static int ttm_copy_io_page(void *dst, void *src, unsigned long page) | |||
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
257 | 257 | ||
258 | #ifdef CONFIG_X86 | ||
259 | #define __ttm_kmap_atomic_prot(__page, __prot) kmap_atomic_prot(__page, __prot) | ||
260 | #define __ttm_kunmap_atomic(__addr) kunmap_atomic(__addr) | ||
261 | #else | ||
262 | #define __ttm_kmap_atomic_prot(__page, __prot) vmap(&__page, 1, 0, __prot) | ||
263 | #define __ttm_kunmap_atomic(__addr) vunmap(__addr) | ||
264 | #endif | ||
265 | |||
266 | |||
267 | /** | ||
268 | * ttm_kmap_atomic_prot - Efficient kernel map of a single page with | ||
269 | * specified page protection. | ||
270 | * | ||
271 | * @page: The page to map. | ||
272 | * @prot: The page protection. | ||
273 | * | ||
274 | * This function maps a TTM page using the kmap_atomic api if available, | ||
275 | * otherwise falls back to vmap. The user must make sure that the | ||
276 | * specified page does not have an aliased mapping with a different caching | ||
277 | * policy unless the architecture explicitly allows it. Also mapping and | ||
278 | * unmapping using this api must be correctly nested. Unmapping should | ||
279 | * occur in the reverse order of mapping. | ||
280 | */ | ||
281 | void *ttm_kmap_atomic_prot(struct page *page, pgprot_t prot) | ||
282 | { | ||
283 | if (pgprot_val(prot) == pgprot_val(PAGE_KERNEL)) | ||
284 | return kmap_atomic(page); | ||
285 | else | ||
286 | return __ttm_kmap_atomic_prot(page, prot); | ||
287 | } | ||
288 | EXPORT_SYMBOL(ttm_kmap_atomic_prot); | ||
289 | |||
290 | /** | ||
291 | * ttm_kunmap_atomic_prot - Unmap a page that was mapped using | ||
292 | * ttm_kmap_atomic_prot. | ||
293 | * | ||
294 | * @addr: The virtual address from the map. | ||
295 | * @prot: The page protection. | ||
296 | */ | ||
297 | void ttm_kunmap_atomic_prot(void *addr, pgprot_t prot) | ||
298 | { | ||
299 | if (pgprot_val(prot) == pgprot_val(PAGE_KERNEL)) | ||
300 | kunmap_atomic(addr); | ||
301 | else | ||
302 | __ttm_kunmap_atomic(addr); | ||
303 | } | ||
304 | EXPORT_SYMBOL(ttm_kunmap_atomic_prot); | ||
305 | |||
258 | static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, | 306 | static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, |
259 | unsigned long page, | 307 | unsigned long page, |
260 | pgprot_t prot) | 308 | pgprot_t prot) |
@@ -266,28 +314,13 @@ static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src, | |||
266 | return -ENOMEM; | 314 | return -ENOMEM; |
267 | 315 | ||
268 | src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); | 316 | src = (void *)((unsigned long)src + (page << PAGE_SHIFT)); |
269 | 317 | dst = ttm_kmap_atomic_prot(d, prot); | |
270 | #ifdef CONFIG_X86 | ||
271 | dst = kmap_atomic_prot(d, prot); | ||
272 | #else | ||
273 | if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) | ||
274 | dst = vmap(&d, 1, 0, prot); | ||
275 | else | ||
276 | dst = kmap(d); | ||
277 | #endif | ||
278 | if (!dst) | 318 | if (!dst) |
279 | return -ENOMEM; | 319 | return -ENOMEM; |
280 | 320 | ||
281 | memcpy_fromio(dst, src, PAGE_SIZE); | 321 | memcpy_fromio(dst, src, PAGE_SIZE); |
282 | 322 | ||
283 | #ifdef CONFIG_X86 | 323 | ttm_kunmap_atomic_prot(dst, prot); |
284 | kunmap_atomic(dst); | ||
285 | #else | ||
286 | if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) | ||
287 | vunmap(dst); | ||
288 | else | ||
289 | kunmap(d); | ||
290 | #endif | ||
291 | 324 | ||
292 | return 0; | 325 | return 0; |
293 | } | 326 | } |
@@ -303,27 +336,13 @@ static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst, | |||
303 | return -ENOMEM; | 336 | return -ENOMEM; |
304 | 337 | ||
305 | dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); | 338 | dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT)); |
306 | #ifdef CONFIG_X86 | 339 | src = ttm_kmap_atomic_prot(s, prot); |
307 | src = kmap_atomic_prot(s, prot); | ||
308 | #else | ||
309 | if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) | ||
310 | src = vmap(&s, 1, 0, prot); | ||
311 | else | ||
312 | src = kmap(s); | ||
313 | #endif | ||
314 | if (!src) | 340 | if (!src) |
315 | return -ENOMEM; | 341 | return -ENOMEM; |
316 | 342 | ||
317 | memcpy_toio(dst, src, PAGE_SIZE); | 343 | memcpy_toio(dst, src, PAGE_SIZE); |
318 | 344 | ||
319 | #ifdef CONFIG_X86 | 345 | ttm_kunmap_atomic_prot(src, prot); |
320 | kunmap_atomic(src); | ||
321 | #else | ||
322 | if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) | ||
323 | vunmap(src); | ||
324 | else | ||
325 | kunmap(s); | ||
326 | #endif | ||
327 | 346 | ||
328 | return 0; | 347 | return 0; |
329 | } | 348 | } |
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index ad80211e1098..794cc9d5c9b0 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile | |||
@@ -7,6 +7,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ | |||
7 | vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ | 7 | vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ |
8 | vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ | 8 | vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ |
9 | vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ | 9 | vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \ |
10 | vmwgfx_simple_resource.o vmwgfx_va.o | 10 | vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o |
11 | 11 | ||
12 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o | 12 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o |
diff --git a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h index 6e0ccb70a700..88e72bf9a534 100644 --- a/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/device_include/svga_reg.h | |||
@@ -372,6 +372,14 @@ SVGAGuestPtr; | |||
372 | * PA, not biased by the offset. When the command buffer is finished | 372 | * PA, not biased by the offset. When the command buffer is finished |
373 | * the guest should not read the offset field as there is no guarantee | 373 | * the guest should not read the offset field as there is no guarantee |
374 | * what it will set to. | 374 | * what it will set to. |
375 | * | ||
376 | * When the SVGA_CAP_HP_CMD_QUEUE cap bit is set a new command queue | ||
377 | * SVGA_CB_CONTEXT_1 is available. Commands submitted to this queue | ||
378 | * will be executed as quickly as possible by the SVGA device | ||
379 | * potentially before already queued commands on SVGA_CB_CONTEXT_0. | ||
380 | * The SVGA device guarantees that any command buffers submitted to | ||
381 | * SVGA_CB_CONTEXT_0 will be executed after any _already_ submitted | ||
382 | * command buffers to SVGA_CB_CONTEXT_1. | ||
375 | */ | 383 | */ |
376 | 384 | ||
377 | #define SVGA_CB_MAX_SIZE (512 * 1024) /* 512 KB */ | 385 | #define SVGA_CB_MAX_SIZE (512 * 1024) /* 512 KB */ |
@@ -382,7 +390,8 @@ SVGAGuestPtr; | |||
382 | typedef enum { | 390 | typedef enum { |
383 | SVGA_CB_CONTEXT_DEVICE = 0x3f, | 391 | SVGA_CB_CONTEXT_DEVICE = 0x3f, |
384 | SVGA_CB_CONTEXT_0 = 0x0, | 392 | SVGA_CB_CONTEXT_0 = 0x0, |
385 | SVGA_CB_CONTEXT_MAX = 0x1, | 393 | SVGA_CB_CONTEXT_1 = 0x1, /* Supported with SVGA_CAP_HP_CMD_QUEUE */ |
394 | SVGA_CB_CONTEXT_MAX = 0x2, | ||
386 | } SVGACBContext; | 395 | } SVGACBContext; |
387 | 396 | ||
388 | 397 | ||
@@ -689,6 +698,7 @@ SVGASignedPoint; | |||
689 | #define SVGA_CAP_CMD_BUFFERS_2 0x04000000 | 698 | #define SVGA_CAP_CMD_BUFFERS_2 0x04000000 |
690 | #define SVGA_CAP_GBOBJECTS 0x08000000 | 699 | #define SVGA_CAP_GBOBJECTS 0x08000000 |
691 | #define SVGA_CAP_DX 0x10000000 | 700 | #define SVGA_CAP_DX 0x10000000 |
701 | #define SVGA_CAP_HP_CMD_QUEUE 0x20000000 | ||
692 | 702 | ||
693 | #define SVGA_CAP_CMD_RESERVED 0x80000000 | 703 | #define SVGA_CAP_CMD_RESERVED 0x80000000 |
694 | 704 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c new file mode 100644 index 000000000000..e8c94b19db7b --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_blit.c | |||
@@ -0,0 +1,506 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright © 2017 VMware, Inc., Palo Alto, CA., USA | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | **************************************************************************/ | ||
27 | |||
28 | #include "vmwgfx_drv.h" | ||
29 | |||
30 | /* | ||
31 | * Template that implements find_first_diff() for a generic | ||
32 | * unsigned integer type. @size and return value are in bytes. | ||
33 | */ | ||
34 | #define VMW_FIND_FIRST_DIFF(_type) \ | ||
35 | static size_t vmw_find_first_diff_ ## _type \ | ||
36 | (const _type * dst, const _type * src, size_t size)\ | ||
37 | { \ | ||
38 | size_t i; \ | ||
39 | \ | ||
40 | for (i = 0; i < size; i += sizeof(_type)) { \ | ||
41 | if (*dst++ != *src++) \ | ||
42 | break; \ | ||
43 | } \ | ||
44 | \ | ||
45 | return i; \ | ||
46 | } | ||
47 | |||
48 | |||
49 | /* | ||
50 | * Template that implements find_last_diff() for a generic | ||
51 | * unsigned integer type. Pointers point to the item following the | ||
52 | * *end* of the area to be examined. @size and return value are in | ||
53 | * bytes. | ||
54 | */ | ||
55 | #define VMW_FIND_LAST_DIFF(_type) \ | ||
56 | static ssize_t vmw_find_last_diff_ ## _type( \ | ||
57 | const _type * dst, const _type * src, size_t size) \ | ||
58 | { \ | ||
59 | while (size) { \ | ||
60 | if (*--dst != *--src) \ | ||
61 | break; \ | ||
62 | \ | ||
63 | size -= sizeof(_type); \ | ||
64 | } \ | ||
65 | return size; \ | ||
66 | } | ||
67 | |||
68 | |||
69 | /* | ||
70 | * Instantiate find diff functions for relevant unsigned integer sizes, | ||
71 | * assuming that wider integers are faster (including aligning) up to the | ||
72 | * architecture native width, which is assumed to be 32 bit unless | ||
73 | * CONFIG_64BIT is defined. | ||
74 | */ | ||
75 | VMW_FIND_FIRST_DIFF(u8); | ||
76 | VMW_FIND_LAST_DIFF(u8); | ||
77 | |||
78 | VMW_FIND_FIRST_DIFF(u16); | ||
79 | VMW_FIND_LAST_DIFF(u16); | ||
80 | |||
81 | VMW_FIND_FIRST_DIFF(u32); | ||
82 | VMW_FIND_LAST_DIFF(u32); | ||
83 | |||
84 | #ifdef CONFIG_64BIT | ||
85 | VMW_FIND_FIRST_DIFF(u64); | ||
86 | VMW_FIND_LAST_DIFF(u64); | ||
87 | #endif | ||
88 | |||
89 | |||
90 | /* We use size aligned copies. This computes (addr - align(addr)) */ | ||
91 | #define SPILL(_var, _type) ((unsigned long) _var & (sizeof(_type) - 1)) | ||
92 | |||
93 | |||
94 | /* | ||
95 | * Template to compute find_first_diff() for a certain integer type | ||
96 | * including a head copy for alignment, and adjustment of parameters | ||
97 | * for tail find or increased resolution find using an unsigned integer find | ||
98 | * of smaller width. If finding is complete, and resolution is sufficient, | ||
99 | * the macro executes a return statement. Otherwise it falls through. | ||
100 | */ | ||
101 | #define VMW_TRY_FIND_FIRST_DIFF(_type) \ | ||
102 | do { \ | ||
103 | unsigned int spill = SPILL(dst, _type); \ | ||
104 | size_t diff_offs; \ | ||
105 | \ | ||
106 | if (spill && spill == SPILL(src, _type) && \ | ||
107 | sizeof(_type) - spill <= size) { \ | ||
108 | spill = sizeof(_type) - spill; \ | ||
109 | diff_offs = vmw_find_first_diff_u8(dst, src, spill); \ | ||
110 | if (diff_offs < spill) \ | ||
111 | return round_down(offset + diff_offs, granularity); \ | ||
112 | \ | ||
113 | dst += spill; \ | ||
114 | src += spill; \ | ||
115 | size -= spill; \ | ||
116 | offset += spill; \ | ||
117 | spill = 0; \ | ||
118 | } \ | ||
119 | if (!spill && !SPILL(src, _type)) { \ | ||
120 | size_t to_copy = size & ~(sizeof(_type) - 1); \ | ||
121 | \ | ||
122 | diff_offs = vmw_find_first_diff_ ## _type \ | ||
123 | ((_type *) dst, (_type *) src, to_copy); \ | ||
124 | if (diff_offs >= size || granularity == sizeof(_type)) \ | ||
125 | return (offset + diff_offs); \ | ||
126 | \ | ||
127 | dst += diff_offs; \ | ||
128 | src += diff_offs; \ | ||
129 | size -= diff_offs; \ | ||
130 | offset += diff_offs; \ | ||
131 | } \ | ||
132 | } while (0) \ | ||
133 | |||
134 | |||
135 | /** | ||
136 | * vmw_find_first_diff - find the first difference between dst and src | ||
137 | * | ||
138 | * @dst: The destination address | ||
139 | * @src: The source address | ||
140 | * @size: Number of bytes to compare | ||
141 | * @granularity: The granularity needed for the return value in bytes. | ||
142 | * return: The offset from find start where the first difference was | ||
143 | * encountered in bytes. If no difference was found, the function returns | ||
144 | * a value >= @size. | ||
145 | */ | ||
146 | static size_t vmw_find_first_diff(const u8 *dst, const u8 *src, size_t size, | ||
147 | size_t granularity) | ||
148 | { | ||
149 | size_t offset = 0; | ||
150 | |||
151 | /* | ||
152 | * Try finding with large integers if alignment allows, or we can | ||
153 | * fix it. Fall through if we need better resolution or alignment | ||
154 | * was bad. | ||
155 | */ | ||
156 | #ifdef CONFIG_64BIT | ||
157 | VMW_TRY_FIND_FIRST_DIFF(u64); | ||
158 | #endif | ||
159 | VMW_TRY_FIND_FIRST_DIFF(u32); | ||
160 | VMW_TRY_FIND_FIRST_DIFF(u16); | ||
161 | |||
162 | return round_down(offset + vmw_find_first_diff_u8(dst, src, size), | ||
163 | granularity); | ||
164 | } | ||
165 | |||
166 | |||
167 | /* | ||
168 | * Template to compute find_last_diff() for a certain integer type | ||
169 | * including a tail copy for alignment, and adjustment of parameters | ||
170 | * for head find or increased resolution find using an unsigned integer find | ||
171 | * of smaller width. If finding is complete, and resolution is sufficient, | ||
172 | * the macro executes a return statement. Otherwise it falls through. | ||
173 | */ | ||
174 | #define VMW_TRY_FIND_LAST_DIFF(_type) \ | ||
175 | do { \ | ||
176 | unsigned int spill = SPILL(dst, _type); \ | ||
177 | ssize_t location; \ | ||
178 | ssize_t diff_offs; \ | ||
179 | \ | ||
180 | if (spill && spill <= size && spill == SPILL(src, _type)) { \ | ||
181 | diff_offs = vmw_find_last_diff_u8(dst, src, spill); \ | ||
182 | if (diff_offs) { \ | ||
183 | location = size - spill + diff_offs - 1; \ | ||
184 | return round_down(location, granularity); \ | ||
185 | } \ | ||
186 | \ | ||
187 | dst -= spill; \ | ||
188 | src -= spill; \ | ||
189 | size -= spill; \ | ||
190 | spill = 0; \ | ||
191 | } \ | ||
192 | if (!spill && !SPILL(src, _type)) { \ | ||
193 | size_t to_copy = round_down(size, sizeof(_type)); \ | ||
194 | \ | ||
195 | diff_offs = vmw_find_last_diff_ ## _type \ | ||
196 | ((_type *) dst, (_type *) src, to_copy); \ | ||
197 | location = size - to_copy + diff_offs - sizeof(_type); \ | ||
198 | if (location < 0 || granularity == sizeof(_type)) \ | ||
199 | return location; \ | ||
200 | \ | ||
201 | dst -= to_copy - diff_offs; \ | ||
202 | src -= to_copy - diff_offs; \ | ||
203 | size -= to_copy - diff_offs; \ | ||
204 | } \ | ||
205 | } while (0) | ||
206 | |||
207 | |||
208 | /** | ||
209 | * vmw_find_last_diff - find the last difference between dst and src | ||
210 | * | ||
211 | * @dst: The destination address | ||
212 | * @src: The source address | ||
213 | * @size: Number of bytes to compare | ||
214 | * @granularity: The granularity needed for the return value in bytes. | ||
215 | * return: The offset from find start where the last difference was | ||
216 | * encountered in bytes, or a negative value if no difference was found. | ||
217 | */ | ||
218 | static ssize_t vmw_find_last_diff(const u8 *dst, const u8 *src, size_t size, | ||
219 | size_t granularity) | ||
220 | { | ||
221 | dst += size; | ||
222 | src += size; | ||
223 | |||
224 | #ifdef CONFIG_64BIT | ||
225 | VMW_TRY_FIND_LAST_DIFF(u64); | ||
226 | #endif | ||
227 | VMW_TRY_FIND_LAST_DIFF(u32); | ||
228 | VMW_TRY_FIND_LAST_DIFF(u16); | ||
229 | |||
230 | return round_down(vmw_find_last_diff_u8(dst, src, size) - 1, | ||
231 | granularity); | ||
232 | } | ||
233 | |||
234 | |||
235 | /** | ||
236 | * vmw_memcpy - A wrapper around kernel memcpy with allowing to plug it into a | ||
237 | * struct vmw_diff_cpy. | ||
238 | * | ||
239 | * @diff: The struct vmw_diff_cpy closure argument (unused). | ||
240 | * @dest: The copy destination. | ||
241 | * @src: The copy source. | ||
242 | * @n: Number of bytes to copy. | ||
243 | */ | ||
244 | void vmw_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, size_t n) | ||
245 | { | ||
246 | memcpy(dest, src, n); | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * vmw_adjust_rect - Adjust rectangle coordinates for newly found difference | ||
252 | * | ||
253 | * @diff: The struct vmw_diff_cpy used to track the modified bounding box. | ||
254 | * @diff_offs: The offset from @diff->line_offset where the difference was | ||
255 | * found. | ||
256 | */ | ||
257 | static void vmw_adjust_rect(struct vmw_diff_cpy *diff, size_t diff_offs) | ||
258 | { | ||
259 | size_t offs = (diff_offs + diff->line_offset) / diff->cpp; | ||
260 | struct drm_rect *rect = &diff->rect; | ||
261 | |||
262 | rect->x1 = min_t(int, rect->x1, offs); | ||
263 | rect->x2 = max_t(int, rect->x2, offs + 1); | ||
264 | rect->y1 = min_t(int, rect->y1, diff->line); | ||
265 | rect->y2 = max_t(int, rect->y2, diff->line + 1); | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * vmw_diff_memcpy - memcpy that creates a bounding box of modified content. | ||
270 | * | ||
271 | * @diff: The struct vmw_diff_cpy used to track the modified bounding box. | ||
272 | * @dest: The copy destination. | ||
273 | * @src: The copy source. | ||
274 | * @n: Number of bytes to copy. | ||
275 | * | ||
276 | * In order to correctly track the modified content, the field @diff->line must | ||
277 | * be pre-loaded with the current line number, the field @diff->line_offset must | ||
278 | * be pre-loaded with the line offset in bytes where the copy starts, and | ||
279 | * finally the field @diff->cpp need to be preloaded with the number of bytes | ||
280 | * per unit in the horizontal direction of the area we're examining. | ||
281 | * Typically bytes per pixel. | ||
282 | * This is needed to know the needed granularity of the difference computing | ||
283 | * operations. A higher cpp generally leads to faster execution at the cost of | ||
284 | * bounding box width precision. | ||
285 | */ | ||
286 | void vmw_diff_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, | ||
287 | size_t n) | ||
288 | { | ||
289 | ssize_t csize, byte_len; | ||
290 | |||
291 | if (WARN_ON_ONCE(round_down(n, diff->cpp) != n)) | ||
292 | return; | ||
293 | |||
294 | /* TODO: Possibly use a single vmw_find_first_diff per line? */ | ||
295 | csize = vmw_find_first_diff(dest, src, n, diff->cpp); | ||
296 | if (csize < n) { | ||
297 | vmw_adjust_rect(diff, csize); | ||
298 | byte_len = diff->cpp; | ||
299 | |||
300 | /* | ||
301 | * Starting from where first difference was found, find | ||
302 | * location of last difference, and then copy. | ||
303 | */ | ||
304 | diff->line_offset += csize; | ||
305 | dest += csize; | ||
306 | src += csize; | ||
307 | n -= csize; | ||
308 | csize = vmw_find_last_diff(dest, src, n, diff->cpp); | ||
309 | if (csize >= 0) { | ||
310 | byte_len += csize; | ||
311 | vmw_adjust_rect(diff, csize); | ||
312 | } | ||
313 | memcpy(dest, src, byte_len); | ||
314 | } | ||
315 | diff->line_offset += n; | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * struct vmw_bo_blit_line_data - Convenience argument to vmw_bo_cpu_blit_line | ||
320 | * | ||
321 | * @mapped_dst: Already mapped destination page index in @dst_pages. | ||
322 | * @dst_addr: Kernel virtual address of mapped destination page. | ||
323 | * @dst_pages: Array of destination bo pages. | ||
324 | * @dst_num_pages: Number of destination bo pages. | ||
325 | * @dst_prot: Destination bo page protection. | ||
326 | * @mapped_src: Already mapped source page index in @dst_pages. | ||
327 | * @src_addr: Kernel virtual address of mapped source page. | ||
328 | * @src_pages: Array of source bo pages. | ||
329 | * @src_num_pages: Number of source bo pages. | ||
330 | * @src_prot: Source bo page protection. | ||
331 | * @diff: Struct vmw_diff_cpy, in the end forwarded to the memcpy routine. | ||
332 | */ | ||
333 | struct vmw_bo_blit_line_data { | ||
334 | u32 mapped_dst; | ||
335 | u8 *dst_addr; | ||
336 | struct page **dst_pages; | ||
337 | u32 dst_num_pages; | ||
338 | pgprot_t dst_prot; | ||
339 | u32 mapped_src; | ||
340 | u8 *src_addr; | ||
341 | struct page **src_pages; | ||
342 | u32 src_num_pages; | ||
343 | pgprot_t src_prot; | ||
344 | struct vmw_diff_cpy *diff; | ||
345 | }; | ||
346 | |||
347 | /** | ||
348 | * vmw_bo_cpu_blit_line - Blit part of a line from one bo to another. | ||
349 | * | ||
350 | * @d: Blit data as described above. | ||
351 | * @dst_offset: Destination copy start offset from start of bo. | ||
352 | * @src_offset: Source copy start offset from start of bo. | ||
353 | * @bytes_to_copy: Number of bytes to copy in this line. | ||
354 | */ | ||
355 | static int vmw_bo_cpu_blit_line(struct vmw_bo_blit_line_data *d, | ||
356 | u32 dst_offset, | ||
357 | u32 src_offset, | ||
358 | u32 bytes_to_copy) | ||
359 | { | ||
360 | struct vmw_diff_cpy *diff = d->diff; | ||
361 | |||
362 | while (bytes_to_copy) { | ||
363 | u32 copy_size = bytes_to_copy; | ||
364 | u32 dst_page = dst_offset >> PAGE_SHIFT; | ||
365 | u32 src_page = src_offset >> PAGE_SHIFT; | ||
366 | u32 dst_page_offset = dst_offset & ~PAGE_MASK; | ||
367 | u32 src_page_offset = src_offset & ~PAGE_MASK; | ||
368 | bool unmap_dst = d->dst_addr && dst_page != d->mapped_dst; | ||
369 | bool unmap_src = d->src_addr && (src_page != d->mapped_src || | ||
370 | unmap_dst); | ||
371 | |||
372 | copy_size = min_t(u32, copy_size, PAGE_SIZE - dst_page_offset); | ||
373 | copy_size = min_t(u32, copy_size, PAGE_SIZE - src_page_offset); | ||
374 | |||
375 | if (unmap_src) { | ||
376 | ttm_kunmap_atomic_prot(d->src_addr, d->src_prot); | ||
377 | d->src_addr = NULL; | ||
378 | } | ||
379 | |||
380 | if (unmap_dst) { | ||
381 | ttm_kunmap_atomic_prot(d->dst_addr, d->dst_prot); | ||
382 | d->dst_addr = NULL; | ||
383 | } | ||
384 | |||
385 | if (!d->dst_addr) { | ||
386 | if (WARN_ON_ONCE(dst_page >= d->dst_num_pages)) | ||
387 | return -EINVAL; | ||
388 | |||
389 | d->dst_addr = | ||
390 | ttm_kmap_atomic_prot(d->dst_pages[dst_page], | ||
391 | d->dst_prot); | ||
392 | if (!d->dst_addr) | ||
393 | return -ENOMEM; | ||
394 | |||
395 | d->mapped_dst = dst_page; | ||
396 | } | ||
397 | |||
398 | if (!d->src_addr) { | ||
399 | if (WARN_ON_ONCE(src_page >= d->src_num_pages)) | ||
400 | return -EINVAL; | ||
401 | |||
402 | d->src_addr = | ||
403 | ttm_kmap_atomic_prot(d->src_pages[src_page], | ||
404 | d->src_prot); | ||
405 | if (!d->src_addr) | ||
406 | return -ENOMEM; | ||
407 | |||
408 | d->mapped_src = src_page; | ||
409 | } | ||
410 | diff->do_cpy(diff, d->dst_addr + dst_page_offset, | ||
411 | d->src_addr + src_page_offset, copy_size); | ||
412 | |||
413 | bytes_to_copy -= copy_size; | ||
414 | dst_offset += copy_size; | ||
415 | src_offset += copy_size; | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * ttm_bo_cpu_blit - in-kernel cpu blit. | ||
423 | * | ||
424 | * @dst: Destination buffer object. | ||
425 | * @dst_offset: Destination offset of blit start in bytes. | ||
426 | * @dst_stride: Destination stride in bytes. | ||
427 | * @src: Source buffer object. | ||
428 | * @src_offset: Source offset of blit start in bytes. | ||
429 | * @src_stride: Source stride in bytes. | ||
430 | * @w: Width of blit. | ||
431 | * @h: Height of blit. | ||
432 | * return: Zero on success. Negative error value on failure. Will print out | ||
433 | * kernel warnings on caller bugs. | ||
434 | * | ||
435 | * Performs a CPU blit from one buffer object to another avoiding a full | ||
436 | * bo vmap which may exhaust- or fragment vmalloc space. | ||
437 | * On supported architectures (x86), we're using kmap_atomic which avoids | ||
438 | * cross-processor TLB- and cache flushes and may, on non-HIGHMEM systems | ||
439 | * reference already set-up mappings. | ||
440 | * | ||
441 | * Neither of the buffer objects may be placed in PCI memory | ||
442 | * (Fixed memory in TTM terminology) when using this function. | ||
443 | */ | ||
444 | int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, | ||
445 | u32 dst_offset, u32 dst_stride, | ||
446 | struct ttm_buffer_object *src, | ||
447 | u32 src_offset, u32 src_stride, | ||
448 | u32 w, u32 h, | ||
449 | struct vmw_diff_cpy *diff) | ||
450 | { | ||
451 | struct ttm_operation_ctx ctx = { | ||
452 | .interruptible = false, | ||
453 | .no_wait_gpu = false | ||
454 | }; | ||
455 | u32 j, initial_line = dst_offset / dst_stride; | ||
456 | struct vmw_bo_blit_line_data d; | ||
457 | int ret = 0; | ||
458 | |||
459 | /* Buffer objects need to be either pinned or reserved: */ | ||
460 | if (!(dst->mem.placement & TTM_PL_FLAG_NO_EVICT)) | ||
461 | lockdep_assert_held(&dst->resv->lock.base); | ||
462 | if (!(src->mem.placement & TTM_PL_FLAG_NO_EVICT)) | ||
463 | lockdep_assert_held(&src->resv->lock.base); | ||
464 | |||
465 | if (dst->ttm->state == tt_unpopulated) { | ||
466 | ret = dst->ttm->bdev->driver->ttm_tt_populate(dst->ttm, &ctx); | ||
467 | if (ret) | ||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | if (src->ttm->state == tt_unpopulated) { | ||
472 | ret = src->ttm->bdev->driver->ttm_tt_populate(src->ttm, &ctx); | ||
473 | if (ret) | ||
474 | return ret; | ||
475 | } | ||
476 | |||
477 | d.mapped_dst = 0; | ||
478 | d.mapped_src = 0; | ||
479 | d.dst_addr = NULL; | ||
480 | d.src_addr = NULL; | ||
481 | d.dst_pages = dst->ttm->pages; | ||
482 | d.src_pages = src->ttm->pages; | ||
483 | d.dst_num_pages = dst->num_pages; | ||
484 | d.src_num_pages = src->num_pages; | ||
485 | d.dst_prot = ttm_io_prot(dst->mem.placement, PAGE_KERNEL); | ||
486 | d.src_prot = ttm_io_prot(src->mem.placement, PAGE_KERNEL); | ||
487 | d.diff = diff; | ||
488 | |||
489 | for (j = 0; j < h; ++j) { | ||
490 | diff->line = j + initial_line; | ||
491 | diff->line_offset = dst_offset % dst_stride; | ||
492 | ret = vmw_bo_cpu_blit_line(&d, dst_offset, src_offset, w); | ||
493 | if (ret) | ||
494 | goto out; | ||
495 | |||
496 | dst_offset += dst_stride; | ||
497 | src_offset += src_stride; | ||
498 | } | ||
499 | out: | ||
500 | if (d.src_addr) | ||
501 | ttm_kunmap_atomic_prot(d.src_addr, d.src_prot); | ||
502 | if (d.dst_addr) | ||
503 | ttm_kunmap_atomic_prot(d.dst_addr, d.dst_prot); | ||
504 | |||
505 | return ret; | ||
506 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index 7177eecb8c9f..21111fd091f9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | |||
@@ -185,6 +185,22 @@ static const struct ttm_place evictable_placement_flags[] = { | |||
185 | } | 185 | } |
186 | }; | 186 | }; |
187 | 187 | ||
188 | static const struct ttm_place nonfixed_placement_flags[] = { | ||
189 | { | ||
190 | .fpfn = 0, | ||
191 | .lpfn = 0, | ||
192 | .flags = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED | ||
193 | }, { | ||
194 | .fpfn = 0, | ||
195 | .lpfn = 0, | ||
196 | .flags = VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED | ||
197 | }, { | ||
198 | .fpfn = 0, | ||
199 | .lpfn = 0, | ||
200 | .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED | ||
201 | } | ||
202 | }; | ||
203 | |||
188 | struct ttm_placement vmw_evictable_placement = { | 204 | struct ttm_placement vmw_evictable_placement = { |
189 | .num_placement = 4, | 205 | .num_placement = 4, |
190 | .placement = evictable_placement_flags, | 206 | .placement = evictable_placement_flags, |
@@ -213,6 +229,13 @@ struct ttm_placement vmw_mob_ne_placement = { | |||
213 | .busy_placement = &mob_ne_placement_flags | 229 | .busy_placement = &mob_ne_placement_flags |
214 | }; | 230 | }; |
215 | 231 | ||
232 | struct ttm_placement vmw_nonfixed_placement = { | ||
233 | .num_placement = 3, | ||
234 | .placement = nonfixed_placement_flags, | ||
235 | .num_busy_placement = 1, | ||
236 | .busy_placement = &sys_placement_flags | ||
237 | }; | ||
238 | |||
216 | struct vmw_ttm_tt { | 239 | struct vmw_ttm_tt { |
217 | struct ttm_dma_tt dma_ttm; | 240 | struct ttm_dma_tt dma_ttm; |
218 | struct vmw_private *dev_priv; | 241 | struct vmw_private *dev_priv; |
@@ -841,6 +864,7 @@ static void vmw_move_notify(struct ttm_buffer_object *bo, | |||
841 | */ | 864 | */ |
842 | static void vmw_swap_notify(struct ttm_buffer_object *bo) | 865 | static void vmw_swap_notify(struct ttm_buffer_object *bo) |
843 | { | 866 | { |
867 | vmw_resource_swap_notify(bo); | ||
844 | (void) ttm_bo_wait(bo, false, false); | 868 | (void) ttm_bo_wait(bo, false, false); |
845 | } | 869 | } |
846 | 870 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index f283324ce598..9f45d5004cae 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | |||
@@ -101,6 +101,7 @@ struct vmw_cmdbuf_context { | |||
101 | * @handle: DMA address handle for the command buffer space if @using_mob is | 101 | * @handle: DMA address handle for the command buffer space if @using_mob is |
102 | * false. Immutable. | 102 | * false. Immutable. |
103 | * @size: The size of the command buffer space. Immutable. | 103 | * @size: The size of the command buffer space. Immutable. |
104 | * @num_contexts: Number of contexts actually enabled. | ||
104 | */ | 105 | */ |
105 | struct vmw_cmdbuf_man { | 106 | struct vmw_cmdbuf_man { |
106 | struct mutex cur_mutex; | 107 | struct mutex cur_mutex; |
@@ -128,6 +129,7 @@ struct vmw_cmdbuf_man { | |||
128 | bool has_pool; | 129 | bool has_pool; |
129 | dma_addr_t handle; | 130 | dma_addr_t handle; |
130 | size_t size; | 131 | size_t size; |
132 | u32 num_contexts; | ||
131 | }; | 133 | }; |
132 | 134 | ||
133 | /** | 135 | /** |
@@ -185,7 +187,7 @@ struct vmw_cmdbuf_alloc_info { | |||
185 | 187 | ||
186 | /* Loop over each context in the command buffer manager. */ | 188 | /* Loop over each context in the command buffer manager. */ |
187 | #define for_each_cmdbuf_ctx(_man, _i, _ctx) \ | 189 | #define for_each_cmdbuf_ctx(_man, _i, _ctx) \ |
188 | for (_i = 0, _ctx = &(_man)->ctx[0]; (_i) < SVGA_CB_CONTEXT_MAX; \ | 190 | for (_i = 0, _ctx = &(_man)->ctx[0]; (_i) < (_man)->num_contexts; \ |
189 | ++(_i), ++(_ctx)) | 191 | ++(_i), ++(_ctx)) |
190 | 192 | ||
191 | static int vmw_cmdbuf_startstop(struct vmw_cmdbuf_man *man, u32 context, | 193 | static int vmw_cmdbuf_startstop(struct vmw_cmdbuf_man *man, u32 context, |
@@ -514,6 +516,7 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) | |||
514 | struct list_head restart_head[SVGA_CB_CONTEXT_MAX]; | 516 | struct list_head restart_head[SVGA_CB_CONTEXT_MAX]; |
515 | int i; | 517 | int i; |
516 | struct vmw_cmdbuf_context *ctx; | 518 | struct vmw_cmdbuf_context *ctx; |
519 | bool global_block = false; | ||
517 | 520 | ||
518 | for_each_cmdbuf_ctx(man, i, ctx) { | 521 | for_each_cmdbuf_ctx(man, i, ctx) { |
519 | INIT_LIST_HEAD(&restart_head[i]); | 522 | INIT_LIST_HEAD(&restart_head[i]); |
@@ -531,6 +534,7 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) | |||
531 | 534 | ||
532 | list_del_init(&entry->list); | 535 | list_del_init(&entry->list); |
533 | restart[entry->cb_context] = true; | 536 | restart[entry->cb_context] = true; |
537 | global_block = true; | ||
534 | 538 | ||
535 | if (!vmw_cmd_describe(header, &error_cmd_size, &cmd_name)) { | 539 | if (!vmw_cmd_describe(header, &error_cmd_size, &cmd_name)) { |
536 | DRM_ERROR("Unknown command causing device error.\n"); | 540 | DRM_ERROR("Unknown command causing device error.\n"); |
@@ -564,23 +568,21 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) | |||
564 | cb_hdr->length -= new_start_offset; | 568 | cb_hdr->length -= new_start_offset; |
565 | cb_hdr->errorOffset = 0; | 569 | cb_hdr->errorOffset = 0; |
566 | cb_hdr->offset = 0; | 570 | cb_hdr->offset = 0; |
571 | |||
567 | list_add_tail(&entry->list, &restart_head[entry->cb_context]); | 572 | list_add_tail(&entry->list, &restart_head[entry->cb_context]); |
568 | man->ctx[entry->cb_context].block_submission = true; | ||
569 | } | 573 | } |
574 | |||
575 | for_each_cmdbuf_ctx(man, i, ctx) | ||
576 | man->ctx[i].block_submission = true; | ||
577 | |||
570 | spin_unlock(&man->lock); | 578 | spin_unlock(&man->lock); |
571 | 579 | ||
572 | /* Preempt all contexts with errors */ | 580 | /* Preempt all contexts */ |
573 | for_each_cmdbuf_ctx(man, i, ctx) { | 581 | if (global_block && vmw_cmdbuf_preempt(man, 0)) |
574 | if (ctx->block_submission && vmw_cmdbuf_preempt(man, i)) | 582 | DRM_ERROR("Failed preempting command buffer contexts\n"); |
575 | DRM_ERROR("Failed preempting command buffer " | ||
576 | "context %u.\n", i); | ||
577 | } | ||
578 | 583 | ||
579 | spin_lock(&man->lock); | 584 | spin_lock(&man->lock); |
580 | for_each_cmdbuf_ctx(man, i, ctx) { | 585 | for_each_cmdbuf_ctx(man, i, ctx) { |
581 | if (!ctx->block_submission) | ||
582 | continue; | ||
583 | |||
584 | /* Move preempted command buffers to the preempted queue. */ | 586 | /* Move preempted command buffers to the preempted queue. */ |
585 | vmw_cmdbuf_ctx_process(man, ctx, &dummy); | 587 | vmw_cmdbuf_ctx_process(man, ctx, &dummy); |
586 | 588 | ||
@@ -594,19 +596,16 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) | |||
594 | * Finally add all command buffers first in the submitted | 596 | * Finally add all command buffers first in the submitted |
595 | * queue, to rerun them. | 597 | * queue, to rerun them. |
596 | */ | 598 | */ |
597 | list_splice_init(&restart_head[i], &ctx->submitted); | ||
598 | 599 | ||
599 | ctx->block_submission = false; | 600 | ctx->block_submission = false; |
601 | list_splice_init(&restart_head[i], &ctx->submitted); | ||
600 | } | 602 | } |
601 | 603 | ||
602 | vmw_cmdbuf_man_process(man); | 604 | vmw_cmdbuf_man_process(man); |
603 | spin_unlock(&man->lock); | 605 | spin_unlock(&man->lock); |
604 | 606 | ||
605 | for_each_cmdbuf_ctx(man, i, ctx) { | 607 | if (global_block && vmw_cmdbuf_startstop(man, 0, true)) |
606 | if (restart[i] && vmw_cmdbuf_startstop(man, i, true)) | 608 | DRM_ERROR("Failed restarting command buffer contexts\n"); |
607 | DRM_ERROR("Failed restarting command buffer " | ||
608 | "context %u.\n", i); | ||
609 | } | ||
610 | 609 | ||
611 | /* Send a new fence in case one was removed */ | 610 | /* Send a new fence in case one was removed */ |
612 | if (send_fence) { | 611 | if (send_fence) { |
@@ -1307,6 +1306,8 @@ struct vmw_cmdbuf_man *vmw_cmdbuf_man_create(struct vmw_private *dev_priv) | |||
1307 | if (!man) | 1306 | if (!man) |
1308 | return ERR_PTR(-ENOMEM); | 1307 | return ERR_PTR(-ENOMEM); |
1309 | 1308 | ||
1309 | man->num_contexts = (dev_priv->capabilities & SVGA_CAP_HP_CMD_QUEUE) ? | ||
1310 | 2 : 1; | ||
1310 | man->headers = dma_pool_create("vmwgfx cmdbuf", | 1311 | man->headers = dma_pool_create("vmwgfx cmdbuf", |
1311 | &dev_priv->dev->pdev->dev, | 1312 | &dev_priv->dev->pdev->dev, |
1312 | sizeof(SVGACBHeader), | 1313 | sizeof(SVGACBHeader), |
@@ -1341,14 +1342,11 @@ struct vmw_cmdbuf_man *vmw_cmdbuf_man_create(struct vmw_private *dev_priv) | |||
1341 | INIT_WORK(&man->work, &vmw_cmdbuf_work_func); | 1342 | INIT_WORK(&man->work, &vmw_cmdbuf_work_func); |
1342 | vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ERROR, | 1343 | vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ERROR, |
1343 | &dev_priv->error_waiters); | 1344 | &dev_priv->error_waiters); |
1344 | for_each_cmdbuf_ctx(man, i, ctx) { | 1345 | ret = vmw_cmdbuf_startstop(man, 0, true); |
1345 | ret = vmw_cmdbuf_startstop(man, i, true); | 1346 | if (ret) { |
1346 | if (ret) { | 1347 | DRM_ERROR("Failed starting command buffer contexts\n"); |
1347 | DRM_ERROR("Failed starting command buffer " | 1348 | vmw_cmdbuf_man_destroy(man); |
1348 | "context %u.\n", i); | 1349 | return ERR_PTR(ret); |
1349 | vmw_cmdbuf_man_destroy(man); | ||
1350 | return ERR_PTR(ret); | ||
1351 | } | ||
1352 | } | 1350 | } |
1353 | 1351 | ||
1354 | return man; | 1352 | return man; |
@@ -1398,16 +1396,11 @@ void vmw_cmdbuf_remove_pool(struct vmw_cmdbuf_man *man) | |||
1398 | */ | 1396 | */ |
1399 | void vmw_cmdbuf_man_destroy(struct vmw_cmdbuf_man *man) | 1397 | void vmw_cmdbuf_man_destroy(struct vmw_cmdbuf_man *man) |
1400 | { | 1398 | { |
1401 | struct vmw_cmdbuf_context *ctx; | ||
1402 | unsigned int i; | ||
1403 | |||
1404 | WARN_ON_ONCE(man->has_pool); | 1399 | WARN_ON_ONCE(man->has_pool); |
1405 | (void) vmw_cmdbuf_idle(man, false, 10*HZ); | 1400 | (void) vmw_cmdbuf_idle(man, false, 10*HZ); |
1406 | 1401 | ||
1407 | for_each_cmdbuf_ctx(man, i, ctx) | 1402 | if (vmw_cmdbuf_startstop(man, 0, false)) |
1408 | if (vmw_cmdbuf_startstop(man, i, false)) | 1403 | DRM_ERROR("Failed stopping command buffer contexts.\n"); |
1409 | DRM_ERROR("Failed stopping command buffer " | ||
1410 | "context %u.\n", i); | ||
1411 | 1404 | ||
1412 | vmw_generic_waiter_remove(man->dev_priv, SVGA_IRQFLAG_ERROR, | 1405 | vmw_generic_waiter_remove(man->dev_priv, SVGA_IRQFLAG_ERROR, |
1413 | &man->dev_priv->error_waiters); | 1406 | &man->dev_priv->error_waiters); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index d45d2caffa5a..d59d9dd16ebc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | |||
@@ -323,3 +323,54 @@ void vmw_bo_pin_reserved(struct vmw_dma_buffer *vbo, bool pin) | |||
323 | 323 | ||
324 | BUG_ON(ret != 0 || bo->mem.mem_type != old_mem_type); | 324 | BUG_ON(ret != 0 || bo->mem.mem_type != old_mem_type); |
325 | } | 325 | } |
326 | |||
327 | |||
328 | /* | ||
329 | * vmw_dma_buffer_unmap - Tear down a cached buffer object map. | ||
330 | * | ||
331 | * @vbo: The buffer object whose map we are tearing down. | ||
332 | * | ||
333 | * This function tears down a cached map set up using | ||
334 | * vmw_dma_buffer_map_and_cache(). | ||
335 | */ | ||
336 | void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo) | ||
337 | { | ||
338 | if (vbo->map.bo == NULL) | ||
339 | return; | ||
340 | |||
341 | ttm_bo_kunmap(&vbo->map); | ||
342 | } | ||
343 | |||
344 | |||
345 | /* | ||
346 | * vmw_dma_buffer_map_and_cache - Map a buffer object and cache the map | ||
347 | * | ||
348 | * @vbo: The buffer object to map | ||
349 | * Return: A kernel virtual address or NULL if mapping failed. | ||
350 | * | ||
351 | * This function maps a buffer object into the kernel address space, or | ||
352 | * returns the virtual kernel address of an already existing map. The virtual | ||
353 | * address remains valid as long as the buffer object is pinned or reserved. | ||
354 | * The cached map is torn down on either | ||
355 | * 1) Buffer object move | ||
356 | * 2) Buffer object swapout | ||
357 | * 3) Buffer object destruction | ||
358 | * | ||
359 | */ | ||
360 | void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo) | ||
361 | { | ||
362 | struct ttm_buffer_object *bo = &vbo->base; | ||
363 | bool not_used; | ||
364 | void *virtual; | ||
365 | int ret; | ||
366 | |||
367 | virtual = ttm_kmap_obj_virtual(&vbo->map, ¬_used); | ||
368 | if (virtual) | ||
369 | return virtual; | ||
370 | |||
371 | ret = ttm_bo_kmap(bo, 0, bo->num_pages, &vbo->map); | ||
372 | if (ret) | ||
373 | DRM_ERROR("Buffer object map failed: %d.\n", ret); | ||
374 | |||
375 | return ttm_kmap_obj_virtual(&vbo->map, ¬_used); | ||
376 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 184340d486c3..61a03ac90f8c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -301,6 +301,8 @@ static void vmw_print_capabilities(uint32_t capabilities) | |||
301 | DRM_INFO(" Guest Backed Resources.\n"); | 301 | DRM_INFO(" Guest Backed Resources.\n"); |
302 | if (capabilities & SVGA_CAP_DX) | 302 | if (capabilities & SVGA_CAP_DX) |
303 | DRM_INFO(" DX Features.\n"); | 303 | DRM_INFO(" DX Features.\n"); |
304 | if (capabilities & SVGA_CAP_HP_CMD_QUEUE) | ||
305 | DRM_INFO(" HP Command Queue.\n"); | ||
304 | } | 306 | } |
305 | 307 | ||
306 | /** | 308 | /** |
@@ -1277,8 +1279,7 @@ static void vmw_master_drop(struct drm_device *dev, | |||
1277 | ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); | 1279 | ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); |
1278 | ttm_vt_unlock(&dev_priv->fbdev_master.lock); | 1280 | ttm_vt_unlock(&dev_priv->fbdev_master.lock); |
1279 | 1281 | ||
1280 | if (dev_priv->enable_fb) | 1282 | vmw_fb_refresh(dev_priv); |
1281 | vmw_fb_on(dev_priv); | ||
1282 | } | 1283 | } |
1283 | 1284 | ||
1284 | /** | 1285 | /** |
@@ -1368,28 +1369,23 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, | |||
1368 | 1369 | ||
1369 | switch (val) { | 1370 | switch (val) { |
1370 | case PM_HIBERNATION_PREPARE: | 1371 | case PM_HIBERNATION_PREPARE: |
1371 | if (dev_priv->enable_fb) | ||
1372 | vmw_fb_off(dev_priv); | ||
1373 | ttm_suspend_lock(&dev_priv->reservation_sem); | ||
1374 | |||
1375 | /* | 1372 | /* |
1376 | * This empties VRAM and unbinds all GMR bindings. | 1373 | * Take the reservation sem in write mode, which will make sure |
1377 | * Buffer contents is moved to swappable memory. | 1374 | * there are no other processes holding a buffer object |
1375 | * reservation, meaning we should be able to evict all buffer | ||
1376 | * objects if needed. | ||
1377 | * Once user-space processes have been frozen, we can release | ||
1378 | * the lock again. | ||
1378 | */ | 1379 | */ |
1379 | vmw_execbuf_release_pinned_bo(dev_priv); | 1380 | ttm_suspend_lock(&dev_priv->reservation_sem); |
1380 | vmw_resource_evict_all(dev_priv); | 1381 | dev_priv->suspend_locked = true; |
1381 | vmw_release_device_early(dev_priv); | ||
1382 | ttm_bo_swapout_all(&dev_priv->bdev); | ||
1383 | vmw_fence_fifo_down(dev_priv->fman); | ||
1384 | break; | 1382 | break; |
1385 | case PM_POST_HIBERNATION: | 1383 | case PM_POST_HIBERNATION: |
1386 | case PM_POST_RESTORE: | 1384 | case PM_POST_RESTORE: |
1387 | vmw_fence_fifo_up(dev_priv->fman); | 1385 | if (READ_ONCE(dev_priv->suspend_locked)) { |
1388 | ttm_suspend_unlock(&dev_priv->reservation_sem); | 1386 | dev_priv->suspend_locked = false; |
1389 | if (dev_priv->enable_fb) | 1387 | ttm_suspend_unlock(&dev_priv->reservation_sem); |
1390 | vmw_fb_on(dev_priv); | 1388 | } |
1391 | break; | ||
1392 | case PM_RESTORE_PREPARE: | ||
1393 | break; | 1389 | break; |
1394 | default: | 1390 | default: |
1395 | break; | 1391 | break; |
@@ -1440,25 +1436,48 @@ static int vmw_pm_freeze(struct device *kdev) | |||
1440 | struct pci_dev *pdev = to_pci_dev(kdev); | 1436 | struct pci_dev *pdev = to_pci_dev(kdev); |
1441 | struct drm_device *dev = pci_get_drvdata(pdev); | 1437 | struct drm_device *dev = pci_get_drvdata(pdev); |
1442 | struct vmw_private *dev_priv = vmw_priv(dev); | 1438 | struct vmw_private *dev_priv = vmw_priv(dev); |
1439 | int ret; | ||
1443 | 1440 | ||
1444 | dev_priv->suspended = true; | 1441 | /* |
1442 | * Unlock for vmw_kms_suspend. | ||
1443 | * No user-space processes should be running now. | ||
1444 | */ | ||
1445 | ttm_suspend_unlock(&dev_priv->reservation_sem); | ||
1446 | ret = vmw_kms_suspend(dev_priv->dev); | ||
1447 | if (ret) { | ||
1448 | ttm_suspend_lock(&dev_priv->reservation_sem); | ||
1449 | DRM_ERROR("Failed to freeze modesetting.\n"); | ||
1450 | return ret; | ||
1451 | } | ||
1445 | if (dev_priv->enable_fb) | 1452 | if (dev_priv->enable_fb) |
1446 | vmw_fifo_resource_dec(dev_priv); | 1453 | vmw_fb_off(dev_priv); |
1447 | 1454 | ||
1455 | ttm_suspend_lock(&dev_priv->reservation_sem); | ||
1456 | vmw_execbuf_release_pinned_bo(dev_priv); | ||
1457 | vmw_resource_evict_all(dev_priv); | ||
1458 | vmw_release_device_early(dev_priv); | ||
1459 | ttm_bo_swapout_all(&dev_priv->bdev); | ||
1460 | if (dev_priv->enable_fb) | ||
1461 | vmw_fifo_resource_dec(dev_priv); | ||
1448 | if (atomic_read(&dev_priv->num_fifo_resources) != 0) { | 1462 | if (atomic_read(&dev_priv->num_fifo_resources) != 0) { |
1449 | DRM_ERROR("Can't hibernate while 3D resources are active.\n"); | 1463 | DRM_ERROR("Can't hibernate while 3D resources are active.\n"); |
1450 | if (dev_priv->enable_fb) | 1464 | if (dev_priv->enable_fb) |
1451 | vmw_fifo_resource_inc(dev_priv); | 1465 | vmw_fifo_resource_inc(dev_priv); |
1452 | WARN_ON(vmw_request_device_late(dev_priv)); | 1466 | WARN_ON(vmw_request_device_late(dev_priv)); |
1453 | dev_priv->suspended = false; | 1467 | dev_priv->suspend_locked = false; |
1468 | ttm_suspend_unlock(&dev_priv->reservation_sem); | ||
1469 | if (dev_priv->suspend_state) | ||
1470 | vmw_kms_resume(dev); | ||
1471 | if (dev_priv->enable_fb) | ||
1472 | vmw_fb_on(dev_priv); | ||
1473 | vmw_fb_refresh(dev_priv); | ||
1454 | return -EBUSY; | 1474 | return -EBUSY; |
1455 | } | 1475 | } |
1456 | 1476 | ||
1457 | if (dev_priv->enable_fb) | 1477 | vmw_fence_fifo_down(dev_priv->fman); |
1458 | __vmw_svga_disable(dev_priv); | 1478 | __vmw_svga_disable(dev_priv); |
1459 | 1479 | ||
1460 | vmw_release_device_late(dev_priv); | 1480 | vmw_release_device_late(dev_priv); |
1461 | |||
1462 | return 0; | 1481 | return 0; |
1463 | } | 1482 | } |
1464 | 1483 | ||
@@ -1482,7 +1501,16 @@ static int vmw_pm_restore(struct device *kdev) | |||
1482 | if (dev_priv->enable_fb) | 1501 | if (dev_priv->enable_fb) |
1483 | __vmw_svga_enable(dev_priv); | 1502 | __vmw_svga_enable(dev_priv); |
1484 | 1503 | ||
1485 | dev_priv->suspended = false; | 1504 | vmw_fence_fifo_up(dev_priv->fman); |
1505 | dev_priv->suspend_locked = false; | ||
1506 | ttm_suspend_unlock(&dev_priv->reservation_sem); | ||
1507 | if (dev_priv->suspend_state) | ||
1508 | vmw_kms_resume(dev_priv->dev); | ||
1509 | |||
1510 | if (dev_priv->enable_fb) | ||
1511 | vmw_fb_on(dev_priv); | ||
1512 | |||
1513 | vmw_fb_refresh(dev_priv); | ||
1486 | 1514 | ||
1487 | return 0; | 1515 | return 0; |
1488 | } | 1516 | } |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d08753e8fd94..9e60de95b863 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
@@ -43,10 +43,10 @@ | |||
43 | #include <linux/sync_file.h> | 43 | #include <linux/sync_file.h> |
44 | 44 | ||
45 | #define VMWGFX_DRIVER_NAME "vmwgfx" | 45 | #define VMWGFX_DRIVER_NAME "vmwgfx" |
46 | #define VMWGFX_DRIVER_DATE "20170612" | 46 | #define VMWGFX_DRIVER_DATE "20180322" |
47 | #define VMWGFX_DRIVER_MAJOR 2 | 47 | #define VMWGFX_DRIVER_MAJOR 2 |
48 | #define VMWGFX_DRIVER_MINOR 14 | 48 | #define VMWGFX_DRIVER_MINOR 14 |
49 | #define VMWGFX_DRIVER_PATCHLEVEL 0 | 49 | #define VMWGFX_DRIVER_PATCHLEVEL 1 |
50 | #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 | 50 | #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 |
51 | #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) | 51 | #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) |
52 | #define VMWGFX_MAX_RELOCATIONS 2048 | 52 | #define VMWGFX_MAX_RELOCATIONS 2048 |
@@ -92,6 +92,8 @@ struct vmw_dma_buffer { | |||
92 | s32 pin_count; | 92 | s32 pin_count; |
93 | /* Not ref-counted. Protected by binding_mutex */ | 93 | /* Not ref-counted. Protected by binding_mutex */ |
94 | struct vmw_resource *dx_query_ctx; | 94 | struct vmw_resource *dx_query_ctx; |
95 | /* Protected by reservation */ | ||
96 | struct ttm_bo_kmap_obj map; | ||
95 | }; | 97 | }; |
96 | 98 | ||
97 | /** | 99 | /** |
@@ -423,6 +425,7 @@ struct vmw_private { | |||
423 | struct vmw_framebuffer *implicit_fb; | 425 | struct vmw_framebuffer *implicit_fb; |
424 | struct mutex global_kms_state_mutex; | 426 | struct mutex global_kms_state_mutex; |
425 | spinlock_t cursor_lock; | 427 | spinlock_t cursor_lock; |
428 | struct drm_atomic_state *suspend_state; | ||
426 | 429 | ||
427 | /* | 430 | /* |
428 | * Context and surface management. | 431 | * Context and surface management. |
@@ -494,8 +497,8 @@ struct vmw_private { | |||
494 | struct vmw_master *active_master; | 497 | struct vmw_master *active_master; |
495 | struct vmw_master fbdev_master; | 498 | struct vmw_master fbdev_master; |
496 | struct notifier_block pm_nb; | 499 | struct notifier_block pm_nb; |
497 | bool suspended; | ||
498 | bool refuse_hibernation; | 500 | bool refuse_hibernation; |
501 | bool suspend_locked; | ||
499 | 502 | ||
500 | struct mutex release_mutex; | 503 | struct mutex release_mutex; |
501 | atomic_t num_fifo_resources; | 504 | atomic_t num_fifo_resources; |
@@ -673,11 +676,13 @@ extern void vmw_resource_move_notify(struct ttm_buffer_object *bo, | |||
673 | struct ttm_mem_reg *mem); | 676 | struct ttm_mem_reg *mem); |
674 | extern void vmw_query_move_notify(struct ttm_buffer_object *bo, | 677 | extern void vmw_query_move_notify(struct ttm_buffer_object *bo, |
675 | struct ttm_mem_reg *mem); | 678 | struct ttm_mem_reg *mem); |
679 | extern void vmw_resource_swap_notify(struct ttm_buffer_object *bo); | ||
676 | extern int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob); | 680 | extern int vmw_query_readback_all(struct vmw_dma_buffer *dx_query_mob); |
677 | extern void vmw_fence_single_bo(struct ttm_buffer_object *bo, | 681 | extern void vmw_fence_single_bo(struct ttm_buffer_object *bo, |
678 | struct vmw_fence_obj *fence); | 682 | struct vmw_fence_obj *fence); |
679 | extern void vmw_resource_evict_all(struct vmw_private *dev_priv); | 683 | extern void vmw_resource_evict_all(struct vmw_private *dev_priv); |
680 | 684 | ||
685 | |||
681 | /** | 686 | /** |
682 | * DMA buffer helper routines - vmwgfx_dmabuf.c | 687 | * DMA buffer helper routines - vmwgfx_dmabuf.c |
683 | */ | 688 | */ |
@@ -700,6 +705,8 @@ extern int vmw_dmabuf_unpin(struct vmw_private *vmw_priv, | |||
700 | extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf, | 705 | extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf, |
701 | SVGAGuestPtr *ptr); | 706 | SVGAGuestPtr *ptr); |
702 | extern void vmw_bo_pin_reserved(struct vmw_dma_buffer *bo, bool pin); | 707 | extern void vmw_bo_pin_reserved(struct vmw_dma_buffer *bo, bool pin); |
708 | extern void *vmw_dma_buffer_map_and_cache(struct vmw_dma_buffer *vbo); | ||
709 | extern void vmw_dma_buffer_unmap(struct vmw_dma_buffer *vbo); | ||
703 | 710 | ||
704 | /** | 711 | /** |
705 | * Misc Ioctl functionality - vmwgfx_ioctl.c | 712 | * Misc Ioctl functionality - vmwgfx_ioctl.c |
@@ -766,6 +773,7 @@ extern struct ttm_placement vmw_evictable_placement; | |||
766 | extern struct ttm_placement vmw_srf_placement; | 773 | extern struct ttm_placement vmw_srf_placement; |
767 | extern struct ttm_placement vmw_mob_placement; | 774 | extern struct ttm_placement vmw_mob_placement; |
768 | extern struct ttm_placement vmw_mob_ne_placement; | 775 | extern struct ttm_placement vmw_mob_ne_placement; |
776 | extern struct ttm_placement vmw_nonfixed_placement; | ||
769 | extern struct ttm_bo_driver vmw_bo_driver; | 777 | extern struct ttm_bo_driver vmw_bo_driver; |
770 | extern int vmw_dma_quiescent(struct drm_device *dev); | 778 | extern int vmw_dma_quiescent(struct drm_device *dev); |
771 | extern int vmw_bo_map_dma(struct ttm_buffer_object *bo); | 779 | extern int vmw_bo_map_dma(struct ttm_buffer_object *bo); |
@@ -902,6 +910,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv); | |||
902 | int vmw_fb_close(struct vmw_private *dev_priv); | 910 | int vmw_fb_close(struct vmw_private *dev_priv); |
903 | int vmw_fb_off(struct vmw_private *vmw_priv); | 911 | int vmw_fb_off(struct vmw_private *vmw_priv); |
904 | int vmw_fb_on(struct vmw_private *vmw_priv); | 912 | int vmw_fb_on(struct vmw_private *vmw_priv); |
913 | void vmw_fb_refresh(struct vmw_private *vmw_priv); | ||
905 | 914 | ||
906 | /** | 915 | /** |
907 | * Kernel modesetting - vmwgfx_kms.c | 916 | * Kernel modesetting - vmwgfx_kms.c |
@@ -938,6 +947,8 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
938 | int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, | 947 | int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, |
939 | struct drm_file *file_priv); | 948 | struct drm_file *file_priv); |
940 | void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv); | 949 | void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv); |
950 | int vmw_kms_suspend(struct drm_device *dev); | ||
951 | int vmw_kms_resume(struct drm_device *dev); | ||
941 | 952 | ||
942 | int vmw_dumb_create(struct drm_file *file_priv, | 953 | int vmw_dumb_create(struct drm_file *file_priv, |
943 | struct drm_device *dev, | 954 | struct drm_device *dev, |
@@ -1165,6 +1176,53 @@ extern int vmw_cmdbuf_cur_flush(struct vmw_cmdbuf_man *man, | |||
1165 | bool interruptible); | 1176 | bool interruptible); |
1166 | extern void vmw_cmdbuf_irqthread(struct vmw_cmdbuf_man *man); | 1177 | extern void vmw_cmdbuf_irqthread(struct vmw_cmdbuf_man *man); |
1167 | 1178 | ||
1179 | /* CPU blit utilities - vmwgfx_blit.c */ | ||
1180 | |||
1181 | /** | ||
1182 | * struct vmw_diff_cpy - CPU blit information structure | ||
1183 | * | ||
1184 | * @rect: The output bounding box rectangle. | ||
1185 | * @line: The current line of the blit. | ||
1186 | * @line_offset: Offset of the current line segment. | ||
1187 | * @cpp: Bytes per pixel (granularity information). | ||
1188 | * @memcpy: Which memcpy function to use. | ||
1189 | */ | ||
1190 | struct vmw_diff_cpy { | ||
1191 | struct drm_rect rect; | ||
1192 | size_t line; | ||
1193 | size_t line_offset; | ||
1194 | int cpp; | ||
1195 | void (*do_cpy)(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, | ||
1196 | size_t n); | ||
1197 | }; | ||
1198 | |||
1199 | #define VMW_CPU_BLIT_INITIALIZER { \ | ||
1200 | .do_cpy = vmw_memcpy, \ | ||
1201 | } | ||
1202 | |||
1203 | #define VMW_CPU_BLIT_DIFF_INITIALIZER(_cpp) { \ | ||
1204 | .line = 0, \ | ||
1205 | .line_offset = 0, \ | ||
1206 | .rect = { .x1 = INT_MAX/2, \ | ||
1207 | .y1 = INT_MAX/2, \ | ||
1208 | .x2 = INT_MIN/2, \ | ||
1209 | .y2 = INT_MIN/2 \ | ||
1210 | }, \ | ||
1211 | .cpp = _cpp, \ | ||
1212 | .do_cpy = vmw_diff_memcpy, \ | ||
1213 | } | ||
1214 | |||
1215 | void vmw_diff_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, | ||
1216 | size_t n); | ||
1217 | |||
1218 | void vmw_memcpy(struct vmw_diff_cpy *diff, u8 *dest, const u8 *src, size_t n); | ||
1219 | |||
1220 | int vmw_bo_cpu_blit(struct ttm_buffer_object *dst, | ||
1221 | u32 dst_offset, u32 dst_stride, | ||
1222 | struct ttm_buffer_object *src, | ||
1223 | u32 src_offset, u32 src_stride, | ||
1224 | u32 w, u32 h, | ||
1225 | struct vmw_diff_cpy *diff); | ||
1168 | 1226 | ||
1169 | /** | 1227 | /** |
1170 | * Inline helper functions | 1228 | * Inline helper functions |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index be7d7fb1b44b..2582ffd36bb5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | |||
@@ -43,8 +43,6 @@ struct vmw_fb_par { | |||
43 | 43 | ||
44 | struct mutex bo_mutex; | 44 | struct mutex bo_mutex; |
45 | struct vmw_dma_buffer *vmw_bo; | 45 | struct vmw_dma_buffer *vmw_bo; |
46 | struct ttm_bo_kmap_obj map; | ||
47 | void *bo_ptr; | ||
48 | unsigned bo_size; | 46 | unsigned bo_size; |
49 | struct drm_framebuffer *set_fb; | 47 | struct drm_framebuffer *set_fb; |
50 | struct drm_display_mode *set_mode; | 48 | struct drm_display_mode *set_mode; |
@@ -163,10 +161,17 @@ static int vmw_fb_blank(int blank, struct fb_info *info) | |||
163 | return 0; | 161 | return 0; |
164 | } | 162 | } |
165 | 163 | ||
166 | /* | 164 | /** |
167 | * Dirty code | 165 | * vmw_fb_dirty_flush - flush dirty regions to the kms framebuffer |
166 | * | ||
167 | * @work: The struct work_struct associated with this task. | ||
168 | * | ||
169 | * This function flushes the dirty regions of the vmalloc framebuffer to the | ||
170 | * kms framebuffer, and if the kms framebuffer is visible, also updated the | ||
171 | * corresponding displays. Note that this function runs even if the kms | ||
172 | * framebuffer is not bound to a crtc and thus not visible, but it's turned | ||
173 | * off during hibernation using the par->dirty.active bool. | ||
168 | */ | 174 | */ |
169 | |||
170 | static void vmw_fb_dirty_flush(struct work_struct *work) | 175 | static void vmw_fb_dirty_flush(struct work_struct *work) |
171 | { | 176 | { |
172 | struct vmw_fb_par *par = container_of(work, struct vmw_fb_par, | 177 | struct vmw_fb_par *par = container_of(work, struct vmw_fb_par, |
@@ -174,13 +179,15 @@ static void vmw_fb_dirty_flush(struct work_struct *work) | |||
174 | struct vmw_private *vmw_priv = par->vmw_priv; | 179 | struct vmw_private *vmw_priv = par->vmw_priv; |
175 | struct fb_info *info = vmw_priv->fb_info; | 180 | struct fb_info *info = vmw_priv->fb_info; |
176 | unsigned long irq_flags; | 181 | unsigned long irq_flags; |
177 | s32 dst_x1, dst_x2, dst_y1, dst_y2, w, h; | 182 | s32 dst_x1, dst_x2, dst_y1, dst_y2, w = 0, h = 0; |
178 | u32 cpp, max_x, max_y; | 183 | u32 cpp, max_x, max_y; |
179 | struct drm_clip_rect clip; | 184 | struct drm_clip_rect clip; |
180 | struct drm_framebuffer *cur_fb; | 185 | struct drm_framebuffer *cur_fb; |
181 | u8 *src_ptr, *dst_ptr; | 186 | u8 *src_ptr, *dst_ptr; |
187 | struct vmw_dma_buffer *vbo = par->vmw_bo; | ||
188 | void *virtual; | ||
182 | 189 | ||
183 | if (vmw_priv->suspended) | 190 | if (!READ_ONCE(par->dirty.active)) |
184 | return; | 191 | return; |
185 | 192 | ||
186 | mutex_lock(&par->bo_mutex); | 193 | mutex_lock(&par->bo_mutex); |
@@ -188,10 +195,16 @@ static void vmw_fb_dirty_flush(struct work_struct *work) | |||
188 | if (!cur_fb) | 195 | if (!cur_fb) |
189 | goto out_unlock; | 196 | goto out_unlock; |
190 | 197 | ||
198 | (void) ttm_read_lock(&vmw_priv->reservation_sem, false); | ||
199 | (void) ttm_bo_reserve(&vbo->base, false, false, NULL); | ||
200 | virtual = vmw_dma_buffer_map_and_cache(vbo); | ||
201 | if (!virtual) | ||
202 | goto out_unreserve; | ||
203 | |||
191 | spin_lock_irqsave(&par->dirty.lock, irq_flags); | 204 | spin_lock_irqsave(&par->dirty.lock, irq_flags); |
192 | if (!par->dirty.active) { | 205 | if (!par->dirty.active) { |
193 | spin_unlock_irqrestore(&par->dirty.lock, irq_flags); | 206 | spin_unlock_irqrestore(&par->dirty.lock, irq_flags); |
194 | goto out_unlock; | 207 | goto out_unreserve; |
195 | } | 208 | } |
196 | 209 | ||
197 | /* | 210 | /* |
@@ -221,7 +234,7 @@ static void vmw_fb_dirty_flush(struct work_struct *work) | |||
221 | spin_unlock_irqrestore(&par->dirty.lock, irq_flags); | 234 | spin_unlock_irqrestore(&par->dirty.lock, irq_flags); |
222 | 235 | ||
223 | if (w && h) { | 236 | if (w && h) { |
224 | dst_ptr = (u8 *)par->bo_ptr + | 237 | dst_ptr = (u8 *)virtual + |
225 | (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); | 238 | (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); |
226 | src_ptr = (u8 *)par->vmalloc + | 239 | src_ptr = (u8 *)par->vmalloc + |
227 | ((dst_y1 + par->fb_y) * info->fix.line_length + | 240 | ((dst_y1 + par->fb_y) * info->fix.line_length + |
@@ -237,7 +250,12 @@ static void vmw_fb_dirty_flush(struct work_struct *work) | |||
237 | clip.x2 = dst_x2; | 250 | clip.x2 = dst_x2; |
238 | clip.y1 = dst_y1; | 251 | clip.y1 = dst_y1; |
239 | clip.y2 = dst_y2; | 252 | clip.y2 = dst_y2; |
253 | } | ||
240 | 254 | ||
255 | out_unreserve: | ||
256 | ttm_bo_unreserve(&vbo->base); | ||
257 | ttm_read_unlock(&vmw_priv->reservation_sem); | ||
258 | if (w && h) { | ||
241 | WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, | 259 | WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, |
242 | &clip, 1)); | 260 | &clip, 1)); |
243 | vmw_fifo_flush(vmw_priv, false); | 261 | vmw_fifo_flush(vmw_priv, false); |
@@ -504,18 +522,8 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par, | |||
504 | par->set_fb = NULL; | 522 | par->set_fb = NULL; |
505 | } | 523 | } |
506 | 524 | ||
507 | if (par->vmw_bo && detach_bo) { | 525 | if (par->vmw_bo && detach_bo && unref_bo) |
508 | struct vmw_private *vmw_priv = par->vmw_priv; | 526 | vmw_dmabuf_unreference(&par->vmw_bo); |
509 | |||
510 | if (par->bo_ptr) { | ||
511 | ttm_bo_kunmap(&par->map); | ||
512 | par->bo_ptr = NULL; | ||
513 | } | ||
514 | if (unref_bo) | ||
515 | vmw_dmabuf_unreference(&par->vmw_bo); | ||
516 | else if (vmw_priv->active_display_unit != vmw_du_legacy) | ||
517 | vmw_dmabuf_unpin(par->vmw_priv, par->vmw_bo, false); | ||
518 | } | ||
519 | 527 | ||
520 | return 0; | 528 | return 0; |
521 | } | 529 | } |
@@ -636,38 +644,6 @@ static int vmw_fb_set_par(struct fb_info *info) | |||
636 | if (ret) | 644 | if (ret) |
637 | goto out_unlock; | 645 | goto out_unlock; |
638 | 646 | ||
639 | if (!par->bo_ptr) { | ||
640 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(set.fb); | ||
641 | |||
642 | /* | ||
643 | * Pin before mapping. Since we don't know in what placement | ||
644 | * to pin, call into KMS to do it for us. LDU doesn't require | ||
645 | * additional pinning because set_config() would've pinned | ||
646 | * it already | ||
647 | */ | ||
648 | if (vmw_priv->active_display_unit != vmw_du_legacy) { | ||
649 | ret = vfb->pin(vfb); | ||
650 | if (ret) { | ||
651 | DRM_ERROR("Could not pin the fbdev " | ||
652 | "framebuffer.\n"); | ||
653 | goto out_unlock; | ||
654 | } | ||
655 | } | ||
656 | |||
657 | ret = ttm_bo_kmap(&par->vmw_bo->base, 0, | ||
658 | par->vmw_bo->base.num_pages, &par->map); | ||
659 | if (ret) { | ||
660 | if (vmw_priv->active_display_unit != vmw_du_legacy) | ||
661 | vfb->unpin(vfb); | ||
662 | |||
663 | DRM_ERROR("Could not map the fbdev framebuffer.\n"); | ||
664 | goto out_unlock; | ||
665 | } | ||
666 | |||
667 | par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite); | ||
668 | } | ||
669 | |||
670 | |||
671 | vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, | 647 | vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, |
672 | par->set_fb->width, par->set_fb->height); | 648 | par->set_fb->width, par->set_fb->height); |
673 | 649 | ||
@@ -883,12 +859,6 @@ int vmw_fb_off(struct vmw_private *vmw_priv) | |||
883 | flush_delayed_work(&info->deferred_work); | 859 | flush_delayed_work(&info->deferred_work); |
884 | flush_delayed_work(&par->local_work); | 860 | flush_delayed_work(&par->local_work); |
885 | 861 | ||
886 | mutex_lock(&par->bo_mutex); | ||
887 | drm_modeset_lock_all(vmw_priv->dev); | ||
888 | (void) vmw_fb_kms_detach(par, true, false); | ||
889 | drm_modeset_unlock_all(vmw_priv->dev); | ||
890 | mutex_unlock(&par->bo_mutex); | ||
891 | |||
892 | return 0; | 862 | return 0; |
893 | } | 863 | } |
894 | 864 | ||
@@ -904,10 +874,24 @@ int vmw_fb_on(struct vmw_private *vmw_priv) | |||
904 | info = vmw_priv->fb_info; | 874 | info = vmw_priv->fb_info; |
905 | par = info->par; | 875 | par = info->par; |
906 | 876 | ||
907 | vmw_fb_set_par(info); | ||
908 | spin_lock_irqsave(&par->dirty.lock, flags); | 877 | spin_lock_irqsave(&par->dirty.lock, flags); |
909 | par->dirty.active = true; | 878 | par->dirty.active = true; |
910 | spin_unlock_irqrestore(&par->dirty.lock, flags); | 879 | spin_unlock_irqrestore(&par->dirty.lock, flags); |
911 | 880 | ||
912 | return 0; | 881 | return 0; |
913 | } | 882 | } |
883 | |||
884 | /** | ||
885 | * vmw_fb_refresh - Refresh fb display | ||
886 | * | ||
887 | * @vmw_priv: Pointer to device private | ||
888 | * | ||
889 | * Call into kms to show the fbdev display(s). | ||
890 | */ | ||
891 | void vmw_fb_refresh(struct vmw_private *vmw_priv) | ||
892 | { | ||
893 | if (!vmw_priv->fb_info) | ||
894 | return; | ||
895 | |||
896 | vmw_fb_set_par(vmw_priv->fb_info); | ||
897 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 6c5c75cf5e6c..9ed544f8958f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | |||
@@ -901,11 +901,12 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action) | |||
901 | spin_lock_irq(&dev->event_lock); | 901 | spin_lock_irq(&dev->event_lock); |
902 | 902 | ||
903 | if (likely(eaction->tv_sec != NULL)) { | 903 | if (likely(eaction->tv_sec != NULL)) { |
904 | struct timeval tv; | 904 | struct timespec64 ts; |
905 | 905 | ||
906 | do_gettimeofday(&tv); | 906 | ktime_get_ts64(&ts); |
907 | *eaction->tv_sec = tv.tv_sec; | 907 | /* monotonic time, so no y2038 overflow */ |
908 | *eaction->tv_usec = tv.tv_usec; | 908 | *eaction->tv_sec = ts.tv_sec; |
909 | *eaction->tv_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
909 | } | 910 | } |
910 | 911 | ||
911 | drm_send_event_locked(dev, eaction->event); | 912 | drm_send_event_locked(dev, eaction->event); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 34ecc27fc30a..3628a9fe705f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -393,13 +393,13 @@ vmw_du_cursor_plane_atomic_update(struct drm_plane *plane, | |||
393 | du->cursor_surface = vps->surf; | 393 | du->cursor_surface = vps->surf; |
394 | du->cursor_dmabuf = vps->dmabuf; | 394 | du->cursor_dmabuf = vps->dmabuf; |
395 | 395 | ||
396 | /* setup new image */ | ||
397 | if (vps->surf) { | 396 | if (vps->surf) { |
398 | du->cursor_age = du->cursor_surface->snooper.age; | 397 | du->cursor_age = du->cursor_surface->snooper.age; |
399 | 398 | ||
400 | ret = vmw_cursor_update_image(dev_priv, | 399 | ret = vmw_cursor_update_image(dev_priv, |
401 | vps->surf->snooper.image, | 400 | vps->surf->snooper.image, |
402 | 64, 64, hotspot_x, hotspot_y); | 401 | 64, 64, hotspot_x, |
402 | hotspot_y); | ||
403 | } else if (vps->dmabuf) { | 403 | } else if (vps->dmabuf) { |
404 | ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf, | 404 | ret = vmw_cursor_update_dmabuf(dev_priv, vps->dmabuf, |
405 | plane->state->crtc_w, | 405 | plane->state->crtc_w, |
@@ -497,11 +497,22 @@ int vmw_du_cursor_plane_atomic_check(struct drm_plane *plane, | |||
497 | struct vmw_surface *surface = NULL; | 497 | struct vmw_surface *surface = NULL; |
498 | struct drm_framebuffer *fb = new_state->fb; | 498 | struct drm_framebuffer *fb = new_state->fb; |
499 | 499 | ||
500 | struct drm_rect src = drm_plane_state_src(new_state); | ||
501 | struct drm_rect dest = drm_plane_state_dest(new_state); | ||
500 | 502 | ||
501 | /* Turning off */ | 503 | /* Turning off */ |
502 | if (!fb) | 504 | if (!fb) |
503 | return ret; | 505 | return ret; |
504 | 506 | ||
507 | ret = drm_plane_helper_check_update(plane, new_state->crtc, fb, | ||
508 | &src, &dest, | ||
509 | DRM_MODE_ROTATE_0, | ||
510 | DRM_PLANE_HELPER_NO_SCALING, | ||
511 | DRM_PLANE_HELPER_NO_SCALING, | ||
512 | true, true, &new_state->visible); | ||
513 | if (!ret) | ||
514 | return ret; | ||
515 | |||
505 | /* A lot of the code assumes this */ | 516 | /* A lot of the code assumes this */ |
506 | if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { | 517 | if (new_state->crtc_w != 64 || new_state->crtc_h != 64) { |
507 | DRM_ERROR("Invalid cursor dimensions (%d, %d)\n", | 518 | DRM_ERROR("Invalid cursor dimensions (%d, %d)\n", |
@@ -566,13 +577,9 @@ void vmw_du_crtc_atomic_flush(struct drm_crtc *crtc, | |||
566 | crtc->state->event = NULL; | 577 | crtc->state->event = NULL; |
567 | 578 | ||
568 | spin_lock_irq(&crtc->dev->event_lock); | 579 | spin_lock_irq(&crtc->dev->event_lock); |
569 | if (drm_crtc_vblank_get(crtc) == 0) | 580 | drm_crtc_send_vblank_event(crtc, event); |
570 | drm_crtc_arm_vblank_event(crtc, event); | ||
571 | else | ||
572 | drm_crtc_send_vblank_event(crtc, event); | ||
573 | spin_unlock_irq(&crtc->dev->event_lock); | 581 | spin_unlock_irq(&crtc->dev->event_lock); |
574 | } | 582 | } |
575 | |||
576 | } | 583 | } |
577 | 584 | ||
578 | 585 | ||
@@ -675,9 +682,6 @@ vmw_du_plane_duplicate_state(struct drm_plane *plane) | |||
675 | return NULL; | 682 | return NULL; |
676 | 683 | ||
677 | vps->pinned = 0; | 684 | vps->pinned = 0; |
678 | |||
679 | /* Mapping is managed by prepare_fb/cleanup_fb */ | ||
680 | memset(&vps->host_map, 0, sizeof(vps->host_map)); | ||
681 | vps->cpp = 0; | 685 | vps->cpp = 0; |
682 | 686 | ||
683 | /* Each ref counted resource needs to be acquired again */ | 687 | /* Each ref counted resource needs to be acquired again */ |
@@ -739,11 +743,6 @@ vmw_du_plane_destroy_state(struct drm_plane *plane, | |||
739 | 743 | ||
740 | 744 | ||
741 | /* Should have been freed by cleanup_fb */ | 745 | /* Should have been freed by cleanup_fb */ |
742 | if (vps->host_map.virtual) { | ||
743 | DRM_ERROR("Host mapping not freed\n"); | ||
744 | ttm_bo_kunmap(&vps->host_map); | ||
745 | } | ||
746 | |||
747 | if (vps->surf) | 746 | if (vps->surf) |
748 | vmw_surface_unreference(&vps->surf); | 747 | vmw_surface_unreference(&vps->surf); |
749 | 748 | ||
@@ -888,11 +887,11 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, | |||
888 | if (dev_priv->active_display_unit == vmw_du_screen_object) | 887 | if (dev_priv->active_display_unit == vmw_du_screen_object) |
889 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, | 888 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, |
890 | clips, NULL, NULL, 0, 0, | 889 | clips, NULL, NULL, 0, 0, |
891 | num_clips, inc, NULL); | 890 | num_clips, inc, NULL, NULL); |
892 | else | 891 | else |
893 | ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, | 892 | ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, |
894 | clips, NULL, NULL, 0, 0, | 893 | clips, NULL, NULL, 0, 0, |
895 | num_clips, inc, NULL); | 894 | num_clips, inc, NULL, NULL); |
896 | 895 | ||
897 | vmw_fifo_flush(dev_priv, false); | 896 | vmw_fifo_flush(dev_priv, false); |
898 | ttm_read_unlock(&dev_priv->reservation_sem); | 897 | ttm_read_unlock(&dev_priv->reservation_sem); |
@@ -928,11 +927,12 @@ int vmw_kms_readback(struct vmw_private *dev_priv, | |||
928 | switch (dev_priv->active_display_unit) { | 927 | switch (dev_priv->active_display_unit) { |
929 | case vmw_du_screen_object: | 928 | case vmw_du_screen_object: |
930 | return vmw_kms_sou_readback(dev_priv, file_priv, vfb, | 929 | return vmw_kms_sou_readback(dev_priv, file_priv, vfb, |
931 | user_fence_rep, vclips, num_clips); | 930 | user_fence_rep, vclips, num_clips, |
931 | NULL); | ||
932 | case vmw_du_screen_target: | 932 | case vmw_du_screen_target: |
933 | return vmw_kms_stdu_dma(dev_priv, file_priv, vfb, | 933 | return vmw_kms_stdu_dma(dev_priv, file_priv, vfb, |
934 | user_fence_rep, NULL, vclips, num_clips, | 934 | user_fence_rep, NULL, vclips, num_clips, |
935 | 1, false, true); | 935 | 1, false, true, NULL); |
936 | default: | 936 | default: |
937 | WARN_ONCE(true, | 937 | WARN_ONCE(true, |
938 | "Readback called with invalid display system.\n"); | 938 | "Readback called with invalid display system.\n"); |
@@ -1090,12 +1090,12 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, | |||
1090 | case vmw_du_screen_target: | 1090 | case vmw_du_screen_target: |
1091 | ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, | 1091 | ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, |
1092 | clips, NULL, num_clips, increment, | 1092 | clips, NULL, num_clips, increment, |
1093 | true, true); | 1093 | true, true, NULL); |
1094 | break; | 1094 | break; |
1095 | case vmw_du_screen_object: | 1095 | case vmw_du_screen_object: |
1096 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, | 1096 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, |
1097 | clips, NULL, num_clips, | 1097 | clips, NULL, num_clips, |
1098 | increment, true, NULL); | 1098 | increment, true, NULL, NULL); |
1099 | break; | 1099 | break; |
1100 | case vmw_du_legacy: | 1100 | case vmw_du_legacy: |
1101 | ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, | 1101 | ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, |
@@ -1121,12 +1121,14 @@ static const struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { | |||
1121 | }; | 1121 | }; |
1122 | 1122 | ||
1123 | /** | 1123 | /** |
1124 | * Pin the dmabuffer to the start of vram. | 1124 | * Pin the dmabuffer in a location suitable for access by the |
1125 | * display system. | ||
1125 | */ | 1126 | */ |
1126 | static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) | 1127 | static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) |
1127 | { | 1128 | { |
1128 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); | 1129 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); |
1129 | struct vmw_dma_buffer *buf; | 1130 | struct vmw_dma_buffer *buf; |
1131 | struct ttm_placement *placement; | ||
1130 | int ret; | 1132 | int ret; |
1131 | 1133 | ||
1132 | buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : | 1134 | buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : |
@@ -1143,12 +1145,24 @@ static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) | |||
1143 | break; | 1145 | break; |
1144 | case vmw_du_screen_object: | 1146 | case vmw_du_screen_object: |
1145 | case vmw_du_screen_target: | 1147 | case vmw_du_screen_target: |
1146 | if (vfb->dmabuf) | 1148 | if (vfb->dmabuf) { |
1147 | return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, | 1149 | if (dev_priv->capabilities & SVGA_CAP_3D) { |
1148 | false); | 1150 | /* |
1151 | * Use surface DMA to get content to | ||
1152 | * sreen target surface. | ||
1153 | */ | ||
1154 | placement = &vmw_vram_gmr_placement; | ||
1155 | } else { | ||
1156 | /* Use CPU blit. */ | ||
1157 | placement = &vmw_sys_placement; | ||
1158 | } | ||
1159 | } else { | ||
1160 | /* Use surface / image update */ | ||
1161 | placement = &vmw_mob_placement; | ||
1162 | } | ||
1149 | 1163 | ||
1150 | return vmw_dmabuf_pin_in_placement(dev_priv, buf, | 1164 | return vmw_dmabuf_pin_in_placement(dev_priv, buf, placement, |
1151 | &vmw_mob_placement, false); | 1165 | false); |
1152 | default: | 1166 | default: |
1153 | return -EINVAL; | 1167 | return -EINVAL; |
1154 | } | 1168 | } |
@@ -1539,35 +1553,10 @@ vmw_kms_atomic_check_modeset(struct drm_device *dev, | |||
1539 | return drm_atomic_helper_check(dev, state); | 1553 | return drm_atomic_helper_check(dev, state); |
1540 | } | 1554 | } |
1541 | 1555 | ||
1542 | |||
1543 | /** | ||
1544 | * vmw_kms_atomic_commit - Perform an atomic state commit | ||
1545 | * | ||
1546 | * @dev: DRM device | ||
1547 | * @state: the driver state object | ||
1548 | * @nonblock: Whether nonblocking behaviour is requested | ||
1549 | * | ||
1550 | * This is a simple wrapper around drm_atomic_helper_commit() for | ||
1551 | * us to clear the nonblocking value. | ||
1552 | * | ||
1553 | * Nonblocking commits currently cause synchronization issues | ||
1554 | * for vmwgfx. | ||
1555 | * | ||
1556 | * RETURNS | ||
1557 | * Zero for success or negative error code on failure. | ||
1558 | */ | ||
1559 | int vmw_kms_atomic_commit(struct drm_device *dev, | ||
1560 | struct drm_atomic_state *state, | ||
1561 | bool nonblock) | ||
1562 | { | ||
1563 | return drm_atomic_helper_commit(dev, state, false); | ||
1564 | } | ||
1565 | |||
1566 | |||
1567 | static const struct drm_mode_config_funcs vmw_kms_funcs = { | 1556 | static const struct drm_mode_config_funcs vmw_kms_funcs = { |
1568 | .fb_create = vmw_kms_fb_create, | 1557 | .fb_create = vmw_kms_fb_create, |
1569 | .atomic_check = vmw_kms_atomic_check_modeset, | 1558 | .atomic_check = vmw_kms_atomic_check_modeset, |
1570 | .atomic_commit = vmw_kms_atomic_commit, | 1559 | .atomic_commit = drm_atomic_helper_commit, |
1571 | }; | 1560 | }; |
1572 | 1561 | ||
1573 | static int vmw_kms_generic_present(struct vmw_private *dev_priv, | 1562 | static int vmw_kms_generic_present(struct vmw_private *dev_priv, |
@@ -1581,7 +1570,7 @@ static int vmw_kms_generic_present(struct vmw_private *dev_priv, | |||
1581 | { | 1570 | { |
1582 | return vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, clips, | 1571 | return vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, clips, |
1583 | &surface->res, destX, destY, | 1572 | &surface->res, destX, destY, |
1584 | num_clips, 1, NULL); | 1573 | num_clips, 1, NULL, NULL); |
1585 | } | 1574 | } |
1586 | 1575 | ||
1587 | 1576 | ||
@@ -1600,7 +1589,7 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1600 | case vmw_du_screen_target: | 1589 | case vmw_du_screen_target: |
1601 | ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, clips, | 1590 | ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, clips, |
1602 | &surface->res, destX, destY, | 1591 | &surface->res, destX, destY, |
1603 | num_clips, 1, NULL); | 1592 | num_clips, 1, NULL, NULL); |
1604 | break; | 1593 | break; |
1605 | case vmw_du_screen_object: | 1594 | case vmw_du_screen_object: |
1606 | ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, | 1595 | ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, |
@@ -2328,10 +2317,16 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, | |||
2328 | 2317 | ||
2329 | dirty->dev_priv = dev_priv; | 2318 | dirty->dev_priv = dev_priv; |
2330 | 2319 | ||
2331 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { | 2320 | /* If crtc is passed, no need to iterate over other display units */ |
2332 | if (crtc->primary->fb != &framebuffer->base) | 2321 | if (dirty->crtc) { |
2333 | continue; | 2322 | units[num_units++] = vmw_crtc_to_du(dirty->crtc); |
2334 | units[num_units++] = vmw_crtc_to_du(crtc); | 2323 | } else { |
2324 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, | ||
2325 | head) { | ||
2326 | if (crtc->primary->fb != &framebuffer->base) | ||
2327 | continue; | ||
2328 | units[num_units++] = vmw_crtc_to_du(crtc); | ||
2329 | } | ||
2335 | } | 2330 | } |
2336 | 2331 | ||
2337 | for (k = 0; k < num_units; k++) { | 2332 | for (k = 0; k < num_units; k++) { |
@@ -2430,14 +2425,21 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, | |||
2430 | int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, | 2425 | int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, |
2431 | struct vmw_dma_buffer *buf, | 2426 | struct vmw_dma_buffer *buf, |
2432 | bool interruptible, | 2427 | bool interruptible, |
2433 | bool validate_as_mob) | 2428 | bool validate_as_mob, |
2429 | bool for_cpu_blit) | ||
2434 | { | 2430 | { |
2431 | struct ttm_operation_ctx ctx = { | ||
2432 | .interruptible = interruptible, | ||
2433 | .no_wait_gpu = false}; | ||
2435 | struct ttm_buffer_object *bo = &buf->base; | 2434 | struct ttm_buffer_object *bo = &buf->base; |
2436 | int ret; | 2435 | int ret; |
2437 | 2436 | ||
2438 | ttm_bo_reserve(bo, false, false, NULL); | 2437 | ttm_bo_reserve(bo, false, false, NULL); |
2439 | ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, | 2438 | if (for_cpu_blit) |
2440 | validate_as_mob); | 2439 | ret = ttm_bo_validate(bo, &vmw_nonfixed_placement, &ctx); |
2440 | else | ||
2441 | ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, | ||
2442 | validate_as_mob); | ||
2441 | if (ret) | 2443 | if (ret) |
2442 | ttm_bo_unreserve(bo); | 2444 | ttm_bo_unreserve(bo); |
2443 | 2445 | ||
@@ -2549,7 +2551,8 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, | |||
2549 | if (res->backup) { | 2551 | if (res->backup) { |
2550 | ret = vmw_kms_helper_buffer_prepare(res->dev_priv, res->backup, | 2552 | ret = vmw_kms_helper_buffer_prepare(res->dev_priv, res->backup, |
2551 | interruptible, | 2553 | interruptible, |
2552 | res->dev_priv->has_mob); | 2554 | res->dev_priv->has_mob, |
2555 | false); | ||
2553 | if (ret) | 2556 | if (ret) |
2554 | goto out_unreserve; | 2557 | goto out_unreserve; |
2555 | } | 2558 | } |
@@ -2845,3 +2848,51 @@ int vmw_kms_set_config(struct drm_mode_set *set, | |||
2845 | 2848 | ||
2846 | return drm_atomic_helper_set_config(set, ctx); | 2849 | return drm_atomic_helper_set_config(set, ctx); |
2847 | } | 2850 | } |
2851 | |||
2852 | |||
2853 | /** | ||
2854 | * vmw_kms_suspend - Save modesetting state and turn modesetting off. | ||
2855 | * | ||
2856 | * @dev: Pointer to the drm device | ||
2857 | * Return: 0 on success. Negative error code on failure. | ||
2858 | */ | ||
2859 | int vmw_kms_suspend(struct drm_device *dev) | ||
2860 | { | ||
2861 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
2862 | |||
2863 | dev_priv->suspend_state = drm_atomic_helper_suspend(dev); | ||
2864 | if (IS_ERR(dev_priv->suspend_state)) { | ||
2865 | int ret = PTR_ERR(dev_priv->suspend_state); | ||
2866 | |||
2867 | DRM_ERROR("Failed kms suspend: %d\n", ret); | ||
2868 | dev_priv->suspend_state = NULL; | ||
2869 | |||
2870 | return ret; | ||
2871 | } | ||
2872 | |||
2873 | return 0; | ||
2874 | } | ||
2875 | |||
2876 | |||
2877 | /** | ||
2878 | * vmw_kms_resume - Re-enable modesetting and restore state | ||
2879 | * | ||
2880 | * @dev: Pointer to the drm device | ||
2881 | * Return: 0 on success. Negative error code on failure. | ||
2882 | * | ||
2883 | * State is resumed from a previous vmw_kms_suspend(). It's illegal | ||
2884 | * to call this function without a previous vmw_kms_suspend(). | ||
2885 | */ | ||
2886 | int vmw_kms_resume(struct drm_device *dev) | ||
2887 | { | ||
2888 | struct vmw_private *dev_priv = vmw_priv(dev); | ||
2889 | int ret; | ||
2890 | |||
2891 | if (WARN_ON(!dev_priv->suspend_state)) | ||
2892 | return 0; | ||
2893 | |||
2894 | ret = drm_atomic_helper_resume(dev, dev_priv->suspend_state); | ||
2895 | dev_priv->suspend_state = NULL; | ||
2896 | |||
2897 | return ret; | ||
2898 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index cd9da2dd79af..4e8749a8717e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | |||
@@ -50,6 +50,7 @@ | |||
50 | * @unit: The current display unit. Set up by the helper before a call to @clip. | 50 | * @unit: The current display unit. Set up by the helper before a call to @clip. |
51 | * @cmd: The allocated fifo space. Set up by the helper before the first @clip | 51 | * @cmd: The allocated fifo space. Set up by the helper before the first @clip |
52 | * call. | 52 | * call. |
53 | * @crtc: The crtc for which to build dirty commands. | ||
53 | * @num_hits: Number of clip rect commands for this display unit. | 54 | * @num_hits: Number of clip rect commands for this display unit. |
54 | * Cleared by the helper before the first @clip call. Updated by the @clip | 55 | * Cleared by the helper before the first @clip call. Updated by the @clip |
55 | * callback. | 56 | * callback. |
@@ -71,6 +72,7 @@ struct vmw_kms_dirty { | |||
71 | struct vmw_private *dev_priv; | 72 | struct vmw_private *dev_priv; |
72 | struct vmw_display_unit *unit; | 73 | struct vmw_display_unit *unit; |
73 | void *cmd; | 74 | void *cmd; |
75 | struct drm_crtc *crtc; | ||
74 | u32 num_hits; | 76 | u32 num_hits; |
75 | s32 fb_x; | 77 | s32 fb_x; |
76 | s32 fb_y; | 78 | s32 fb_y; |
@@ -175,7 +177,6 @@ struct vmw_plane_state { | |||
175 | int pinned; | 177 | int pinned; |
176 | 178 | ||
177 | /* For CPU Blit */ | 179 | /* For CPU Blit */ |
178 | struct ttm_bo_kmap_obj host_map; | ||
179 | unsigned int cpp; | 180 | unsigned int cpp; |
180 | }; | 181 | }; |
181 | 182 | ||
@@ -287,7 +288,8 @@ int vmw_kms_helper_dirty(struct vmw_private *dev_priv, | |||
287 | int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, | 288 | int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, |
288 | struct vmw_dma_buffer *buf, | 289 | struct vmw_dma_buffer *buf, |
289 | bool interruptible, | 290 | bool interruptible, |
290 | bool validate_as_mob); | 291 | bool validate_as_mob, |
292 | bool for_cpu_blit); | ||
291 | void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf); | 293 | void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf); |
292 | void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, | 294 | void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, |
293 | struct drm_file *file_priv, | 295 | struct drm_file *file_priv, |
@@ -398,20 +400,23 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, | |||
398 | s32 dest_x, | 400 | s32 dest_x, |
399 | s32 dest_y, | 401 | s32 dest_y, |
400 | unsigned num_clips, int inc, | 402 | unsigned num_clips, int inc, |
401 | struct vmw_fence_obj **out_fence); | 403 | struct vmw_fence_obj **out_fence, |
404 | struct drm_crtc *crtc); | ||
402 | int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, | 405 | int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, |
403 | struct vmw_framebuffer *framebuffer, | 406 | struct vmw_framebuffer *framebuffer, |
404 | struct drm_clip_rect *clips, | 407 | struct drm_clip_rect *clips, |
405 | struct drm_vmw_rect *vclips, | 408 | struct drm_vmw_rect *vclips, |
406 | unsigned num_clips, int increment, | 409 | unsigned num_clips, int increment, |
407 | bool interruptible, | 410 | bool interruptible, |
408 | struct vmw_fence_obj **out_fence); | 411 | struct vmw_fence_obj **out_fence, |
412 | struct drm_crtc *crtc); | ||
409 | int vmw_kms_sou_readback(struct vmw_private *dev_priv, | 413 | int vmw_kms_sou_readback(struct vmw_private *dev_priv, |
410 | struct drm_file *file_priv, | 414 | struct drm_file *file_priv, |
411 | struct vmw_framebuffer *vfb, | 415 | struct vmw_framebuffer *vfb, |
412 | struct drm_vmw_fence_rep __user *user_fence_rep, | 416 | struct drm_vmw_fence_rep __user *user_fence_rep, |
413 | struct drm_vmw_rect *vclips, | 417 | struct drm_vmw_rect *vclips, |
414 | uint32_t num_clips); | 418 | uint32_t num_clips, |
419 | struct drm_crtc *crtc); | ||
415 | 420 | ||
416 | /* | 421 | /* |
417 | * Screen Target Display Unit functions - vmwgfx_stdu.c | 422 | * Screen Target Display Unit functions - vmwgfx_stdu.c |
@@ -425,7 +430,8 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, | |||
425 | s32 dest_x, | 430 | s32 dest_x, |
426 | s32 dest_y, | 431 | s32 dest_y, |
427 | unsigned num_clips, int inc, | 432 | unsigned num_clips, int inc, |
428 | struct vmw_fence_obj **out_fence); | 433 | struct vmw_fence_obj **out_fence, |
434 | struct drm_crtc *crtc); | ||
429 | int vmw_kms_stdu_dma(struct vmw_private *dev_priv, | 435 | int vmw_kms_stdu_dma(struct vmw_private *dev_priv, |
430 | struct drm_file *file_priv, | 436 | struct drm_file *file_priv, |
431 | struct vmw_framebuffer *vfb, | 437 | struct vmw_framebuffer *vfb, |
@@ -435,7 +441,8 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, | |||
435 | uint32_t num_clips, | 441 | uint32_t num_clips, |
436 | int increment, | 442 | int increment, |
437 | bool to_surface, | 443 | bool to_surface, |
438 | bool interruptible); | 444 | bool interruptible, |
445 | struct drm_crtc *crtc); | ||
439 | 446 | ||
440 | int vmw_kms_set_config(struct drm_mode_set *set, | 447 | int vmw_kms_set_config(struct drm_mode_set *set, |
441 | struct drm_modeset_acquire_ctx *ctx); | 448 | struct drm_modeset_acquire_ctx *ctx); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c index 97000996b8dc..cdff99211602 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_msg.c | |||
@@ -328,7 +328,7 @@ int vmw_host_get_guestinfo(const char *guest_info_param, | |||
328 | { | 328 | { |
329 | struct rpc_channel channel; | 329 | struct rpc_channel channel; |
330 | char *msg, *reply = NULL; | 330 | char *msg, *reply = NULL; |
331 | size_t msg_len, reply_len = 0; | 331 | size_t reply_len = 0; |
332 | int ret = 0; | 332 | int ret = 0; |
333 | 333 | ||
334 | 334 | ||
@@ -338,15 +338,12 @@ int vmw_host_get_guestinfo(const char *guest_info_param, | |||
338 | if (!guest_info_param || !length) | 338 | if (!guest_info_param || !length) |
339 | return -EINVAL; | 339 | return -EINVAL; |
340 | 340 | ||
341 | msg_len = strlen(guest_info_param) + strlen("info-get ") + 1; | 341 | msg = kasprintf(GFP_KERNEL, "info-get %s", guest_info_param); |
342 | msg = kzalloc(msg_len, GFP_KERNEL); | ||
343 | if (!msg) { | 342 | if (!msg) { |
344 | DRM_ERROR("Cannot allocate memory to get %s", guest_info_param); | 343 | DRM_ERROR("Cannot allocate memory to get %s", guest_info_param); |
345 | return -ENOMEM; | 344 | return -ENOMEM; |
346 | } | 345 | } |
347 | 346 | ||
348 | sprintf(msg, "info-get %s", guest_info_param); | ||
349 | |||
350 | if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || | 347 | if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || |
351 | vmw_send_msg(&channel, msg) || | 348 | vmw_send_msg(&channel, msg) || |
352 | vmw_recv_msg(&channel, (void *) &reply, &reply_len) || | 349 | vmw_recv_msg(&channel, (void *) &reply, &reply_len) || |
@@ -388,7 +385,6 @@ int vmw_host_log(const char *log) | |||
388 | { | 385 | { |
389 | struct rpc_channel channel; | 386 | struct rpc_channel channel; |
390 | char *msg; | 387 | char *msg; |
391 | int msg_len; | ||
392 | int ret = 0; | 388 | int ret = 0; |
393 | 389 | ||
394 | 390 | ||
@@ -398,15 +394,12 @@ int vmw_host_log(const char *log) | |||
398 | if (!log) | 394 | if (!log) |
399 | return ret; | 395 | return ret; |
400 | 396 | ||
401 | msg_len = strlen(log) + strlen("log ") + 1; | 397 | msg = kasprintf(GFP_KERNEL, "log %s", log); |
402 | msg = kzalloc(msg_len, GFP_KERNEL); | ||
403 | if (!msg) { | 398 | if (!msg) { |
404 | DRM_ERROR("Cannot allocate memory for log message\n"); | 399 | DRM_ERROR("Cannot allocate memory for log message\n"); |
405 | return -ENOMEM; | 400 | return -ENOMEM; |
406 | } | 401 | } |
407 | 402 | ||
408 | sprintf(msg, "log %s", log); | ||
409 | |||
410 | if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || | 403 | if (vmw_open_channel(&channel, RPCI_PROTOCOL_NUM) || |
411 | vmw_send_msg(&channel, msg) || | 404 | vmw_send_msg(&channel, msg) || |
412 | vmw_close_channel(&channel)) { | 405 | vmw_close_channel(&channel)) { |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 9e101450cc4d..6b3a942b18df 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | |||
@@ -354,6 +354,7 @@ void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo) | |||
354 | { | 354 | { |
355 | struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); | 355 | struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo); |
356 | 356 | ||
357 | vmw_dma_buffer_unmap(vmw_bo); | ||
357 | kfree(vmw_bo); | 358 | kfree(vmw_bo); |
358 | } | 359 | } |
359 | 360 | ||
@@ -361,6 +362,7 @@ static void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo) | |||
361 | { | 362 | { |
362 | struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); | 363 | struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo); |
363 | 364 | ||
365 | vmw_dma_buffer_unmap(&vmw_user_bo->dma); | ||
364 | ttm_prime_object_kfree(vmw_user_bo, prime); | 366 | ttm_prime_object_kfree(vmw_user_bo, prime); |
365 | } | 367 | } |
366 | 368 | ||
@@ -1239,6 +1241,12 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, | |||
1239 | 1241 | ||
1240 | dma_buf = container_of(bo, struct vmw_dma_buffer, base); | 1242 | dma_buf = container_of(bo, struct vmw_dma_buffer, base); |
1241 | 1243 | ||
1244 | /* | ||
1245 | * Kill any cached kernel maps before move. An optimization could | ||
1246 | * be to do this iff source or destination memory type is VRAM. | ||
1247 | */ | ||
1248 | vmw_dma_buffer_unmap(dma_buf); | ||
1249 | |||
1242 | if (mem->mem_type != VMW_PL_MOB) { | 1250 | if (mem->mem_type != VMW_PL_MOB) { |
1243 | struct vmw_resource *res, *n; | 1251 | struct vmw_resource *res, *n; |
1244 | struct ttm_validate_buffer val_buf; | 1252 | struct ttm_validate_buffer val_buf; |
@@ -1262,6 +1270,21 @@ void vmw_resource_move_notify(struct ttm_buffer_object *bo, | |||
1262 | } | 1270 | } |
1263 | 1271 | ||
1264 | 1272 | ||
1273 | /** | ||
1274 | * vmw_resource_swap_notify - swapout notify callback. | ||
1275 | * | ||
1276 | * @bo: The buffer object to be swapped out. | ||
1277 | */ | ||
1278 | void vmw_resource_swap_notify(struct ttm_buffer_object *bo) | ||
1279 | { | ||
1280 | if (bo->destroy != vmw_dmabuf_bo_free && | ||
1281 | bo->destroy != vmw_user_dmabuf_destroy) | ||
1282 | return; | ||
1283 | |||
1284 | /* Kill any cached kernel maps before swapout */ | ||
1285 | vmw_dma_buffer_unmap(vmw_dma_buffer(bo)); | ||
1286 | } | ||
1287 | |||
1265 | 1288 | ||
1266 | /** | 1289 | /** |
1267 | * vmw_query_readback_all - Read back cached query states | 1290 | * vmw_query_readback_all - Read back cached query states |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 63a4cd794b73..419185f60278 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | |||
@@ -316,69 +316,21 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, | |||
316 | struct drm_modeset_acquire_ctx *ctx) | 316 | struct drm_modeset_acquire_ctx *ctx) |
317 | { | 317 | { |
318 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | 318 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
319 | struct drm_framebuffer *old_fb = crtc->primary->fb; | ||
320 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); | ||
321 | struct vmw_fence_obj *fence = NULL; | ||
322 | struct drm_vmw_rect vclips; | ||
323 | int ret; | 319 | int ret; |
324 | 320 | ||
325 | if (!vmw_kms_crtc_flippable(dev_priv, crtc)) | 321 | if (!vmw_kms_crtc_flippable(dev_priv, crtc)) |
326 | return -EINVAL; | 322 | return -EINVAL; |
327 | 323 | ||
328 | flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; | 324 | ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); |
329 | ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx); | ||
330 | if (ret) { | 325 | if (ret) { |
331 | DRM_ERROR("Page flip error %d.\n", ret); | 326 | DRM_ERROR("Page flip error %d.\n", ret); |
332 | return ret; | 327 | return ret; |
333 | } | 328 | } |
334 | 329 | ||
335 | /* do a full screen dirty update */ | ||
336 | vclips.x = crtc->x; | ||
337 | vclips.y = crtc->y; | ||
338 | vclips.w = crtc->mode.hdisplay; | ||
339 | vclips.h = crtc->mode.vdisplay; | ||
340 | |||
341 | if (vfb->dmabuf) | ||
342 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, | ||
343 | NULL, &vclips, 1, 1, | ||
344 | true, &fence); | ||
345 | else | ||
346 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, | ||
347 | NULL, &vclips, NULL, | ||
348 | 0, 0, 1, 1, &fence); | ||
349 | |||
350 | |||
351 | if (ret != 0) | ||
352 | goto out_no_fence; | ||
353 | if (!fence) { | ||
354 | ret = -EINVAL; | ||
355 | goto out_no_fence; | ||
356 | } | ||
357 | |||
358 | if (event) { | ||
359 | struct drm_file *file_priv = event->base.file_priv; | ||
360 | |||
361 | ret = vmw_event_fence_action_queue(file_priv, fence, | ||
362 | &event->base, | ||
363 | &event->event.vbl.tv_sec, | ||
364 | &event->event.vbl.tv_usec, | ||
365 | true); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * No need to hold on to this now. The only cleanup | ||
370 | * we need to do if we fail is unref the fence. | ||
371 | */ | ||
372 | vmw_fence_obj_unreference(&fence); | ||
373 | |||
374 | if (vmw_crtc_to_du(crtc)->is_implicit) | 330 | if (vmw_crtc_to_du(crtc)->is_implicit) |
375 | vmw_kms_update_implicit_fb(dev_priv, crtc); | 331 | vmw_kms_update_implicit_fb(dev_priv, crtc); |
376 | 332 | ||
377 | return ret; | 333 | return ret; |
378 | |||
379 | out_no_fence: | ||
380 | drm_atomic_set_fb_for_plane(crtc->primary->state, old_fb); | ||
381 | return ret; | ||
382 | } | 334 | } |
383 | 335 | ||
384 | static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { | 336 | static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { |
@@ -453,7 +405,11 @@ vmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane, | |||
453 | struct drm_plane_state *old_state) | 405 | struct drm_plane_state *old_state) |
454 | { | 406 | { |
455 | struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); | 407 | struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); |
408 | struct drm_crtc *crtc = plane->state->crtc ? | ||
409 | plane->state->crtc : old_state->crtc; | ||
456 | 410 | ||
411 | if (vps->dmabuf) | ||
412 | vmw_dmabuf_unpin(vmw_priv(crtc->dev), vps->dmabuf, false); | ||
457 | vmw_dmabuf_unreference(&vps->dmabuf); | 413 | vmw_dmabuf_unreference(&vps->dmabuf); |
458 | vps->dmabuf_size = 0; | 414 | vps->dmabuf_size = 0; |
459 | 415 | ||
@@ -491,10 +447,17 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, | |||
491 | } | 447 | } |
492 | 448 | ||
493 | size = new_state->crtc_w * new_state->crtc_h * 4; | 449 | size = new_state->crtc_w * new_state->crtc_h * 4; |
450 | dev_priv = vmw_priv(crtc->dev); | ||
494 | 451 | ||
495 | if (vps->dmabuf) { | 452 | if (vps->dmabuf) { |
496 | if (vps->dmabuf_size == size) | 453 | if (vps->dmabuf_size == size) { |
497 | return 0; | 454 | /* |
455 | * Note that this might temporarily up the pin-count | ||
456 | * to 2, until cleanup_fb() is called. | ||
457 | */ | ||
458 | return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, | ||
459 | true); | ||
460 | } | ||
498 | 461 | ||
499 | vmw_dmabuf_unreference(&vps->dmabuf); | 462 | vmw_dmabuf_unreference(&vps->dmabuf); |
500 | vps->dmabuf_size = 0; | 463 | vps->dmabuf_size = 0; |
@@ -504,7 +467,6 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, | |||
504 | if (!vps->dmabuf) | 467 | if (!vps->dmabuf) |
505 | return -ENOMEM; | 468 | return -ENOMEM; |
506 | 469 | ||
507 | dev_priv = vmw_priv(crtc->dev); | ||
508 | vmw_svga_enable(dev_priv); | 470 | vmw_svga_enable(dev_priv); |
509 | 471 | ||
510 | /* After we have alloced the backing store might not be able to | 472 | /* After we have alloced the backing store might not be able to |
@@ -515,13 +477,16 @@ vmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, | |||
515 | &vmw_vram_ne_placement, | 477 | &vmw_vram_ne_placement, |
516 | false, &vmw_dmabuf_bo_free); | 478 | false, &vmw_dmabuf_bo_free); |
517 | vmw_overlay_resume_all(dev_priv); | 479 | vmw_overlay_resume_all(dev_priv); |
518 | 480 | if (ret) { | |
519 | if (ret != 0) | ||
520 | vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */ | 481 | vps->dmabuf = NULL; /* vmw_dmabuf_init frees on error */ |
521 | else | 482 | return ret; |
522 | vps->dmabuf_size = size; | 483 | } |
523 | 484 | ||
524 | return ret; | 485 | /* |
486 | * TTM already thinks the buffer is pinned, but make sure the | ||
487 | * pin_count is upped. | ||
488 | */ | ||
489 | return vmw_dmabuf_pin_in_vram(dev_priv, vps->dmabuf, true); | ||
525 | } | 490 | } |
526 | 491 | ||
527 | 492 | ||
@@ -530,9 +495,71 @@ vmw_sou_primary_plane_atomic_update(struct drm_plane *plane, | |||
530 | struct drm_plane_state *old_state) | 495 | struct drm_plane_state *old_state) |
531 | { | 496 | { |
532 | struct drm_crtc *crtc = plane->state->crtc; | 497 | struct drm_crtc *crtc = plane->state->crtc; |
498 | struct drm_pending_vblank_event *event = NULL; | ||
499 | struct vmw_fence_obj *fence = NULL; | ||
500 | int ret; | ||
501 | |||
502 | if (crtc && plane->state->fb) { | ||
503 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | ||
504 | struct vmw_framebuffer *vfb = | ||
505 | vmw_framebuffer_to_vfb(plane->state->fb); | ||
506 | struct drm_vmw_rect vclips; | ||
507 | |||
508 | vclips.x = crtc->x; | ||
509 | vclips.y = crtc->y; | ||
510 | vclips.w = crtc->mode.hdisplay; | ||
511 | vclips.h = crtc->mode.vdisplay; | ||
512 | |||
513 | if (vfb->dmabuf) | ||
514 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, NULL, | ||
515 | &vclips, 1, 1, true, | ||
516 | &fence, crtc); | ||
517 | else | ||
518 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, | ||
519 | &vclips, NULL, 0, 0, | ||
520 | 1, 1, &fence, crtc); | ||
521 | |||
522 | /* | ||
523 | * We cannot really fail this function, so if we do, then output | ||
524 | * an error and maintain consistent atomic state. | ||
525 | */ | ||
526 | if (ret != 0) | ||
527 | DRM_ERROR("Failed to update screen.\n"); | ||
533 | 528 | ||
534 | if (crtc) | ||
535 | crtc->primary->fb = plane->state->fb; | 529 | crtc->primary->fb = plane->state->fb; |
530 | } else { | ||
531 | /* | ||
532 | * When disabling a plane, CRTC and FB should always be NULL | ||
533 | * together, otherwise it's an error. | ||
534 | * Here primary plane is being disable so should really blank | ||
535 | * the screen object display unit, if not already done. | ||
536 | */ | ||
537 | return; | ||
538 | } | ||
539 | |||
540 | event = crtc->state->event; | ||
541 | /* | ||
542 | * In case of failure and other cases, vblank event will be sent in | ||
543 | * vmw_du_crtc_atomic_flush. | ||
544 | */ | ||
545 | if (event && fence) { | ||
546 | struct drm_file *file_priv = event->base.file_priv; | ||
547 | |||
548 | ret = vmw_event_fence_action_queue(file_priv, | ||
549 | fence, | ||
550 | &event->base, | ||
551 | &event->event.vbl.tv_sec, | ||
552 | &event->event.vbl.tv_usec, | ||
553 | true); | ||
554 | |||
555 | if (unlikely(ret != 0)) | ||
556 | DRM_ERROR("Failed to queue event on fence.\n"); | ||
557 | else | ||
558 | crtc->state->event = NULL; | ||
559 | } | ||
560 | |||
561 | if (fence) | ||
562 | vmw_fence_obj_unreference(&fence); | ||
536 | } | 563 | } |
537 | 564 | ||
538 | 565 | ||
@@ -892,6 +919,7 @@ static void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty) | |||
892 | * @out_fence: If non-NULL, will return a ref-counted pointer to a | 919 | * @out_fence: If non-NULL, will return a ref-counted pointer to a |
893 | * struct vmw_fence_obj. The returned fence pointer may be NULL in which | 920 | * struct vmw_fence_obj. The returned fence pointer may be NULL in which |
894 | * case the device has already synchronized. | 921 | * case the device has already synchronized. |
922 | * @crtc: If crtc is passed, perform surface dirty on that crtc only. | ||
895 | * | 923 | * |
896 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if | 924 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if |
897 | * interrupted. | 925 | * interrupted. |
@@ -904,7 +932,8 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, | |||
904 | s32 dest_x, | 932 | s32 dest_x, |
905 | s32 dest_y, | 933 | s32 dest_y, |
906 | unsigned num_clips, int inc, | 934 | unsigned num_clips, int inc, |
907 | struct vmw_fence_obj **out_fence) | 935 | struct vmw_fence_obj **out_fence, |
936 | struct drm_crtc *crtc) | ||
908 | { | 937 | { |
909 | struct vmw_framebuffer_surface *vfbs = | 938 | struct vmw_framebuffer_surface *vfbs = |
910 | container_of(framebuffer, typeof(*vfbs), base); | 939 | container_of(framebuffer, typeof(*vfbs), base); |
@@ -923,6 +952,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, | |||
923 | sdirty.base.dev_priv = dev_priv; | 952 | sdirty.base.dev_priv = dev_priv; |
924 | sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) + | 953 | sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) + |
925 | sizeof(SVGASignedRect) * num_clips; | 954 | sizeof(SVGASignedRect) * num_clips; |
955 | sdirty.base.crtc = crtc; | ||
926 | 956 | ||
927 | sdirty.sid = srf->id; | 957 | sdirty.sid = srf->id; |
928 | sdirty.left = sdirty.top = S32_MAX; | 958 | sdirty.left = sdirty.top = S32_MAX; |
@@ -994,6 +1024,7 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) | |||
994 | * @out_fence: If non-NULL, will return a ref-counted pointer to a | 1024 | * @out_fence: If non-NULL, will return a ref-counted pointer to a |
995 | * struct vmw_fence_obj. The returned fence pointer may be NULL in which | 1025 | * struct vmw_fence_obj. The returned fence pointer may be NULL in which |
996 | * case the device has already synchronized. | 1026 | * case the device has already synchronized. |
1027 | * @crtc: If crtc is passed, perform dmabuf dirty on that crtc only. | ||
997 | * | 1028 | * |
998 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if | 1029 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if |
999 | * interrupted. | 1030 | * interrupted. |
@@ -1004,7 +1035,8 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, | |||
1004 | struct drm_vmw_rect *vclips, | 1035 | struct drm_vmw_rect *vclips, |
1005 | unsigned num_clips, int increment, | 1036 | unsigned num_clips, int increment, |
1006 | bool interruptible, | 1037 | bool interruptible, |
1007 | struct vmw_fence_obj **out_fence) | 1038 | struct vmw_fence_obj **out_fence, |
1039 | struct drm_crtc *crtc) | ||
1008 | { | 1040 | { |
1009 | struct vmw_dma_buffer *buf = | 1041 | struct vmw_dma_buffer *buf = |
1010 | container_of(framebuffer, struct vmw_framebuffer_dmabuf, | 1042 | container_of(framebuffer, struct vmw_framebuffer_dmabuf, |
@@ -1013,7 +1045,7 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, | |||
1013 | int ret; | 1045 | int ret; |
1014 | 1046 | ||
1015 | ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, | 1047 | ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, |
1016 | false); | 1048 | false, false); |
1017 | if (ret) | 1049 | if (ret) |
1018 | return ret; | 1050 | return ret; |
1019 | 1051 | ||
@@ -1021,6 +1053,7 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, | |||
1021 | if (unlikely(ret != 0)) | 1053 | if (unlikely(ret != 0)) |
1022 | goto out_revert; | 1054 | goto out_revert; |
1023 | 1055 | ||
1056 | dirty.crtc = crtc; | ||
1024 | dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit; | 1057 | dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit; |
1025 | dirty.clip = vmw_sou_dmabuf_clip; | 1058 | dirty.clip = vmw_sou_dmabuf_clip; |
1026 | dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * | 1059 | dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * |
@@ -1092,6 +1125,7 @@ static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty) | |||
1092 | * Must be set to non-NULL if @file_priv is non-NULL. | 1125 | * Must be set to non-NULL if @file_priv is non-NULL. |
1093 | * @vclips: Array of clip rects. | 1126 | * @vclips: Array of clip rects. |
1094 | * @num_clips: Number of clip rects in @vclips. | 1127 | * @num_clips: Number of clip rects in @vclips. |
1128 | * @crtc: If crtc is passed, readback on that crtc only. | ||
1095 | * | 1129 | * |
1096 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if | 1130 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if |
1097 | * interrupted. | 1131 | * interrupted. |
@@ -1101,14 +1135,16 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, | |||
1101 | struct vmw_framebuffer *vfb, | 1135 | struct vmw_framebuffer *vfb, |
1102 | struct drm_vmw_fence_rep __user *user_fence_rep, | 1136 | struct drm_vmw_fence_rep __user *user_fence_rep, |
1103 | struct drm_vmw_rect *vclips, | 1137 | struct drm_vmw_rect *vclips, |
1104 | uint32_t num_clips) | 1138 | uint32_t num_clips, |
1139 | struct drm_crtc *crtc) | ||
1105 | { | 1140 | { |
1106 | struct vmw_dma_buffer *buf = | 1141 | struct vmw_dma_buffer *buf = |
1107 | container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; | 1142 | container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; |
1108 | struct vmw_kms_dirty dirty; | 1143 | struct vmw_kms_dirty dirty; |
1109 | int ret; | 1144 | int ret; |
1110 | 1145 | ||
1111 | ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false); | 1146 | ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false, |
1147 | false); | ||
1112 | if (ret) | 1148 | if (ret) |
1113 | return ret; | 1149 | return ret; |
1114 | 1150 | ||
@@ -1116,6 +1152,7 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, | |||
1116 | if (unlikely(ret != 0)) | 1152 | if (unlikely(ret != 0)) |
1117 | goto out_revert; | 1153 | goto out_revert; |
1118 | 1154 | ||
1155 | dirty.crtc = crtc; | ||
1119 | dirty.fifo_commit = vmw_sou_readback_fifo_commit; | 1156 | dirty.fifo_commit = vmw_sou_readback_fifo_commit; |
1120 | dirty.clip = vmw_sou_readback_clip; | 1157 | dirty.clip = vmw_sou_readback_clip; |
1121 | dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) * | 1158 | dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) * |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index b68d74888ab1..8eec88920851 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | |||
@@ -114,7 +114,6 @@ struct vmw_screen_target_display_unit { | |||
114 | bool defined; | 114 | bool defined; |
115 | 115 | ||
116 | /* For CPU Blit */ | 116 | /* For CPU Blit */ |
117 | struct ttm_bo_kmap_obj host_map; | ||
118 | unsigned int cpp; | 117 | unsigned int cpp; |
119 | }; | 118 | }; |
120 | 119 | ||
@@ -492,71 +491,17 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, | |||
492 | { | 491 | { |
493 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | 492 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
494 | struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); | 493 | struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); |
495 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); | ||
496 | struct drm_vmw_rect vclips; | ||
497 | int ret; | 494 | int ret; |
498 | 495 | ||
499 | dev_priv = vmw_priv(crtc->dev); | ||
500 | stdu = vmw_crtc_to_stdu(crtc); | ||
501 | |||
502 | if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) | 496 | if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) |
503 | return -EINVAL; | 497 | return -EINVAL; |
504 | 498 | ||
505 | /* | 499 | ret = drm_atomic_helper_page_flip(crtc, new_fb, event, flags, ctx); |
506 | * We're always async, but the helper doesn't know how to set async | ||
507 | * so lie to the helper. Also, the helper expects someone | ||
508 | * to pick the event up from the crtc state, and if nobody does, | ||
509 | * it will free it. Since we handle the event in this function, | ||
510 | * don't hand it to the helper. | ||
511 | */ | ||
512 | flags &= ~DRM_MODE_PAGE_FLIP_ASYNC; | ||
513 | ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx); | ||
514 | if (ret) { | 500 | if (ret) { |
515 | DRM_ERROR("Page flip error %d.\n", ret); | 501 | DRM_ERROR("Page flip error %d.\n", ret); |
516 | return ret; | 502 | return ret; |
517 | } | 503 | } |
518 | 504 | ||
519 | if (stdu->base.is_implicit) | ||
520 | vmw_kms_update_implicit_fb(dev_priv, crtc); | ||
521 | |||
522 | /* | ||
523 | * Now that we've bound a new surface to the screen target, | ||
524 | * update the contents. | ||
525 | */ | ||
526 | vclips.x = crtc->x; | ||
527 | vclips.y = crtc->y; | ||
528 | vclips.w = crtc->mode.hdisplay; | ||
529 | vclips.h = crtc->mode.vdisplay; | ||
530 | |||
531 | if (vfb->dmabuf) | ||
532 | ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips, | ||
533 | 1, 1, true, false); | ||
534 | else | ||
535 | ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips, | ||
536 | NULL, 0, 0, 1, 1, NULL); | ||
537 | if (ret) { | ||
538 | DRM_ERROR("Page flip update error %d.\n", ret); | ||
539 | return ret; | ||
540 | } | ||
541 | |||
542 | if (event) { | ||
543 | struct vmw_fence_obj *fence = NULL; | ||
544 | struct drm_file *file_priv = event->base.file_priv; | ||
545 | |||
546 | vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); | ||
547 | if (!fence) | ||
548 | return -ENOMEM; | ||
549 | |||
550 | ret = vmw_event_fence_action_queue(file_priv, fence, | ||
551 | &event->base, | ||
552 | &event->event.vbl.tv_sec, | ||
553 | &event->event.vbl.tv_usec, | ||
554 | true); | ||
555 | vmw_fence_obj_unreference(&fence); | ||
556 | } else { | ||
557 | (void) vmw_fifo_flush(dev_priv, false); | ||
558 | } | ||
559 | |||
560 | return 0; | 505 | return 0; |
561 | } | 506 | } |
562 | 507 | ||
@@ -693,10 +638,9 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) | |||
693 | container_of(dirty->unit, typeof(*stdu), base); | 638 | container_of(dirty->unit, typeof(*stdu), base); |
694 | s32 width, height; | 639 | s32 width, height; |
695 | s32 src_pitch, dst_pitch; | 640 | s32 src_pitch, dst_pitch; |
696 | u8 *src, *dst; | 641 | struct ttm_buffer_object *src_bo, *dst_bo; |
697 | bool not_used; | 642 | u32 src_offset, dst_offset; |
698 | struct ttm_bo_kmap_obj guest_map; | 643 | struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(stdu->cpp); |
699 | int ret; | ||
700 | 644 | ||
701 | if (!dirty->num_hits) | 645 | if (!dirty->num_hits) |
702 | return; | 646 | return; |
@@ -707,57 +651,38 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) | |||
707 | if (width == 0 || height == 0) | 651 | if (width == 0 || height == 0) |
708 | return; | 652 | return; |
709 | 653 | ||
710 | ret = ttm_bo_kmap(&ddirty->buf->base, 0, ddirty->buf->base.num_pages, | 654 | /* Assume we are blitting from Guest (dmabuf) to Host (display_srf) */ |
711 | &guest_map); | 655 | dst_pitch = stdu->display_srf->base_size.width * stdu->cpp; |
712 | if (ret) { | 656 | dst_bo = &stdu->display_srf->res.backup->base; |
713 | DRM_ERROR("Failed mapping framebuffer for blit: %d\n", | 657 | dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp; |
714 | ret); | ||
715 | goto out_cleanup; | ||
716 | } | ||
717 | |||
718 | /* Assume we are blitting from Host (display_srf) to Guest (dmabuf) */ | ||
719 | src_pitch = stdu->display_srf->base_size.width * stdu->cpp; | ||
720 | src = ttm_kmap_obj_virtual(&stdu->host_map, ¬_used); | ||
721 | src += ddirty->top * src_pitch + ddirty->left * stdu->cpp; | ||
722 | |||
723 | dst_pitch = ddirty->pitch; | ||
724 | dst = ttm_kmap_obj_virtual(&guest_map, ¬_used); | ||
725 | dst += ddirty->fb_top * dst_pitch + ddirty->fb_left * stdu->cpp; | ||
726 | |||
727 | |||
728 | /* Figure out the real direction */ | ||
729 | if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { | ||
730 | u8 *tmp; | ||
731 | s32 tmp_pitch; | ||
732 | |||
733 | tmp = src; | ||
734 | tmp_pitch = src_pitch; | ||
735 | 658 | ||
736 | src = dst; | 659 | src_pitch = ddirty->pitch; |
737 | src_pitch = dst_pitch; | 660 | src_bo = &ddirty->buf->base; |
661 | src_offset = ddirty->fb_top * src_pitch + ddirty->fb_left * stdu->cpp; | ||
738 | 662 | ||
739 | dst = tmp; | 663 | /* Swap src and dst if the assumption was wrong. */ |
740 | dst_pitch = tmp_pitch; | 664 | if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) { |
665 | swap(dst_pitch, src_pitch); | ||
666 | swap(dst_bo, src_bo); | ||
667 | swap(src_offset, dst_offset); | ||
741 | } | 668 | } |
742 | 669 | ||
743 | /* CPU Blit */ | 670 | (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, |
744 | while (height-- > 0) { | 671 | src_bo, src_offset, src_pitch, |
745 | memcpy(dst, src, width * stdu->cpp); | 672 | width * stdu->cpp, height, &diff); |
746 | dst += dst_pitch; | ||
747 | src += src_pitch; | ||
748 | } | ||
749 | 673 | ||
750 | if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { | 674 | if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM && |
675 | drm_rect_visible(&diff.rect)) { | ||
751 | struct vmw_private *dev_priv; | 676 | struct vmw_private *dev_priv; |
752 | struct vmw_stdu_update *cmd; | 677 | struct vmw_stdu_update *cmd; |
753 | struct drm_clip_rect region; | 678 | struct drm_clip_rect region; |
754 | int ret; | 679 | int ret; |
755 | 680 | ||
756 | /* We are updating the actual surface, not a proxy */ | 681 | /* We are updating the actual surface, not a proxy */ |
757 | region.x1 = ddirty->left; | 682 | region.x1 = diff.rect.x1; |
758 | region.x2 = ddirty->right; | 683 | region.x2 = diff.rect.x2; |
759 | region.y1 = ddirty->top; | 684 | region.y1 = diff.rect.y1; |
760 | region.y2 = ddirty->bottom; | 685 | region.y2 = diff.rect.y2; |
761 | ret = vmw_kms_update_proxy( | 686 | ret = vmw_kms_update_proxy( |
762 | (struct vmw_resource *) &stdu->display_srf->res, | 687 | (struct vmw_resource *) &stdu->display_srf->res, |
763 | (const struct drm_clip_rect *) ®ion, 1, 1); | 688 | (const struct drm_clip_rect *) ®ion, 1, 1); |
@@ -774,13 +699,12 @@ static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty) | |||
774 | } | 699 | } |
775 | 700 | ||
776 | vmw_stdu_populate_update(cmd, stdu->base.unit, | 701 | vmw_stdu_populate_update(cmd, stdu->base.unit, |
777 | ddirty->left, ddirty->right, | 702 | region.x1, region.x2, |
778 | ddirty->top, ddirty->bottom); | 703 | region.y1, region.y2); |
779 | 704 | ||
780 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); | 705 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
781 | } | 706 | } |
782 | 707 | ||
783 | ttm_bo_kunmap(&guest_map); | ||
784 | out_cleanup: | 708 | out_cleanup: |
785 | ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX; | 709 | ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX; |
786 | ddirty->right = ddirty->bottom = S32_MIN; | 710 | ddirty->right = ddirty->bottom = S32_MIN; |
@@ -802,6 +726,7 @@ out_cleanup: | |||
802 | * @to_surface: Whether to DMA to the screen target system as opposed to | 726 | * @to_surface: Whether to DMA to the screen target system as opposed to |
803 | * from the screen target system. | 727 | * from the screen target system. |
804 | * @interruptible: Whether to perform waits interruptible if possible. | 728 | * @interruptible: Whether to perform waits interruptible if possible. |
729 | * @crtc: If crtc is passed, perform stdu dma on that crtc only. | ||
805 | * | 730 | * |
806 | * If DMA-ing till the screen target system, the function will also notify | 731 | * If DMA-ing till the screen target system, the function will also notify |
807 | * the screen target system that a bounding box of the cliprects has been | 732 | * the screen target system that a bounding box of the cliprects has been |
@@ -818,15 +743,22 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, | |||
818 | uint32_t num_clips, | 743 | uint32_t num_clips, |
819 | int increment, | 744 | int increment, |
820 | bool to_surface, | 745 | bool to_surface, |
821 | bool interruptible) | 746 | bool interruptible, |
747 | struct drm_crtc *crtc) | ||
822 | { | 748 | { |
823 | struct vmw_dma_buffer *buf = | 749 | struct vmw_dma_buffer *buf = |
824 | container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; | 750 | container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; |
825 | struct vmw_stdu_dirty ddirty; | 751 | struct vmw_stdu_dirty ddirty; |
826 | int ret; | 752 | int ret; |
753 | bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); | ||
827 | 754 | ||
755 | /* | ||
756 | * VMs without 3D support don't have the surface DMA command and | ||
757 | * we'll be using a CPU blit, and the framebuffer should be moved out | ||
758 | * of VRAM. | ||
759 | */ | ||
828 | ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, | 760 | ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, |
829 | false); | 761 | false, cpu_blit); |
830 | if (ret) | 762 | if (ret) |
831 | return ret; | 763 | return ret; |
832 | 764 | ||
@@ -845,13 +777,15 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv, | |||
845 | if (to_surface) | 777 | if (to_surface) |
846 | ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update); | 778 | ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update); |
847 | 779 | ||
848 | /* 2D VMs cannot use SVGA_3D_CMD_SURFACE_DMA so do CPU blit instead */ | 780 | |
849 | if (!(dev_priv->capabilities & SVGA_CAP_3D)) { | 781 | if (cpu_blit) { |
850 | ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit; | 782 | ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit; |
851 | ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip; | 783 | ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip; |
852 | ddirty.base.fifo_reserve_size = 0; | 784 | ddirty.base.fifo_reserve_size = 0; |
853 | } | 785 | } |
854 | 786 | ||
787 | ddirty.base.crtc = crtc; | ||
788 | |||
855 | ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips, | 789 | ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips, |
856 | 0, 0, num_clips, increment, &ddirty.base); | 790 | 0, 0, num_clips, increment, &ddirty.base); |
857 | vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL, | 791 | vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL, |
@@ -963,6 +897,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) | |||
963 | * @out_fence: If non-NULL, will return a ref-counted pointer to a | 897 | * @out_fence: If non-NULL, will return a ref-counted pointer to a |
964 | * struct vmw_fence_obj. The returned fence pointer may be NULL in which | 898 | * struct vmw_fence_obj. The returned fence pointer may be NULL in which |
965 | * case the device has already synchronized. | 899 | * case the device has already synchronized. |
900 | * @crtc: If crtc is passed, perform surface dirty on that crtc only. | ||
966 | * | 901 | * |
967 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if | 902 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if |
968 | * interrupted. | 903 | * interrupted. |
@@ -975,7 +910,8 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, | |||
975 | s32 dest_x, | 910 | s32 dest_x, |
976 | s32 dest_y, | 911 | s32 dest_y, |
977 | unsigned num_clips, int inc, | 912 | unsigned num_clips, int inc, |
978 | struct vmw_fence_obj **out_fence) | 913 | struct vmw_fence_obj **out_fence, |
914 | struct drm_crtc *crtc) | ||
979 | { | 915 | { |
980 | struct vmw_framebuffer_surface *vfbs = | 916 | struct vmw_framebuffer_surface *vfbs = |
981 | container_of(framebuffer, typeof(*vfbs), base); | 917 | container_of(framebuffer, typeof(*vfbs), base); |
@@ -1000,6 +936,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, | |||
1000 | sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) + | 936 | sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) + |
1001 | sizeof(SVGA3dCopyBox) * num_clips + | 937 | sizeof(SVGA3dCopyBox) * num_clips + |
1002 | sizeof(struct vmw_stdu_update); | 938 | sizeof(struct vmw_stdu_update); |
939 | sdirty.base.crtc = crtc; | ||
1003 | sdirty.sid = srf->id; | 940 | sdirty.sid = srf->id; |
1004 | sdirty.left = sdirty.top = S32_MAX; | 941 | sdirty.left = sdirty.top = S32_MAX; |
1005 | sdirty.right = sdirty.bottom = S32_MIN; | 942 | sdirty.right = sdirty.bottom = S32_MIN; |
@@ -1118,9 +1055,6 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, | |||
1118 | { | 1055 | { |
1119 | struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); | 1056 | struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); |
1120 | 1057 | ||
1121 | if (vps->host_map.virtual) | ||
1122 | ttm_bo_kunmap(&vps->host_map); | ||
1123 | |||
1124 | if (vps->surf) | 1058 | if (vps->surf) |
1125 | WARN_ON(!vps->pinned); | 1059 | WARN_ON(!vps->pinned); |
1126 | 1060 | ||
@@ -1282,24 +1216,11 @@ vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, | |||
1282 | * so cache these mappings | 1216 | * so cache these mappings |
1283 | */ | 1217 | */ |
1284 | if (vps->content_fb_type == SEPARATE_DMA && | 1218 | if (vps->content_fb_type == SEPARATE_DMA && |
1285 | !(dev_priv->capabilities & SVGA_CAP_3D)) { | 1219 | !(dev_priv->capabilities & SVGA_CAP_3D)) |
1286 | ret = ttm_bo_kmap(&vps->surf->res.backup->base, 0, | ||
1287 | vps->surf->res.backup->base.num_pages, | ||
1288 | &vps->host_map); | ||
1289 | if (ret) { | ||
1290 | DRM_ERROR("Failed to map display buffer to CPU\n"); | ||
1291 | goto out_srf_unpin; | ||
1292 | } | ||
1293 | |||
1294 | vps->cpp = new_fb->pitches[0] / new_fb->width; | 1220 | vps->cpp = new_fb->pitches[0] / new_fb->width; |
1295 | } | ||
1296 | 1221 | ||
1297 | return 0; | 1222 | return 0; |
1298 | 1223 | ||
1299 | out_srf_unpin: | ||
1300 | vmw_resource_unpin(&vps->surf->res); | ||
1301 | vps->pinned--; | ||
1302 | |||
1303 | out_srf_unref: | 1224 | out_srf_unref: |
1304 | vmw_surface_unreference(&vps->surf); | 1225 | vmw_surface_unreference(&vps->surf); |
1305 | return ret; | 1226 | return ret; |
@@ -1322,41 +1243,104 @@ static void | |||
1322 | vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, | 1243 | vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, |
1323 | struct drm_plane_state *old_state) | 1244 | struct drm_plane_state *old_state) |
1324 | { | 1245 | { |
1325 | struct vmw_private *dev_priv; | ||
1326 | struct vmw_screen_target_display_unit *stdu; | ||
1327 | struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state); | 1246 | struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state); |
1328 | struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc; | 1247 | struct drm_crtc *crtc = plane->state->crtc; |
1248 | struct vmw_screen_target_display_unit *stdu; | ||
1249 | struct drm_pending_vblank_event *event; | ||
1250 | struct vmw_private *dev_priv; | ||
1329 | int ret; | 1251 | int ret; |
1330 | 1252 | ||
1331 | stdu = vmw_crtc_to_stdu(crtc); | 1253 | /* |
1332 | dev_priv = vmw_priv(crtc->dev); | 1254 | * We cannot really fail this function, so if we do, then output an |
1255 | * error and maintain consistent atomic state. | ||
1256 | */ | ||
1257 | if (crtc && plane->state->fb) { | ||
1258 | struct vmw_framebuffer *vfb = | ||
1259 | vmw_framebuffer_to_vfb(plane->state->fb); | ||
1260 | struct drm_vmw_rect vclips; | ||
1261 | stdu = vmw_crtc_to_stdu(crtc); | ||
1262 | dev_priv = vmw_priv(crtc->dev); | ||
1263 | |||
1264 | stdu->display_srf = vps->surf; | ||
1265 | stdu->content_fb_type = vps->content_fb_type; | ||
1266 | stdu->cpp = vps->cpp; | ||
1267 | |||
1268 | vclips.x = crtc->x; | ||
1269 | vclips.y = crtc->y; | ||
1270 | vclips.w = crtc->mode.hdisplay; | ||
1271 | vclips.h = crtc->mode.vdisplay; | ||
1272 | |||
1273 | ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); | ||
1274 | if (ret) | ||
1275 | DRM_ERROR("Failed to bind surface to STDU.\n"); | ||
1276 | |||
1277 | if (vfb->dmabuf) | ||
1278 | ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, | ||
1279 | &vclips, 1, 1, true, false, | ||
1280 | crtc); | ||
1281 | else | ||
1282 | ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, | ||
1283 | &vclips, NULL, 0, 0, | ||
1284 | 1, 1, NULL, crtc); | ||
1285 | if (ret) | ||
1286 | DRM_ERROR("Failed to update STDU.\n"); | ||
1333 | 1287 | ||
1334 | stdu->display_srf = vps->surf; | 1288 | crtc->primary->fb = plane->state->fb; |
1335 | stdu->content_fb_type = vps->content_fb_type; | 1289 | } else { |
1336 | stdu->cpp = vps->cpp; | 1290 | crtc = old_state->crtc; |
1337 | memcpy(&stdu->host_map, &vps->host_map, sizeof(vps->host_map)); | 1291 | stdu = vmw_crtc_to_stdu(crtc); |
1292 | dev_priv = vmw_priv(crtc->dev); | ||
1338 | 1293 | ||
1339 | if (!stdu->defined) | 1294 | /* |
1340 | return; | 1295 | * When disabling a plane, CRTC and FB should always be NULL |
1296 | * together, otherwise it's an error. | ||
1297 | * Here primary plane is being disable so blank the screen | ||
1298 | * target display unit, if not already done. | ||
1299 | */ | ||
1300 | if (!stdu->defined) | ||
1301 | return; | ||
1341 | 1302 | ||
1342 | if (plane->state->fb) | ||
1343 | ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); | ||
1344 | else | ||
1345 | ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); | 1303 | ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); |
1304 | if (ret) | ||
1305 | DRM_ERROR("Failed to blank STDU\n"); | ||
1306 | |||
1307 | ret = vmw_stdu_update_st(dev_priv, stdu); | ||
1308 | if (ret) | ||
1309 | DRM_ERROR("Failed to update STDU.\n"); | ||
1310 | |||
1311 | return; | ||
1312 | } | ||
1346 | 1313 | ||
1314 | event = crtc->state->event; | ||
1347 | /* | 1315 | /* |
1348 | * We cannot really fail this function, so if we do, then output an | 1316 | * In case of failure and other cases, vblank event will be sent in |
1349 | * error and quit | 1317 | * vmw_du_crtc_atomic_flush. |
1350 | */ | 1318 | */ |
1351 | if (ret) | 1319 | if (event && (ret == 0)) { |
1352 | DRM_ERROR("Failed to bind surface to STDU.\n"); | 1320 | struct vmw_fence_obj *fence = NULL; |
1353 | else | 1321 | struct drm_file *file_priv = event->base.file_priv; |
1354 | crtc->primary->fb = plane->state->fb; | ||
1355 | 1322 | ||
1356 | ret = vmw_stdu_update_st(dev_priv, stdu); | 1323 | vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); |
1357 | 1324 | ||
1358 | if (ret) | 1325 | /* |
1359 | DRM_ERROR("Failed to update STDU.\n"); | 1326 | * If fence is NULL, then already sync. |
1327 | */ | ||
1328 | if (fence) { | ||
1329 | ret = vmw_event_fence_action_queue( | ||
1330 | file_priv, fence, &event->base, | ||
1331 | &event->event.vbl.tv_sec, | ||
1332 | &event->event.vbl.tv_usec, | ||
1333 | true); | ||
1334 | if (ret) | ||
1335 | DRM_ERROR("Failed to queue event on fence.\n"); | ||
1336 | else | ||
1337 | crtc->state->event = NULL; | ||
1338 | |||
1339 | vmw_fence_obj_unreference(&fence); | ||
1340 | } | ||
1341 | } else { | ||
1342 | (void) vmw_fifo_flush(dev_priv, false); | ||
1343 | } | ||
1360 | } | 1344 | } |
1361 | 1345 | ||
1362 | 1346 | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index db1bb166845e..b236c48bf265 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | |||
@@ -345,7 +345,6 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res) | |||
345 | dev_priv->used_memory_size -= res->backup_size; | 345 | dev_priv->used_memory_size -= res->backup_size; |
346 | mutex_unlock(&dev_priv->cmdbuf_mutex); | 346 | mutex_unlock(&dev_priv->cmdbuf_mutex); |
347 | } | 347 | } |
348 | vmw_fifo_resource_dec(dev_priv); | ||
349 | } | 348 | } |
350 | 349 | ||
351 | /** | 350 | /** |
@@ -407,6 +406,8 @@ static int vmw_legacy_srf_create(struct vmw_resource *res) | |||
407 | 406 | ||
408 | vmw_surface_define_encode(srf, cmd); | 407 | vmw_surface_define_encode(srf, cmd); |
409 | vmw_fifo_commit(dev_priv, submit_size); | 408 | vmw_fifo_commit(dev_priv, submit_size); |
409 | vmw_fifo_resource_inc(dev_priv); | ||
410 | |||
410 | /* | 411 | /* |
411 | * Surface memory usage accounting. | 412 | * Surface memory usage accounting. |
412 | */ | 413 | */ |
@@ -558,6 +559,7 @@ static int vmw_legacy_srf_destroy(struct vmw_resource *res) | |||
558 | */ | 559 | */ |
559 | 560 | ||
560 | vmw_resource_release_id(res); | 561 | vmw_resource_release_id(res); |
562 | vmw_fifo_resource_dec(dev_priv); | ||
561 | 563 | ||
562 | return 0; | 564 | return 0; |
563 | } | 565 | } |
@@ -579,15 +581,11 @@ static int vmw_surface_init(struct vmw_private *dev_priv, | |||
579 | struct vmw_resource *res = &srf->res; | 581 | struct vmw_resource *res = &srf->res; |
580 | 582 | ||
581 | BUG_ON(!res_free); | 583 | BUG_ON(!res_free); |
582 | if (!dev_priv->has_mob) | ||
583 | vmw_fifo_resource_inc(dev_priv); | ||
584 | ret = vmw_resource_init(dev_priv, res, true, res_free, | 584 | ret = vmw_resource_init(dev_priv, res, true, res_free, |
585 | (dev_priv->has_mob) ? &vmw_gb_surface_func : | 585 | (dev_priv->has_mob) ? &vmw_gb_surface_func : |
586 | &vmw_legacy_surface_func); | 586 | &vmw_legacy_surface_func); |
587 | 587 | ||
588 | if (unlikely(ret != 0)) { | 588 | if (unlikely(ret != 0)) { |
589 | if (!dev_priv->has_mob) | ||
590 | vmw_fifo_resource_dec(dev_priv); | ||
591 | res_free(res); | 589 | res_free(res); |
592 | return ret; | 590 | return ret; |
593 | } | 591 | } |
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h index 8e2fb1ac4e0c..c67977aa1a0e 100644 --- a/include/drm/ttm/ttm_bo_api.h +++ b/include/drm/ttm/ttm_bo_api.h | |||
@@ -709,6 +709,10 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo); | |||
709 | int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, | 709 | int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma, |
710 | struct ttm_bo_device *bdev); | 710 | struct ttm_bo_device *bdev); |
711 | 711 | ||
712 | void *ttm_kmap_atomic_prot(struct page *page, pgprot_t prot); | ||
713 | |||
714 | void ttm_kunmap_atomic_prot(void *addr, pgprot_t prot); | ||
715 | |||
712 | /** | 716 | /** |
713 | * ttm_bo_io | 717 | * ttm_bo_io |
714 | * | 718 | * |