Rev 5078 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5078 | Rev 6296 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /************************************************************************** |
1 | /************************************************************************** |
2 | * |
2 | * |
3 | * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA |
3 | * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA |
4 | * All Rights Reserved. |
4 | * All Rights Reserved. |
5 | * |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the |
7 | * copy of this software and associated documentation files (the |
8 | * "Software"), to deal in the Software without restriction, including |
8 | * "Software"), to deal in the Software without restriction, including |
Line 29... | Line 29... | ||
29 | 29 | ||
30 | 30 | ||
Line 31... | Line -... | ||
31 | /* Might need a hrtimer here? */ |
- | |
32 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) |
- | |
33 | - | ||
34 | - | ||
35 | struct vmw_clip_rect { |
- | |
36 | int x1, x2, y1, y2; |
- | |
37 | }; |
- | |
38 | - | ||
39 | /** |
- | |
40 | * Clip @num_rects number of @rects against @clip storing the |
- | |
41 | * results in @out_rects and the number of passed rects in @out_num. |
- | |
42 | */ |
- | |
43 | static void vmw_clip_cliprects(struct drm_clip_rect *rects, |
- | |
44 | int num_rects, |
- | |
45 | struct vmw_clip_rect clip, |
- | |
46 | SVGASignedRect *out_rects, |
- | |
47 | int *out_num) |
- | |
48 | { |
- | |
49 | int i, k; |
- | |
50 | - | ||
51 | for (i = 0, k = 0; i < num_rects; i++) { |
- | |
52 | int x1 = max_t(int, clip.x1, rects[i].x1); |
- | |
53 | int y1 = max_t(int, clip.y1, rects[i].y1); |
- | |
54 | int x2 = min_t(int, clip.x2, rects[i].x2); |
- | |
55 | int y2 = min_t(int, clip.y2, rects[i].y2); |
- | |
56 | - | ||
57 | if (x1 >= x2) |
- | |
58 | continue; |
- | |
59 | if (y1 >= y2) |
- | |
60 | continue; |
- | |
61 | - | ||
62 | out_rects[k].left = x1; |
- | |
63 | out_rects[k].top = y1; |
- | |
64 | out_rects[k].right = x2; |
- | |
65 | out_rects[k].bottom = y2; |
- | |
66 | k++; |
- | |
67 | } |
- | |
68 | - | ||
69 | *out_num = k; |
31 | /* Might need a hrtimer here? */ |
70 | } |
32 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) |
71 | 33 | ||
72 | void vmw_display_unit_cleanup(struct vmw_display_unit *du) |
34 | void vmw_du_cleanup(struct vmw_display_unit *du) |
73 | { |
35 | { |
74 | // if (du->cursor_surface) |
36 | // if (du->cursor_surface) |
- | 37 | // vmw_surface_unreference(&du->cursor_surface); |
|
75 | // vmw_surface_unreference(&du->cursor_surface); |
38 | // if (du->cursor_dmabuf) |
76 | // if (du->cursor_dmabuf) |
39 | // vmw_dmabuf_unreference(&du->cursor_dmabuf); |
77 | // vmw_dmabuf_unreference(&du->cursor_dmabuf); |
40 | drm_connector_unregister(&du->connector); |
78 | drm_crtc_cleanup(&du->crtc); |
41 | drm_crtc_cleanup(&du->crtc); |
Line 118... | Line 81... | ||
118 | *dst++ = 0; |
81 | *dst++ = 0; |
119 | } |
82 | } |
120 | for(i = 0; i < 64*(64-32); i++) |
83 | for(i = 0; i < 64*(64-32); i++) |
121 | *dst++ = 0; |
84 | *dst++ = 0; |
Line 122... | Line 85... | ||
122 | 85 | ||
123 | cmd->cmd = cpu_to_le32(SVGA_CMD_DEFINE_ALPHA_CURSOR); |
86 | cmd->cmd = SVGA_CMD_DEFINE_ALPHA_CURSOR; |
124 | cmd->cursor.id = cpu_to_le32(0); |
87 | cmd->cursor.id = 0; |
125 | cmd->cursor.width = cpu_to_le32(width); |
88 | cmd->cursor.width = width; |
126 | cmd->cursor.height = cpu_to_le32(height); |
89 | cmd->cursor.height = height; |
127 | cmd->cursor.hotspotX = cpu_to_le32(hotspotX); |
90 | cmd->cursor.hotspotX = hotspotX; |
Line 128... | Line 91... | ||
128 | cmd->cursor.hotspotY = cpu_to_le32(hotspotY); |
91 | cmd->cursor.hotspotY = hotspotY; |
Line 129... | Line 92... | ||
129 | 92 | ||
130 | vmw_fifo_commit(dev_priv, cmd_size); |
93 | vmw_fifo_commit_flush(dev_priv, cmd_size); |
Line 131... | Line 94... | ||
131 | 94 | ||
Line 171... | Line 134... | ||
171 | #endif |
134 | #endif |
Line 172... | Line 135... | ||
172 | 135 | ||
173 | void vmw_cursor_update_position(struct vmw_private *dev_priv, |
136 | void vmw_cursor_update_position(struct vmw_private *dev_priv, |
174 | bool show, int x, int y) |
137 | bool show, int x, int y) |
175 | { |
138 | { |
176 | __le32 __iomem *fifo_mem = dev_priv->mmio_virt; |
139 | u32 *fifo_mem = dev_priv->mmio_virt; |
Line 177... | Line 140... | ||
177 | uint32_t count; |
140 | uint32_t count; |
178 | 141 | ||
179 | iowrite32(show ? 1 : 0, fifo_mem + SVGA_FIFO_CURSOR_ON); |
142 | vmw_mmio_write(show ? 1 : 0, fifo_mem + SVGA_FIFO_CURSOR_ON); |
180 | iowrite32(x, fifo_mem + SVGA_FIFO_CURSOR_X); |
143 | vmw_mmio_write(x, fifo_mem + SVGA_FIFO_CURSOR_X); |
181 | iowrite32(y, fifo_mem + SVGA_FIFO_CURSOR_Y); |
144 | vmw_mmio_write(y, fifo_mem + SVGA_FIFO_CURSOR_Y); |
182 | count = ioread32(fifo_mem + SVGA_FIFO_CURSOR_COUNT); |
145 | count = vmw_mmio_read(fifo_mem + SVGA_FIFO_CURSOR_COUNT); |
Line 183... | Line 146... | ||
183 | iowrite32(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT); |
146 | vmw_mmio_write(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT); |
- | 147 | } |
|
- | 148 | ||
- | 149 | #if 0 |
|
184 | } |
150 | /* |
185 | 151 | * vmw_du_crtc_cursor_set2 - Driver cursor_set2 callback. |
|
- | 152 | */ |
|
186 | #if 0 |
153 | int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, |
187 | int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, |
154 | uint32_t handle, uint32_t width, uint32_t height, |
188 | uint32_t handle, uint32_t width, uint32_t height) |
155 | int32_t hot_x, int32_t hot_y) |
189 | { |
156 | { |
190 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
157 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
- | 158 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
|
191 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
159 | struct vmw_surface *surface = NULL; |
Line 192... | Line 160... | ||
192 | struct vmw_surface *surface = NULL; |
160 | struct vmw_dma_buffer *dmabuf = NULL; |
193 | struct vmw_dma_buffer *dmabuf = NULL; |
161 | s32 hotspot_x, hotspot_y; |
194 | int ret; |
162 | int ret; |
195 | 163 | ||
196 | /* |
164 | /* |
197 | * FIXME: Unclear whether there's any global state touched by the |
165 | * FIXME: Unclear whether there's any global state touched by the |
198 | * cursor_set function, especially vmw_cursor_update_position looks |
166 | * cursor_set function, especially vmw_cursor_update_position looks |
199 | * suspicious. For now take the easy route and reacquire all locks. We |
167 | * suspicious. For now take the easy route and reacquire all locks. We |
200 | * can do this since the caller in the drm core doesn't check anything |
168 | * can do this since the caller in the drm core doesn't check anything |
- | 169 | * which is protected by any looks. |
|
- | 170 | */ |
|
Line 201... | Line 171... | ||
201 | * which is protected by any looks. |
171 | drm_modeset_unlock_crtc(crtc); |
202 | */ |
172 | drm_modeset_lock_all(dev_priv->dev); |
203 | drm_modeset_unlock(&crtc->mutex); |
173 | hotspot_x = hot_x + du->hotspot_x; |
204 | drm_modeset_lock_all(dev_priv->dev); |
174 | hotspot_y = hot_y + du->hotspot_y; |
Line 236... | Line 206... | ||
236 | } |
206 | } |
237 | if (du->cursor_dmabuf) |
207 | if (du->cursor_dmabuf) |
238 | vmw_dmabuf_unreference(&du->cursor_dmabuf); |
208 | vmw_dmabuf_unreference(&du->cursor_dmabuf); |
Line 239... | Line 209... | ||
239 | 209 | ||
- | 210 | /* setup new image */ |
|
240 | /* setup new image */ |
211 | ret = 0; |
241 | if (surface) { |
212 | if (surface) { |
242 | /* vmw_user_surface_lookup takes one reference */ |
213 | /* vmw_user_surface_lookup takes one reference */ |
Line 243... | Line 214... | ||
243 | du->cursor_surface = surface; |
214 | du->cursor_surface = surface; |
244 | 215 | ||
245 | du->cursor_surface->snooper.crtc = crtc; |
216 | du->cursor_surface->snooper.crtc = crtc; |
246 | du->cursor_age = du->cursor_surface->snooper.age; |
217 | du->cursor_age = du->cursor_surface->snooper.age; |
247 | vmw_cursor_update_image(dev_priv, surface->snooper.image, |
218 | ret = vmw_cursor_update_image(dev_priv, surface->snooper.image, |
248 | 64, 64, du->hotspot_x, du->hotspot_y); |
219 | 64, 64, hotspot_x, hotspot_y); |
249 | } else if (dmabuf) { |
220 | } else if (dmabuf) { |
Line 250... | Line 221... | ||
250 | /* vmw_user_surface_lookup takes one reference */ |
221 | /* vmw_user_surface_lookup takes one reference */ |
251 | du->cursor_dmabuf = dmabuf; |
222 | du->cursor_dmabuf = dmabuf; |
252 | 223 | ||
253 | ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height, |
224 | ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height, |
254 | du->hotspot_x, du->hotspot_y); |
- | |
255 | } else { |
225 | hotspot_x, hotspot_y); |
256 | vmw_cursor_update_position(dev_priv, false, 0, 0); |
226 | } else { |
Line -... | Line 227... | ||
- | 227 | vmw_cursor_update_position(dev_priv, false, 0, 0); |
|
257 | ret = 0; |
228 | goto out; |
258 | goto out; |
229 | } |
259 | } |
230 | |
- | 231 | if (!ret) { |
|
- | 232 | vmw_cursor_update_position(dev_priv, true, |
|
- | 233 | du->cursor_x + hotspot_x, |
|
Line 260... | Line -... | ||
260 | - | ||
261 | vmw_cursor_update_position(dev_priv, true, |
234 | du->cursor_y + hotspot_y); |
262 | du->cursor_x + du->hotspot_x, |
235 | du->core_hotspot_x = hot_x; |
263 | du->cursor_y + du->hotspot_y); |
236 | du->core_hotspot_y = hot_y; |
Line 264... | Line 237... | ||
264 | 237 | } |
|
265 | ret = 0; |
238 | |
Line 266... | Line 239... | ||
266 | out: |
239 | out: |
Line 284... | Line 257... | ||
284 | * cursor_set function, especially vmw_cursor_update_position looks |
257 | * cursor_set function, especially vmw_cursor_update_position looks |
285 | * suspicious. For now take the easy route and reacquire all locks. We |
258 | * suspicious. For now take the easy route and reacquire all locks. We |
286 | * can do this since the caller in the drm core doesn't check anything |
259 | * can do this since the caller in the drm core doesn't check anything |
287 | * which is protected by any looks. |
260 | * which is protected by any looks. |
288 | */ |
261 | */ |
289 | drm_modeset_unlock(&crtc->mutex); |
262 | drm_modeset_unlock_crtc(crtc); |
290 | drm_modeset_lock_all(dev_priv->dev); |
263 | drm_modeset_lock_all(dev_priv->dev); |
Line 291... | Line 264... | ||
291 | 264 | ||
292 | vmw_cursor_update_position(dev_priv, shown, |
265 | vmw_cursor_update_position(dev_priv, shown, |
- | 266 | du->cursor_x + du->hotspot_x + |
|
293 | du->cursor_x + du->hotspot_x, |
267 | du->core_hotspot_x, |
- | 268 | du->cursor_y + du->hotspot_y + |
|
Line 294... | Line 269... | ||
294 | du->cursor_y + du->hotspot_y); |
269 | du->core_hotspot_y); |
295 | 270 | ||
Line 296... | Line 271... | ||
296 | drm_modeset_unlock_all(dev_priv->dev); |
271 | drm_modeset_unlock_all(dev_priv->dev); |
297 | drm_modeset_lock(&crtc->mutex, NULL); |
272 | drm_modeset_lock_crtc(crtc, crtc->cursor); |
Line 298... | Line 273... | ||
298 | 273 | ||
Line 378... | Line 353... | ||
378 | box->w * 4); |
353 | box->w * 4); |
379 | } |
354 | } |
Line 380... | Line 355... | ||
380 | 355 | ||
Line 381... | Line -... | ||
381 | srf->snooper.age++; |
- | |
382 | - | ||
383 | /* we can't call this function from this function since execbuf has |
- | |
384 | * reserved fifo space. |
- | |
385 | * |
- | |
386 | * if (srf->snooper.crtc) |
- | |
387 | * vmw_ldu_crtc_cursor_update_image(dev_priv, |
- | |
388 | * srf->snooper.image, 64, 64, |
- | |
389 | * du->hotspot_x, du->hotspot_y); |
- | |
390 | */ |
356 | srf->snooper.age++; |
391 | 357 | ||
392 | ttm_bo_kunmap(&map); |
358 | ttm_bo_kunmap(&map); |
393 | err_unreserve: |
359 | err_unreserve: |
Line -... | Line 360... | ||
- | 360 | ttm_bo_unreserve(bo); |
|
- | 361 | } |
|
- | 362 | ||
- | 363 | /** |
|
- | 364 | * vmw_kms_legacy_hotspot_clear - Clear legacy hotspots |
|
- | 365 | * |
|
- | 366 | * @dev_priv: Pointer to the device private struct. |
|
- | 367 | * |
|
- | 368 | * Clears all legacy hotspots. |
|
- | 369 | */ |
|
- | 370 | void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv) |
|
- | 371 | { |
|
- | 372 | struct drm_device *dev = dev_priv->dev; |
|
- | 373 | struct vmw_display_unit *du; |
|
- | 374 | struct drm_crtc *crtc; |
|
- | 375 | ||
- | 376 | drm_modeset_lock_all(dev); |
|
- | 377 | drm_for_each_crtc(crtc, dev) { |
|
- | 378 | du = vmw_crtc_to_du(crtc); |
|
- | 379 | ||
- | 380 | du->hotspot_x = 0; |
|
- | 381 | du->hotspot_y = 0; |
|
- | 382 | } |
|
394 | ttm_bo_unreserve(bo); |
383 | drm_modeset_unlock_all(dev); |
395 | } |
384 | } |
396 | 385 | ||
397 | void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) |
386 | void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) |
398 | { |
387 | { |
Line 409... | Line 398... | ||
409 | continue; |
398 | continue; |
Line 410... | Line 399... | ||
410 | 399 | ||
411 | du->cursor_age = du->cursor_surface->snooper.age; |
400 | du->cursor_age = du->cursor_surface->snooper.age; |
412 | vmw_cursor_update_image(dev_priv, |
401 | vmw_cursor_update_image(dev_priv, |
- | 402 | du->cursor_surface->snooper.image, |
|
- | 403 | 64, 64, |
|
413 | du->cursor_surface->snooper.image, |
404 | du->hotspot_x + du->core_hotspot_x, |
414 | 64, 64, du->hotspot_x, du->hotspot_y); |
405 | du->hotspot_y + du->core_hotspot_y); |
Line 415... | Line 406... | ||
415 | } |
406 | } |
416 | 407 | ||
417 | mutex_unlock(&dev->mode_config.mutex); |
408 | mutex_unlock(&dev->mode_config.mutex); |
Line 424... | Line 415... | ||
424 | 415 | ||
425 | /* |
416 | /* |
426 | * Surface framebuffer code |
417 | * Surface framebuffer code |
Line 427... | Line -... | ||
427 | */ |
- | |
428 | - | ||
429 | #define vmw_framebuffer_to_vfbs(x) \ |
- | |
430 | container_of(x, struct vmw_framebuffer_surface, base.base) |
- | |
431 | - | ||
432 | struct vmw_framebuffer_surface { |
- | |
433 | struct vmw_framebuffer base; |
- | |
434 | struct vmw_surface *surface; |
- | |
435 | struct vmw_dma_buffer *buffer; |
- | |
436 | struct list_head head; |
- | |
437 | struct drm_master *master; |
- | |
438 | }; |
418 | */ |
439 | 419 | ||
440 | static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) |
420 | static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) |
441 | { |
421 | { |
442 | struct vmw_framebuffer_surface *vfbs = |
- | |
443 | vmw_framebuffer_to_vfbs(framebuffer); |
- | |
444 | struct vmw_master *vmaster = vmw_master(vfbs->master); |
- | |
445 | - | ||
446 | - | ||
447 | mutex_lock(&vmaster->fb_surf_mutex); |
- | |
Line -... | Line 422... | ||
- | 422 | struct vmw_framebuffer_surface *vfbs = |
|
- | 423 | vmw_framebuffer_to_vfbs(framebuffer); |
|
- | 424 | ||
- | 425 | drm_framebuffer_cleanup(framebuffer); |
|
Line 448... | Line 426... | ||
448 | list_del(&vfbs->head); |
426 | vmw_surface_unreference(&vfbs->surface); |
449 | mutex_unlock(&vmaster->fb_surf_mutex); |
427 | if (vfbs->base.user_obj) |
Line 450... | Line -... | ||
450 | - | ||
451 | - | ||
452 | kfree(vfbs); |
- | |
453 | } |
- | |
454 | - | ||
455 | static int do_surface_dirty_sou(struct vmw_private *dev_priv, |
- | |
456 | struct drm_file *file_priv, |
- | |
457 | struct vmw_framebuffer *framebuffer, |
- | |
458 | unsigned flags, unsigned color, |
- | |
459 | struct drm_clip_rect *clips, |
- | |
460 | unsigned num_clips, int inc, |
- | |
461 | struct vmw_fence_obj **out_fence) |
- | |
462 | { |
- | |
463 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
- | |
464 | struct drm_clip_rect *clips_ptr; |
- | |
465 | struct drm_clip_rect *tmp; |
- | |
466 | struct drm_crtc *crtc; |
- | |
467 | size_t fifo_size; |
- | |
468 | int i, num_units; |
- | |
469 | int ret = 0; /* silence warning */ |
- | |
470 | int left, right, top, bottom; |
- | |
471 | - | ||
472 | struct { |
- | |
473 | SVGA3dCmdHeader header; |
- | |
474 | SVGA3dCmdBlitSurfaceToScreen body; |
- | |
475 | } *cmd; |
- | |
476 | SVGASignedRect *blits; |
- | |
477 | - | ||
478 | num_units = 0; |
- | |
479 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, |
- | |
480 | head) { |
- | |
481 | if (crtc->primary->fb != &framebuffer->base) |
- | |
482 | continue; |
- | |
483 | units[num_units++] = vmw_crtc_to_du(crtc); |
- | |
484 | } |
- | |
485 | - | ||
486 | BUG_ON(!clips || !num_clips); |
- | |
487 | - | ||
488 | tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); |
- | |
489 | if (unlikely(tmp == NULL)) { |
- | |
490 | DRM_ERROR("Temporary cliprect memory alloc failed.\n"); |
- | |
491 | return -ENOMEM; |
- | |
492 | } |
- | |
493 | - | ||
494 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; |
- | |
495 | cmd = kzalloc(fifo_size, GFP_KERNEL); |
- | |
496 | if (unlikely(cmd == NULL)) { |
- | |
497 | DRM_ERROR("Temporary fifo memory alloc failed.\n"); |
- | |
498 | ret = -ENOMEM; |
- | |
499 | goto out_free_tmp; |
- | |
500 | } |
- | |
501 | - | ||
502 | /* setup blits pointer */ |
- | |
503 | blits = (SVGASignedRect *)&cmd[1]; |
- | |
504 | - | ||
505 | /* initial clip region */ |
- | |
506 | left = clips->x1; |
- | |
507 | right = clips->x2; |
- | |
508 | top = clips->y1; |
- | |
509 | bottom = clips->y2; |
- | |
510 | - | ||
511 | /* skip the first clip rect */ |
- | |
512 | for (i = 1, clips_ptr = clips + inc; |
- | |
513 | i < num_clips; i++, clips_ptr += inc) { |
- | |
514 | left = min_t(int, left, (int)clips_ptr->x1); |
- | |
515 | right = max_t(int, right, (int)clips_ptr->x2); |
- | |
516 | top = min_t(int, top, (int)clips_ptr->y1); |
- | |
517 | bottom = max_t(int, bottom, (int)clips_ptr->y2); |
- | |
518 | } |
- | |
519 | - | ||
520 | /* only need to do this once */ |
- | |
521 | cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); |
- | |
522 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); |
- | |
523 | - | ||
524 | cmd->body.srcRect.left = left; |
- | |
525 | cmd->body.srcRect.right = right; |
- | |
526 | cmd->body.srcRect.top = top; |
- | |
527 | cmd->body.srcRect.bottom = bottom; |
- | |
528 | - | ||
529 | clips_ptr = clips; |
- | |
530 | for (i = 0; i < num_clips; i++, clips_ptr += inc) { |
- | |
531 | tmp[i].x1 = clips_ptr->x1 - left; |
- | |
532 | tmp[i].x2 = clips_ptr->x2 - left; |
- | |
533 | tmp[i].y1 = clips_ptr->y1 - top; |
- | |
534 | tmp[i].y2 = clips_ptr->y2 - top; |
- | |
535 | } |
- | |
536 | - | ||
537 | /* do per unit writing, reuse fifo for each */ |
- | |
538 | for (i = 0; i < num_units; i++) { |
- | |
539 | struct vmw_display_unit *unit = units[i]; |
- | |
540 | struct vmw_clip_rect clip; |
- | |
541 | int num; |
- | |
542 | - | ||
543 | clip.x1 = left - unit->crtc.x; |
- | |
544 | clip.y1 = top - unit->crtc.y; |
- | |
545 | clip.x2 = right - unit->crtc.x; |
- | |
546 | clip.y2 = bottom - unit->crtc.y; |
- | |
547 | - | ||
548 | /* skip any crtcs that misses the clip region */ |
- | |
549 | if (clip.x1 >= unit->crtc.mode.hdisplay || |
- | |
550 | clip.y1 >= unit->crtc.mode.vdisplay || |
- | |
551 | clip.x2 <= 0 || clip.y2 <= 0) |
- | |
552 | continue; |
- | |
553 | - | ||
554 | /* |
- | |
555 | * In order for the clip rects to be correctly scaled |
- | |
556 | * the src and dest rects needs to be the same size. |
- | |
557 | */ |
- | |
558 | cmd->body.destRect.left = clip.x1; |
- | |
559 | cmd->body.destRect.right = clip.x2; |
- | |
560 | cmd->body.destRect.top = clip.y1; |
- | |
561 | cmd->body.destRect.bottom = clip.y2; |
- | |
562 | - | ||
563 | /* create a clip rect of the crtc in dest coords */ |
- | |
564 | clip.x2 = unit->crtc.mode.hdisplay - clip.x1; |
- | |
565 | clip.y2 = unit->crtc.mode.vdisplay - clip.y1; |
- | |
566 | clip.x1 = 0 - clip.x1; |
- | |
567 | clip.y1 = 0 - clip.y1; |
- | |
568 | - | ||
569 | /* need to reset sid as it is changed by execbuf */ |
- | |
570 | cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); |
- | |
571 | cmd->body.destScreenId = unit->unit; |
- | |
572 | - | ||
573 | /* clip and write blits to cmd stream */ |
- | |
574 | vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); |
- | |
575 | - | ||
576 | /* if no cliprects hit skip this */ |
- | |
577 | if (num == 0) |
- | |
578 | continue; |
- | |
579 | - | ||
580 | /* only return the last fence */ |
- | |
581 | if (out_fence && *out_fence) |
- | |
582 | vmw_fence_obj_unreference(out_fence); |
- | |
583 | - | ||
584 | /* recalculate package length */ |
- | |
585 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; |
- | |
586 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); |
- | |
587 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, |
- | |
588 | fifo_size, 0, NULL, out_fence); |
- | |
589 | - | ||
590 | if (unlikely(ret != 0)) |
- | |
591 | break; |
- | |
592 | } |
- | |
593 | - | ||
594 | - | ||
595 | kfree(cmd); |
- | |
596 | out_free_tmp: |
- | |
597 | kfree(tmp); |
428 | ttm_base_object_unref(&vfbs->base.user_obj); |
598 | 429 | ||
599 | return ret; |
430 | kfree(vfbs); |
600 | } |
431 | } |
601 | 432 | ||
Line 609... | Line 440... | ||
609 | struct vmw_framebuffer_surface *vfbs = |
440 | struct vmw_framebuffer_surface *vfbs = |
610 | vmw_framebuffer_to_vfbs(framebuffer); |
441 | vmw_framebuffer_to_vfbs(framebuffer); |
611 | struct drm_clip_rect norect; |
442 | struct drm_clip_rect norect; |
612 | int ret, inc = 1; |
443 | int ret, inc = 1; |
Line 613... | Line -... | ||
613 | - | ||
614 | if (unlikely(vfbs->master != file_priv->master)) |
- | |
615 | return -EINVAL; |
- | |
616 | 444 | ||
617 | /* Require ScreenObject support for 3D */ |
445 | /* Legacy Display Unit does not support 3D */ |
618 | if (!dev_priv->sou_priv) |
446 | if (dev_priv->active_display_unit == vmw_du_legacy) |
Line 619... | Line 447... | ||
619 | return -EINVAL; |
447 | return -EINVAL; |
Line 620... | Line 448... | ||
620 | 448 | ||
Line 635... | Line 463... | ||
635 | } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { |
463 | } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { |
636 | num_clips /= 2; |
464 | num_clips /= 2; |
637 | inc = 2; /* skip source rects */ |
465 | inc = 2; /* skip source rects */ |
638 | } |
466 | } |
Line -... | Line 467... | ||
- | 467 | ||
639 | 468 | if (dev_priv->active_display_unit == vmw_du_screen_object) |
|
- | 469 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, |
|
640 | ret = do_surface_dirty_sou(dev_priv, file_priv, &vfbs->base, |
470 | clips, NULL, NULL, 0, 0, |
- | 471 | num_clips, inc, NULL); |
|
- | 472 | else |
|
- | 473 | ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, |
|
641 | flags, color, |
474 | clips, NULL, NULL, 0, 0, |
Line -... | Line 475... | ||
- | 475 | num_clips, inc, NULL); |
|
642 | clips, num_clips, inc, NULL); |
476 | |
Line 643... | Line 477... | ||
643 | 477 | vmw_fifo_flush(dev_priv, false); |
|
Line 644... | Line 478... | ||
644 | ttm_read_unlock(&dev_priv->reservation_sem); |
478 | ttm_read_unlock(&dev_priv->reservation_sem); |
645 | 479 | ||
Line -... | Line 480... | ||
- | 480 | drm_modeset_unlock_all(dev_priv->dev); |
|
- | 481 | ||
- | 482 | return 0; |
|
- | 483 | } |
|
- | 484 | ||
- | 485 | /** |
|
- | 486 | * vmw_kms_readback - Perform a readback from the screen system to |
|
- | 487 | * a dma-buffer backed framebuffer. |
|
- | 488 | * |
|
- | 489 | * @dev_priv: Pointer to the device private structure. |
|
- | 490 | * @file_priv: Pointer to a struct drm_file identifying the caller. |
|
- | 491 | * Must be set to NULL if @user_fence_rep is NULL. |
|
- | 492 | * @vfb: Pointer to the dma-buffer backed framebuffer. |
|
- | 493 | * @user_fence_rep: User-space provided structure for fence information. |
|
- | 494 | * Must be set to non-NULL if @file_priv is non-NULL. |
|
- | 495 | * @vclips: Array of clip rects. |
|
- | 496 | * @num_clips: Number of clip rects in @vclips. |
|
- | 497 | * |
|
- | 498 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if |
|
- | 499 | * interrupted. |
|
- | 500 | */ |
|
- | 501 | int vmw_kms_readback(struct vmw_private *dev_priv, |
|
- | 502 | struct drm_file *file_priv, |
|
- | 503 | struct vmw_framebuffer *vfb, |
|
- | 504 | struct drm_vmw_fence_rep __user *user_fence_rep, |
|
- | 505 | struct drm_vmw_rect *vclips, |
|
- | 506 | uint32_t num_clips) |
|
- | 507 | { |
|
- | 508 | switch (dev_priv->active_display_unit) { |
|
- | 509 | case vmw_du_screen_object: |
|
- | 510 | return vmw_kms_sou_readback(dev_priv, file_priv, vfb, |
|
- | 511 | user_fence_rep, vclips, num_clips); |
|
- | 512 | case vmw_du_screen_target: |
|
- | 513 | return vmw_kms_stdu_dma(dev_priv, file_priv, vfb, |
|
- | 514 | user_fence_rep, NULL, vclips, num_clips, |
|
- | 515 | 1, false, true); |
|
- | 516 | default: |
|
- | 517 | WARN_ONCE(true, |
|
- | 518 | "Readback called with invalid display system.\n"); |
|
- | 519 | } |
|
646 | drm_modeset_unlock_all(dev_priv->dev); |
520 | |
647 | 521 | return -ENOSYS; |
|
648 | return 0; |
522 | } |
649 | } |
523 | |
Line 650... | Line 524... | ||
650 | 524 | ||
651 | static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { |
- | |
652 | .destroy = vmw_framebuffer_surface_destroy, |
525 | static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { |
653 | .dirty = vmw_framebuffer_surface_dirty, |
526 | .destroy = vmw_framebuffer_surface_destroy, |
654 | }; |
527 | .dirty = vmw_framebuffer_surface_dirty, |
655 | 528 | }; |
|
- | 529 | ||
Line 656... | Line 530... | ||
656 | static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, |
530 | static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, |
657 | struct drm_file *file_priv, |
531 | struct vmw_surface *surface, |
658 | struct vmw_surface *surface, |
532 | struct vmw_framebuffer **out, |
659 | struct vmw_framebuffer **out, |
533 | const struct drm_mode_fb_cmd |
660 | const struct drm_mode_fb_cmd |
- | |
661 | *mode_cmd) |
534 | *mode_cmd, |
Line 662... | Line 535... | ||
662 | 535 | bool is_dmabuf_proxy) |
|
663 | { |
536 | |
664 | struct drm_device *dev = dev_priv->dev; |
537 | { |
Line 665... | Line 538... | ||
665 | struct vmw_framebuffer_surface *vfbs; |
538 | struct drm_device *dev = dev_priv->dev; |
666 | enum SVGA3dSurfaceFormat format; |
539 | struct vmw_framebuffer_surface *vfbs; |
667 | struct vmw_master *vmaster = vmw_master(file_priv->master); |
540 | enum SVGA3dSurfaceFormat format; |
Line 700... | Line 573... | ||
700 | format = SVGA3D_R5G6B5; |
573 | format = SVGA3D_R5G6B5; |
701 | break; |
574 | break; |
702 | case 15: |
575 | case 15: |
703 | format = SVGA3D_A1R5G5B5; |
576 | format = SVGA3D_A1R5G5B5; |
704 | break; |
577 | break; |
705 | case 8: |
- | |
706 | format = SVGA3D_LUMINANCE8; |
- | |
707 | break; |
- | |
708 | default: |
578 | default: |
709 | DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth); |
579 | DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth); |
710 | return -EINVAL; |
580 | return -EINVAL; |
711 | } |
581 | } |
Line -... | Line 582... | ||
- | 582 | ||
- | 583 | /* |
|
- | 584 | * For DX, surface format validation is done when surface->scanout |
|
- | 585 | * is set. |
|
712 | 586 | */ |
|
713 | if (unlikely(format != surface->format)) { |
587 | if (!dev_priv->has_dx && format != surface->format) { |
714 | DRM_ERROR("Invalid surface format for requested mode.\n"); |
588 | DRM_ERROR("Invalid surface format for requested mode.\n"); |
715 | return -EINVAL; |
589 | return -EINVAL; |
Line 716... | Line 590... | ||
716 | } |
590 | } |
717 | 591 | ||
718 | vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL); |
592 | vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL); |
719 | if (!vfbs) { |
593 | if (!vfbs) { |
720 | ret = -ENOMEM; |
594 | ret = -ENOMEM; |
Line 721... | Line -... | ||
721 | goto out_err1; |
- | |
722 | } |
- | |
723 | - | ||
724 | if (!vmw_surface_reference(surface)) { |
- | |
725 | DRM_ERROR("failed to reference surface %p\n", surface); |
- | |
726 | ret = -EINVAL; |
- | |
727 | goto out_err2; |
595 | goto out_err1; |
728 | } |
596 | } |
729 | 597 | ||
730 | /* XXX get the first 3 from the surface info */ |
598 | /* XXX get the first 3 from the surface info */ |
731 | vfbs->base.base.bits_per_pixel = mode_cmd->bpp; |
599 | vfbs->base.base.bits_per_pixel = mode_cmd->bpp; |
732 | vfbs->base.base.pitches[0] = mode_cmd->pitch; |
600 | vfbs->base.base.pitches[0] = mode_cmd->pitch; |
733 | vfbs->base.base.depth = mode_cmd->depth; |
601 | vfbs->base.base.depth = mode_cmd->depth; |
734 | vfbs->base.base.width = mode_cmd->width; |
602 | vfbs->base.base.width = mode_cmd->width; |
735 | vfbs->base.base.height = mode_cmd->height; |
603 | vfbs->base.base.height = mode_cmd->height; |
736 | vfbs->surface = surface; |
- | |
737 | vfbs->base.user_handle = mode_cmd->handle; |
- | |
738 | // vfbs->master = drm_master_get(file_priv->master); |
- | |
739 | - | ||
Line 740... | Line 604... | ||
740 | mutex_lock(&vmaster->fb_surf_mutex); |
604 | vfbs->surface = vmw_surface_reference(surface); |
Line 741... | Line 605... | ||
741 | list_add_tail(&vfbs->head, &vmaster->fb_surf); |
605 | vfbs->base.user_handle = mode_cmd->handle; |
742 | mutex_unlock(&vmaster->fb_surf_mutex); |
606 | vfbs->is_dmabuf_proxy = is_dmabuf_proxy; |
743 | 607 | ||
744 | *out = &vfbs->base; |
608 | *out = &vfbs->base; |
Line 745... | Line 609... | ||
745 | 609 | ||
Line 746... | Line -... | ||
746 | ret = drm_framebuffer_init(dev, &vfbs->base.base, |
- | |
747 | &vmw_framebuffer_surface_funcs); |
- | |
748 | if (ret) |
610 | ret = drm_framebuffer_init(dev, &vfbs->base.base, |
- | 611 | &vmw_framebuffer_surface_funcs); |
|
749 | goto out_err3; |
612 | if (ret) |
750 | 613 | goto out_err2; |
|
751 | return 0; |
614 | |
752 | 615 | return 0; |
|
Line 753... | Line 616... | ||
753 | out_err3: |
616 | |
754 | vmw_surface_unreference(&surface); |
617 | out_err2: |
755 | out_err2: |
618 | vmw_surface_unreference(&surface); |
Line 756... | Line -... | ||
756 | kfree(vfbs); |
- | |
757 | out_err1: |
- | |
758 | return ret; |
- | |
759 | } |
- | |
760 | - | ||
761 | /* |
- | |
762 | * Dmabuf framebuffer code |
- | |
763 | */ |
- | |
764 | 619 | kfree(vfbs); |
|
765 | #define vmw_framebuffer_to_vfbd(x) \ |
620 | out_err1: |
766 | container_of(x, struct vmw_framebuffer_dmabuf, base.base) |
621 | return ret; |
767 | 622 | } |
|
Line 768... | Line 623... | ||
768 | struct vmw_framebuffer_dmabuf { |
623 | |
769 | struct vmw_framebuffer base; |
624 | /* |
- | 625 | * Dmabuf framebuffer code |
|
770 | struct vmw_dma_buffer *buffer; |
626 | */ |
Line 771... | Line 627... | ||
771 | }; |
627 | |
772 | 628 | static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) |
|
Line 773... | Line -... | ||
773 | static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) |
- | |
774 | { |
- | |
775 | struct vmw_framebuffer_dmabuf *vfbd = |
- | |
776 | vmw_framebuffer_to_vfbd(framebuffer); |
- | |
777 | - | ||
778 | // drm_framebuffer_cleanup(framebuffer); |
- | |
779 | // vmw_dmabuf_unreference(&vfbd->buffer); |
- | |
780 | // ttm_base_object_unref(&vfbd->base.user_obj); |
- | |
781 | - | ||
782 | kfree(vfbd); |
- | |
783 | } |
- | |
784 | - | ||
785 | static int do_dmabuf_dirty_ldu(struct vmw_private *dev_priv, |
- | |
786 | struct vmw_framebuffer *framebuffer, |
- | |
787 | unsigned flags, unsigned color, |
- | |
788 | struct drm_clip_rect *clips, |
- | |
789 | unsigned num_clips, int increment) |
- | |
790 | { |
- | |
791 | size_t fifo_size; |
- | |
792 | int i; |
- | |
793 | - | ||
794 | struct { |
- | |
795 | uint32_t header; |
- | |
796 | SVGAFifoCmdUpdate body; |
- | |
797 | } *cmd; |
- | |
798 | - | ||
799 | fifo_size = sizeof(*cmd) * num_clips; |
- | |
800 | cmd = vmw_fifo_reserve(dev_priv, fifo_size); |
- | |
801 | if (unlikely(cmd == NULL)) { |
- | |
802 | DRM_ERROR("Fifo reserve failed.\n"); |
- | |
803 | return -ENOMEM; |
- | |
804 | } |
- | |
805 | - | ||
806 | memset(cmd, 0, fifo_size); |
- | |
807 | for (i = 0; i < num_clips; i++, clips += increment) { |
- | |
808 | cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE); |
- | |
809 | cmd[i].body.x = cpu_to_le32(clips->x1); |
- | |
810 | cmd[i].body.y = cpu_to_le32(clips->y1); |
- | |
811 | cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1); |
- | |
812 | cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1); |
- | |
813 | } |
- | |
814 | - | ||
815 | vmw_fifo_commit(dev_priv, fifo_size); |
- | |
816 | return 0; |
- | |
817 | } |
- | |
818 | - | ||
819 | static int do_dmabuf_define_gmrfb(struct drm_file *file_priv, |
- | |
820 | struct vmw_private *dev_priv, |
- | |
821 | struct vmw_framebuffer *framebuffer) |
- | |
822 | { |
- | |
823 | int depth = framebuffer->base.depth; |
- | |
824 | size_t fifo_size; |
- | |
825 | int ret; |
- | |
826 | - | ||
827 | struct { |
- | |
828 | uint32_t header; |
- | |
829 | SVGAFifoCmdDefineGMRFB body; |
- | |
830 | } *cmd; |
- | |
831 | - | ||
832 | /* Emulate RGBA support, contrary to svga_reg.h this is not |
- | |
833 | * supported by hosts. This is only a problem if we are reading |
- | |
834 | * this value later and expecting what we uploaded back. |
- | |
835 | */ |
- | |
836 | if (depth == 32) |
- | |
837 | depth = 24; |
- | |
838 | - | ||
839 | fifo_size = sizeof(*cmd); |
- | |
840 | cmd = kmalloc(fifo_size, GFP_KERNEL); |
- | |
841 | if (unlikely(cmd == NULL)) { |
- | |
842 | DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); |
- | |
843 | return -ENOMEM; |
- | |
844 | } |
- | |
845 | - | ||
846 | memset(cmd, 0, fifo_size); |
- | |
847 | cmd->header = SVGA_CMD_DEFINE_GMRFB; |
- | |
848 | cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel; |
- | |
849 | cmd->body.format.colorDepth = depth; |
- | |
850 | cmd->body.format.reserved = 0; |
- | |
851 | cmd->body.bytesPerLine = framebuffer->base.pitches[0]; |
- | |
852 | cmd->body.ptr.gmrId = framebuffer->user_handle; |
- | |
853 | cmd->body.ptr.offset = 0; |
- | |
854 | - | ||
855 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, |
- | |
856 | fifo_size, 0, NULL, NULL); |
- | |
857 | - | ||
858 | kfree(cmd); |
- | |
859 | - | ||
860 | return ret; |
- | |
861 | } |
- | |
862 | - | ||
863 | static int do_dmabuf_dirty_sou(struct drm_file *file_priv, |
- | |
864 | struct vmw_private *dev_priv, |
- | |
865 | struct vmw_framebuffer *framebuffer, |
- | |
866 | unsigned flags, unsigned color, |
- | |
867 | struct drm_clip_rect *clips, |
- | |
868 | unsigned num_clips, int increment, |
- | |
869 | struct vmw_fence_obj **out_fence) |
- | |
870 | { |
- | |
871 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
- | |
872 | struct drm_clip_rect *clips_ptr; |
- | |
873 | int i, k, num_units, ret; |
- | |
874 | struct drm_crtc *crtc; |
- | |
875 | size_t fifo_size; |
- | |
876 | - | ||
877 | struct { |
- | |
878 | uint32_t header; |
- | |
879 | SVGAFifoCmdBlitGMRFBToScreen body; |
- | |
880 | } *blits; |
- | |
881 | - | ||
882 | ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer); |
- | |
883 | if (unlikely(ret != 0)) |
- | |
884 | return ret; /* define_gmrfb prints warnings */ |
- | |
885 | - | ||
886 | fifo_size = sizeof(*blits) * num_clips; |
- | |
887 | blits = kmalloc(fifo_size, GFP_KERNEL); |
- | |
888 | if (unlikely(blits == NULL)) { |
- | |
889 | DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); |
- | |
890 | return -ENOMEM; |
- | |
891 | } |
- | |
892 | - | ||
893 | num_units = 0; |
- | |
894 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { |
- | |
895 | if (crtc->primary->fb != &framebuffer->base) |
- | |
896 | continue; |
- | |
897 | units[num_units++] = vmw_crtc_to_du(crtc); |
- | |
898 | } |
- | |
899 | - | ||
900 | for (k = 0; k < num_units; k++) { |
- | |
901 | struct vmw_display_unit *unit = units[k]; |
- | |
902 | int hit_num = 0; |
- | |
903 | - | ||
904 | clips_ptr = clips; |
- | |
905 | for (i = 0; i < num_clips; i++, clips_ptr += increment) { |
- | |
906 | int clip_x1 = clips_ptr->x1 - unit->crtc.x; |
- | |
907 | int clip_y1 = clips_ptr->y1 - unit->crtc.y; |
- | |
908 | int clip_x2 = clips_ptr->x2 - unit->crtc.x; |
- | |
909 | int clip_y2 = clips_ptr->y2 - unit->crtc.y; |
- | |
910 | int move_x, move_y; |
- | |
911 | - | ||
912 | /* skip any crtcs that misses the clip region */ |
- | |
913 | if (clip_x1 >= unit->crtc.mode.hdisplay || |
- | |
914 | clip_y1 >= unit->crtc.mode.vdisplay || |
- | |
915 | clip_x2 <= 0 || clip_y2 <= 0) |
- | |
916 | continue; |
- | |
917 | - | ||
918 | /* clip size to crtc size */ |
- | |
919 | clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay); |
- | |
920 | clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay); |
- | |
921 | - | ||
922 | /* translate both src and dest to bring clip into screen */ |
- | |
923 | move_x = min_t(int, clip_x1, 0); |
- | |
924 | move_y = min_t(int, clip_y1, 0); |
- | |
925 | - | ||
926 | /* actual translate done here */ |
- | |
927 | blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; |
- | |
928 | blits[hit_num].body.destScreenId = unit->unit; |
- | |
929 | blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x; |
- | |
930 | blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y; |
- | |
931 | blits[hit_num].body.destRect.left = clip_x1 - move_x; |
- | |
932 | blits[hit_num].body.destRect.top = clip_y1 - move_y; |
- | |
933 | blits[hit_num].body.destRect.right = clip_x2; |
- | |
934 | blits[hit_num].body.destRect.bottom = clip_y2; |
- | |
935 | hit_num++; |
- | |
936 | } |
- | |
937 | - | ||
938 | /* no clips hit the crtc */ |
- | |
939 | if (hit_num == 0) |
- | |
940 | continue; |
- | |
941 | - | ||
942 | /* only return the last fence */ |
- | |
943 | if (out_fence && *out_fence) |
- | |
944 | vmw_fence_obj_unreference(out_fence); |
- | |
945 | - | ||
946 | fifo_size = sizeof(*blits) * hit_num; |
- | |
947 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits, |
629 | { |
948 | fifo_size, 0, NULL, out_fence); |
630 | struct vmw_framebuffer_dmabuf *vfbd = |
949 | 631 | vmw_framebuffer_to_vfbd(framebuffer); |
|
950 | if (unlikely(ret != 0)) |
632 | |
951 | break; |
633 | drm_framebuffer_cleanup(framebuffer); |
Line 985... | Line 667... | ||
985 | } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { |
667 | } else if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY) { |
986 | num_clips /= 2; |
668 | num_clips /= 2; |
987 | increment = 2; |
669 | increment = 2; |
988 | } |
670 | } |
Line 989... | Line 671... | ||
989 | 671 | ||
- | 672 | switch (dev_priv->active_display_unit) { |
|
- | 673 | case vmw_du_screen_target: |
|
- | 674 | ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, |
|
- | 675 | clips, NULL, num_clips, increment, |
|
- | 676 | true, true); |
|
- | 677 | break; |
|
990 | if (dev_priv->ldu_priv) { |
678 | case vmw_du_screen_object: |
- | 679 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, |
|
991 | ret = do_dmabuf_dirty_ldu(dev_priv, &vfbd->base, |
680 | clips, num_clips, increment, |
- | 681 | true, |
|
- | 682 | NULL); |
|
- | 683 | break; |
|
- | 684 | case vmw_du_legacy: |
|
992 | flags, color, |
685 | ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, |
993 | clips, num_clips, increment); |
686 | clips, num_clips, increment); |
994 | } else { |
687 | break; |
995 | ret = do_dmabuf_dirty_sou(file_priv, dev_priv, &vfbd->base, |
688 | default: |
996 | flags, color, |
689 | ret = -EINVAL; |
- | 690 | WARN_ONCE(true, "Dirty called with invalid display system.\n"); |
|
997 | clips, num_clips, increment, NULL); |
691 | break; |
Line -... | Line 692... | ||
- | 692 | } |
|
998 | } |
693 | |
Line 999... | Line 694... | ||
999 | 694 | vmw_fifo_flush(dev_priv, false); |
|
Line 1000... | Line 695... | ||
1000 | ttm_read_unlock(&dev_priv->reservation_sem); |
695 | ttm_read_unlock(&dev_priv->reservation_sem); |
Line 1010... | Line 705... | ||
1010 | }; |
705 | }; |
Line 1011... | Line 706... | ||
1011 | 706 | ||
1012 | /** |
707 | /** |
1013 | * Pin the dmabuffer to the start of vram. |
708 | * Pin the dmabuffer to the start of vram. |
1014 | */ |
709 | */ |
1015 | static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) |
710 | static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) |
1016 | { |
711 | { |
1017 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); |
712 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); |
1018 | struct vmw_framebuffer_dmabuf *vfbd = |
- | |
1019 | vmw_framebuffer_to_vfbd(&vfb->base); |
713 | struct vmw_dma_buffer *buf; |
Line 1020... | Line 714... | ||
1020 | int ret; |
714 | int ret; |
1021 | 715 | ||
Line 1022... | Line 716... | ||
1022 | /* This code should not be used with screen objects */ |
716 | buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : |
1023 | BUG_ON(dev_priv->sou_priv); |
717 | vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; |
1024 | - | ||
Line -... | Line 718... | ||
- | 718 | ||
- | 719 | if (!buf) |
|
- | 720 | return 0; |
|
- | 721 | ||
1025 | // vmw_overlay_pause_all(dev_priv); |
722 | switch (dev_priv->active_display_unit) { |
- | 723 | case vmw_du_legacy: |
|
- | 724 | vmw_overlay_pause_all(dev_priv); |
|
- | 725 | ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, buf, false); |
|
- | 726 | vmw_overlay_resume_all(dev_priv); |
|
- | 727 | break; |
|
- | 728 | case vmw_du_screen_object: |
|
Line -... | Line 729... | ||
- | 729 | case vmw_du_screen_target: |
|
- | 730 | if (vfb->dmabuf) |
|
- | 731 | return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, |
|
1026 | 732 | false); |
|
- | 733 | ||
Line 1027... | Line 734... | ||
1027 | ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer, true, false); |
734 | return vmw_dmabuf_pin_in_placement(dev_priv, buf, |
1028 | 735 | &vmw_mob_placement, false); |
|
Line 1029... | Line 736... | ||
1029 | // vmw_overlay_resume_all(dev_priv); |
736 | default: |
1030 | 737 | return -EINVAL; |
|
1031 | WARN_ON(ret != 0); |
738 | } |
1032 | 739 | ||
1033 | return 0; |
- | |
Line -... | Line 740... | ||
- | 740 | return ret; |
|
1034 | } |
741 | } |
- | 742 | ||
1035 | 743 | static int vmw_framebuffer_unpin(struct vmw_framebuffer *vfb) |
|
1036 | static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb) |
744 | { |
- | 745 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); |
|
- | 746 | struct vmw_dma_buffer *buf; |
|
1037 | { |
747 | |
Line -... | Line 748... | ||
- | 748 | buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : |
|
- | 749 | vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; |
|
- | 750 | ||
- | 751 | if (WARN_ON(!buf)) |
|
- | 752 | return 0; |
|
- | 753 | ||
- | 754 | return vmw_dmabuf_unpin(dev_priv, buf, false); |
|
- | 755 | } |
|
- | 756 | ||
- | 757 | /** |
|
- | 758 | * vmw_create_dmabuf_proxy - create a proxy surface for the DMA buf |
|
- | 759 | * |
|
- | 760 | * @dev: DRM device |
|
- | 761 | * @mode_cmd: parameters for the new surface |
|
- | 762 | * @dmabuf_mob: MOB backing the DMA buf |
|
1038 | struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); |
763 | * @srf_out: newly created surface |
- | 764 | * |
|
- | 765 | * When the content FB is a DMA buf, we create a surface as a proxy to the |
|
- | 766 | * same buffer. This way we can do a surface copy rather than a surface DMA. |
|
- | 767 | * This is a more efficient approach |
|
- | 768 | * |
|
- | 769 | * RETURNS: |
|
- | 770 | * 0 on success, error code otherwise |
|
- | 771 | */ |
|
- | 772 | static int vmw_create_dmabuf_proxy(struct drm_device *dev, |
|
- | 773 | const struct drm_mode_fb_cmd *mode_cmd, |
|
- | 774 | struct vmw_dma_buffer *dmabuf_mob, |
|
- | 775 | struct vmw_surface **srf_out) |
|
- | 776 | { |
|
- | 777 | uint32_t format; |
|
- | 778 | struct drm_vmw_size content_base_size; |
|
- | 779 | struct vmw_resource *res; |
|
- | 780 | int ret; |
|
- | 781 | ||
- | 782 | switch (mode_cmd->depth) { |
|
- | 783 | case 32: |
|
- | 784 | case 24: |
|
- | 785 | format = SVGA3D_X8R8G8B8; |
|
- | 786 | break; |
|
- | 787 | ||
- | 788 | case 16: |
|
- | 789 | case 15: |
|
- | 790 | format = SVGA3D_R5G6B5; |
|
1039 | struct vmw_framebuffer_dmabuf *vfbd = |
791 | break; |
Line -... | Line 792... | ||
- | 792 | ||
- | 793 | case 8: |
|
- | 794 | format = SVGA3D_P8; |
|
- | 795 | break; |
|
- | 796 | ||
- | 797 | default: |
|
- | 798 | DRM_ERROR("Invalid framebuffer format %d\n", mode_cmd->depth); |
|
- | 799 | return -EINVAL; |
|
- | 800 | } |
|
- | 801 | ||
- | 802 | content_base_size.width = mode_cmd->width; |
|
1040 | vmw_framebuffer_to_vfbd(&vfb->base); |
803 | content_base_size.height = mode_cmd->height; |
- | 804 | content_base_size.depth = 1; |
|
- | 805 | ||
- | 806 | ret = vmw_surface_gb_priv_define(dev, |
|
- | 807 | 0, /* kernel visible only */ |
|
- | 808 | 0, /* flags */ |
|
- | 809 | format, |
|
- | 810 | true, /* can be a scanout buffer */ |
|
- | 811 | 1, /* num of mip levels */ |
|
- | 812 | 0, |
|
- | 813 | 0, |
|
- | 814 | content_base_size, |
|
- | 815 | srf_out); |
|
- | 816 | if (ret) { |
|
- | 817 | DRM_ERROR("Failed to allocate proxy content buffer\n"); |
|
- | 818 | return ret; |
|
- | 819 | } |
|
- | 820 | ||
- | 821 | res = &(*srf_out)->res; |
|
- | 822 | ||
- | 823 | /* Reserve and switch the backing mob. */ |
|
- | 824 | mutex_lock(&res->dev_priv->cmdbuf_mutex); |
|
- | 825 | (void) vmw_resource_reserve(res, false, true); |
|
- | 826 | vmw_dmabuf_unreference(&res->backup); |
|
1041 | 827 | res->backup = vmw_dmabuf_reference(dmabuf_mob); |
|
1042 | if (!vfbd->buffer) { |
828 | res->backup_offset = 0; |
1043 | WARN_ON(!vfbd->buffer); |
829 | vmw_resource_unreserve(res, false, NULL, 0); |
1044 | return 0; |
830 | mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
1045 | } |
831 | |
Line 1066... | Line 852... | ||
1066 | "for requested mode.\n"); |
852 | "for requested mode.\n"); |
1067 | return -EINVAL; |
853 | return -EINVAL; |
1068 | } |
854 | } |
Line 1069... | Line 855... | ||
1069 | 855 | ||
1070 | /* Limited framebuffer color depth support for screen objects */ |
856 | /* Limited framebuffer color depth support for screen objects */ |
1071 | if (dev_priv->sou_priv) { |
857 | if (dev_priv->active_display_unit == vmw_du_screen_object) { |
1072 | switch (mode_cmd->depth) { |
858 | switch (mode_cmd->depth) { |
1073 | case 32: |
859 | case 32: |
1074 | case 24: |
860 | case 24: |
1075 | /* Only support 32 bpp for 32 and 24 depth fbs */ |
861 | /* Only support 32 bpp for 32 and 24 depth fbs */ |
Line 1098... | Line 884... | ||
1098 | if (!vfbd) { |
884 | if (!vfbd) { |
1099 | ret = -ENOMEM; |
885 | ret = -ENOMEM; |
1100 | goto out_err1; |
886 | goto out_err1; |
1101 | } |
887 | } |
Line 1102... | Line -... | ||
1102 | - | ||
1103 | if (!vmw_dmabuf_reference(dmabuf)) { |
- | |
1104 | DRM_ERROR("failed to reference dmabuf %p\n", dmabuf); |
- | |
1105 | ret = -EINVAL; |
- | |
1106 | goto out_err2; |
- | |
1107 | } |
- | |
1108 | 888 | ||
1109 | vfbd->base.base.bits_per_pixel = mode_cmd->bpp; |
889 | vfbd->base.base.bits_per_pixel = mode_cmd->bpp; |
1110 | vfbd->base.base.pitches[0] = mode_cmd->pitch; |
890 | vfbd->base.base.pitches[0] = mode_cmd->pitch; |
1111 | vfbd->base.base.depth = mode_cmd->depth; |
891 | vfbd->base.base.depth = mode_cmd->depth; |
1112 | vfbd->base.base.width = mode_cmd->width; |
892 | vfbd->base.base.width = mode_cmd->width; |
1113 | vfbd->base.base.height = mode_cmd->height; |
- | |
1114 | if (!dev_priv->sou_priv) { |
- | |
1115 | vfbd->base.pin = vmw_framebuffer_dmabuf_pin; |
- | |
1116 | vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; |
- | |
1117 | } |
893 | vfbd->base.base.height = mode_cmd->height; |
1118 | vfbd->base.dmabuf = true; |
894 | vfbd->base.dmabuf = true; |
1119 | vfbd->buffer = dmabuf; |
895 | vfbd->buffer = vmw_dmabuf_reference(dmabuf); |
1120 | vfbd->base.user_handle = mode_cmd->handle; |
896 | vfbd->base.user_handle = mode_cmd->handle; |
Line 1121... | Line 897... | ||
1121 | *out = &vfbd->base; |
897 | *out = &vfbd->base; |
1122 | 898 | ||
1123 | ret = drm_framebuffer_init(dev, &vfbd->base.base, |
899 | ret = drm_framebuffer_init(dev, &vfbd->base.base, |
1124 | &vmw_framebuffer_dmabuf_funcs); |
900 | &vmw_framebuffer_dmabuf_funcs); |
Line 1125... | Line 901... | ||
1125 | if (ret) |
901 | if (ret) |
Line 1126... | Line -... | ||
1126 | goto out_err3; |
- | |
1127 | - | ||
1128 | return 0; |
902 | goto out_err2; |
- | 903 | ||
1129 | 904 | return 0; |
|
1130 | out_err3: |
905 | |
1131 | vmw_dmabuf_unreference(&dmabuf); |
906 | out_err2: |
1132 | out_err2: |
907 | vmw_dmabuf_unreference(&dmabuf); |
- | 908 | kfree(vfbd); |
|
- | 909 | out_err1: |
|
- | 910 | return ret; |
|
- | 911 | } |
|
- | 912 | ||
- | 913 | /** |
|
- | 914 | * vmw_kms_new_framebuffer - Create a new framebuffer. |
|
- | 915 | * |
|
- | 916 | * @dev_priv: Pointer to device private struct. |
|
- | 917 | * @dmabuf: Pointer to dma buffer to wrap the kms framebuffer around. |
|
- | 918 | * Either @dmabuf or @surface must be NULL. |
|
- | 919 | * @surface: Pointer to a surface to wrap the kms framebuffer around. |
|
- | 920 | * Either @dmabuf or @surface must be NULL. |
|
- | 921 | * @only_2d: No presents will occur to this dma buffer based framebuffer. This |
|
- | 922 | * Helps the code to do some important optimizations. |
|
- | 923 | * @mode_cmd: Frame-buffer metadata. |
|
- | 924 | */ |
|
- | 925 | struct vmw_framebuffer * |
|
- | 926 | vmw_kms_new_framebuffer(struct vmw_private *dev_priv, |
|
- | 927 | struct vmw_dma_buffer *dmabuf, |
|
- | 928 | struct vmw_surface *surface, |
|
- | 929 | bool only_2d, |
|
- | 930 | const struct drm_mode_fb_cmd *mode_cmd) |
|
- | 931 | { |
|
- | 932 | struct vmw_framebuffer *vfb = NULL; |
|
- | 933 | bool is_dmabuf_proxy = false; |
|
- | 934 | int ret; |
|
- | 935 | ||
- | 936 | /* |
|
- | 937 | * We cannot use the SurfaceDMA command in an non-accelerated VM, |
|
- | 938 | * therefore, wrap the DMA buf in a surface so we can use the |
|
- | 939 | * SurfaceCopy command. |
|
- | 940 | */ |
|
- | 941 | if (dmabuf && only_2d && |
|
- | 942 | dev_priv->active_display_unit == vmw_du_screen_target) { |
|
- | 943 | ret = vmw_create_dmabuf_proxy(dev_priv->dev, mode_cmd, |
|
- | 944 | dmabuf, &surface); |
|
- | 945 | if (ret) |
|
- | 946 | return ERR_PTR(ret); |
|
- | 947 | ||
- | 948 | is_dmabuf_proxy = true; |
|
- | 949 | } |
|
- | 950 | ||
- | 951 | /* Create the new framebuffer depending one what we have */ |
|
- | 952 | if (surface) { |
|
- | 953 | ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, |
|
- | 954 | mode_cmd, |
|
- | 955 | is_dmabuf_proxy); |
|
1133 | kfree(vfbd); |
956 | |
- | 957 | /* |
|
- | 958 | * vmw_create_dmabuf_proxy() adds a reference that is no longer |
|
- | 959 | * needed |
|
- | 960 | */ |
|
- | 961 | if (is_dmabuf_proxy) |
|
- | 962 | vmw_surface_unreference(&surface); |
|
- | 963 | } else if (dmabuf) { |
|
- | 964 | ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, dmabuf, &vfb, |
|
- | 965 | mode_cmd); |
|
- | 966 | } else { |
|
- | 967 | BUG(); |
|
- | 968 | } |
|
- | 969 | ||
- | 970 | if (ret) |
|
- | 971 | return ERR_PTR(ret); |
|
- | 972 | ||
- | 973 | vfb->pin = vmw_framebuffer_pin; |
|
Line 1134... | Line 974... | ||
1134 | out_err1: |
974 | vfb->unpin = vmw_framebuffer_unpin; |
1135 | return ret; |
975 | |
1136 | } |
976 | return vfb; |
Line 1167... | Line 1007... | ||
1167 | */ |
1007 | */ |
Line 1168... | Line 1008... | ||
1168 | 1008 | ||
1169 | if (!vmw_kms_validate_mode_vram(dev_priv, |
1009 | if (!vmw_kms_validate_mode_vram(dev_priv, |
1170 | mode_cmd.pitch, |
1010 | mode_cmd.pitch, |
1171 | mode_cmd.height)) { |
1011 | mode_cmd.height)) { |
1172 | DRM_ERROR("VRAM size is too small for requested mode.\n"); |
1012 | DRM_ERROR("Requested mode exceed bounding box limit.\n"); |
1173 | return ERR_PTR(-ENOMEM); |
1013 | return ERR_PTR(-ENOMEM); |
Line 1174... | Line 1014... | ||
1174 | } |
1014 | } |
1175 | 1015 | ||
Line 1191... | Line 1031... | ||
1191 | /** |
1031 | /** |
1192 | * End conditioned code. |
1032 | * End conditioned code. |
1193 | */ |
1033 | */ |
Line 1194... | Line 1034... | ||
1194 | 1034 | ||
1195 | /* returns either a dmabuf or surface */ |
1035 | /* returns either a dmabuf or surface */ |
1196 | // ret = vmw_user_lookup_handle(dev_priv, tfile, |
1036 | ret = vmw_user_lookup_handle(dev_priv, tfile, |
1197 | // mode_cmd.handle, |
1037 | mode_cmd.handle, |
1198 | // &surface, &bo); |
1038 | &surface, &bo); |
1199 | // if (ret) |
1039 | if (ret) |
1200 | // goto err_out; |
1040 | goto err_out; |
1201 | 1041 | ||
1202 | /* Create the new framebuffer depending one what we got back */ |
- | |
1203 | // if (bo) |
1042 | vfb = vmw_kms_new_framebuffer(dev_priv, bo, surface, |
1204 | // ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, |
1043 | !(dev_priv->capabilities & SVGA_CAP_3D), |
1205 | // &mode_cmd); |
1044 | &mode_cmd); |
1206 | // else if (surface) |
- | |
1207 | ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, |
1045 | if (IS_ERR(vfb)) { |
1208 | surface, &vfb, &mode_cmd); |
1046 | ret = PTR_ERR(vfb); |
1209 | // else |
1047 | goto err_out; |
Line 1210... | Line 1048... | ||
1210 | // BUG(); |
1048 | } |
1211 | 1049 | ||
1212 | err_out: |
1050 | err_out: |
1213 | /* vmw_user_lookup_handle takes one ref so does new_fb */ |
1051 | /* vmw_user_lookup_handle takes one ref so does new_fb */ |
1214 | // if (bo) |
1052 | if (bo) |
1215 | // vmw_dmabuf_unreference(&bo); |
1053 | vmw_dmabuf_unreference(&bo); |
Line 1216... | Line 1054... | ||
1216 | // if (surface) |
1054 | if (surface) |
1217 | // vmw_surface_unreference(&surface); |
1055 | vmw_surface_unreference(&surface); |
1218 | 1056 | ||
1219 | if (ret) { |
1057 | if (ret) { |
1220 | DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); |
1058 | DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); |
1221 | // ttm_base_object_unref(&user_obj); |
1059 | ttm_base_object_unref(&user_obj); |
Line 1222... | Line 1060... | ||
1222 | return ERR_PTR(ret); |
1060 | return ERR_PTR(ret); |
Line 1228... | Line 1066... | ||
1228 | 1066 | ||
1229 | static const struct drm_mode_config_funcs vmw_kms_funcs = { |
1067 | static const struct drm_mode_config_funcs vmw_kms_funcs = { |
1230 | .fb_create = vmw_kms_fb_create, |
1068 | .fb_create = vmw_kms_fb_create, |
Line 1231... | Line 1069... | ||
1231 | }; |
1069 | }; |
1232 | 1070 | ||
1233 | int vmw_kms_present(struct vmw_private *dev_priv, |
1071 | static int vmw_kms_generic_present(struct vmw_private *dev_priv, |
1234 | struct drm_file *file_priv, |
1072 | struct drm_file *file_priv, |
1235 | struct vmw_framebuffer *vfb, |
1073 | struct vmw_framebuffer *vfb, |
1236 | struct vmw_surface *surface, |
1074 | struct vmw_surface *surface, |
1237 | uint32_t sid, |
1075 | uint32_t sid, |
1238 | int32_t destX, int32_t destY, |
1076 | int32_t destX, int32_t destY, |
1239 | struct drm_vmw_rect *clips, |
1077 | struct drm_vmw_rect *clips, |
1240 | uint32_t num_clips) |
1078 | uint32_t num_clips) |
1241 | { |
- | |
1242 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
- | |
1243 | struct drm_clip_rect *tmp; |
- | |
1244 | struct drm_crtc *crtc; |
- | |
1245 | size_t fifo_size; |
- | |
1246 | int i, k, num_units; |
- | |
1247 | int ret = 0; /* silence warning */ |
- | |
1248 | int left, right, top, bottom; |
- | |
1249 | - | ||
1250 | struct { |
- | |
1251 | SVGA3dCmdHeader header; |
- | |
1252 | SVGA3dCmdBlitSurfaceToScreen body; |
- | |
1253 | } *cmd; |
- | |
1254 | SVGASignedRect *blits; |
- | |
1255 | - | ||
1256 | num_units = 0; |
1079 | { |
1257 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { |
- | |
1258 | if (crtc->primary->fb != &vfb->base) |
- | |
1259 | continue; |
- | |
1260 | units[num_units++] = vmw_crtc_to_du(crtc); |
- | |
1261 | } |
1080 | return vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, clips, |
1262 | - | ||
1263 | BUG_ON(surface == NULL); |
- | |
1264 | BUG_ON(!clips || !num_clips); |
- | |
1265 | - | ||
1266 | tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); |
- | |
1267 | if (unlikely(tmp == NULL)) { |
- | |
1268 | DRM_ERROR("Temporary cliprect memory alloc failed.\n"); |
- | |
1269 | return -ENOMEM; |
- | |
1270 | } |
- | |
1271 | - | ||
1272 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; |
- | |
1273 | cmd = kmalloc(fifo_size, GFP_KERNEL); |
- | |
1274 | if (unlikely(cmd == NULL)) { |
- | |
1275 | DRM_ERROR("Failed to allocate temporary fifo memory.\n"); |
- | |
1276 | ret = -ENOMEM; |
- | |
1277 | goto out_free_tmp; |
- | |
1278 | } |
- | |
1279 | - | ||
1280 | left = clips->x; |
- | |
1281 | right = clips->x + clips->w; |
- | |
1282 | top = clips->y; |
- | |
1283 | bottom = clips->y + clips->h; |
- | |
1284 | - | ||
1285 | for (i = 1; i < num_clips; i++) { |
- | |
1286 | left = min_t(int, left, (int)clips[i].x); |
- | |
1287 | right = max_t(int, right, (int)clips[i].x + clips[i].w); |
- | |
1288 | top = min_t(int, top, (int)clips[i].y); |
1081 | &surface->res, destX, destY, |
Line 1289... | Line -... | ||
1289 | bottom = max_t(int, bottom, (int)clips[i].y + clips[i].h); |
- | |
1290 | } |
- | |
1291 | - | ||
Line 1292... | Line -... | ||
1292 | /* only need to do this once */ |
- | |
1293 | memset(cmd, 0, fifo_size); |
- | |
1294 | cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); |
- | |
1295 | - | ||
1296 | blits = (SVGASignedRect *)&cmd[1]; |
- | |
1297 | - | ||
1298 | cmd->body.srcRect.left = left; |
- | |
1299 | cmd->body.srcRect.right = right; |
- | |
1300 | cmd->body.srcRect.top = top; |
- | |
1301 | cmd->body.srcRect.bottom = bottom; |
- | |
1302 | - | ||
1303 | for (i = 0; i < num_clips; i++) { |
- | |
1304 | tmp[i].x1 = clips[i].x - left; |
- | |
1305 | tmp[i].x2 = clips[i].x + clips[i].w - left; |
- | |
1306 | tmp[i].y1 = clips[i].y - top; |
- | |
1307 | tmp[i].y2 = clips[i].y + clips[i].h - top; |
- | |
1308 | } |
- | |
1309 | - | ||
1310 | for (k = 0; k < num_units; k++) { |
- | |
1311 | struct vmw_display_unit *unit = units[k]; |
- | |
1312 | struct vmw_clip_rect clip; |
- | |
1313 | int num; |
- | |
1314 | - | ||
1315 | clip.x1 = left + destX - unit->crtc.x; |
- | |
1316 | clip.y1 = top + destY - unit->crtc.y; |
- | |
1317 | clip.x2 = right + destX - unit->crtc.x; |
- | |
1318 | clip.y2 = bottom + destY - unit->crtc.y; |
- | |
1319 | - | ||
1320 | /* skip any crtcs that misses the clip region */ |
- | |
1321 | if (clip.x1 >= unit->crtc.mode.hdisplay || |
- | |
1322 | clip.y1 >= unit->crtc.mode.vdisplay || |
- | |
1323 | clip.x2 <= 0 || clip.y2 <= 0) |
- | |
1324 | continue; |
- | |
1325 | - | ||
1326 | /* |
- | |
1327 | * In order for the clip rects to be correctly scaled |
- | |
1328 | * the src and dest rects needs to be the same size. |
- | |
1329 | */ |
- | |
1330 | cmd->body.destRect.left = clip.x1; |
- | |
1331 | cmd->body.destRect.right = clip.x2; |
- | |
1332 | cmd->body.destRect.top = clip.y1; |
- | |
1333 | cmd->body.destRect.bottom = clip.y2; |
- | |
1334 | - | ||
1335 | /* create a clip rect of the crtc in dest coords */ |
- | |
1336 | clip.x2 = unit->crtc.mode.hdisplay - clip.x1; |
- | |
1337 | clip.y2 = unit->crtc.mode.vdisplay - clip.y1; |
- | |
1338 | clip.x1 = 0 - clip.x1; |
- | |
1339 | clip.y1 = 0 - clip.y1; |
- | |
1340 | - | ||
1341 | /* need to reset sid as it is changed by execbuf */ |
- | |
1342 | cmd->body.srcImage.sid = sid; |
- | |
1343 | cmd->body.destScreenId = unit->unit; |
- | |
1344 | - | ||
1345 | /* clip and write blits to cmd stream */ |
- | |
1346 | vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); |
- | |
1347 | - | ||
1348 | /* if no cliprects hit skip this */ |
- | |
1349 | if (num == 0) |
- | |
1350 | continue; |
- | |
1351 | - | ||
1352 | /* recalculate package length */ |
- | |
1353 | fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; |
- | |
1354 | cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); |
- | |
1355 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, |
- | |
1356 | fifo_size, 0, NULL, NULL); |
- | |
1357 | - | ||
1358 | if (unlikely(ret != 0)) |
- | |
1359 | break; |
- | |
1360 | } |
- | |
1361 | - | ||
1362 | kfree(cmd); |
- | |
1363 | out_free_tmp: |
- | |
1364 | kfree(tmp); |
- | |
1365 | 1082 | num_clips, 1, NULL); |
|
1366 | return ret; |
1083 | } |
1367 | } |
1084 | |
1368 | 1085 | ||
- | 1086 | int vmw_kms_present(struct vmw_private *dev_priv, |
|
- | 1087 | struct drm_file *file_priv, |
|
1369 | int vmw_kms_readback(struct vmw_private *dev_priv, |
1088 | struct vmw_framebuffer *vfb, |
1370 | struct drm_file *file_priv, |
1089 | struct vmw_surface *surface, |
1371 | struct vmw_framebuffer *vfb, |
1090 | uint32_t sid, |
1372 | struct drm_vmw_fence_rep __user *user_fence_rep, |
- | |
1373 | struct drm_vmw_rect *clips, |
- | |
1374 | uint32_t num_clips) |
- | |
1375 | { |
- | |
1376 | struct vmw_framebuffer_dmabuf *vfbd = |
- | |
1377 | vmw_framebuffer_to_vfbd(&vfb->base); |
- | |
1378 | struct vmw_dma_buffer *dmabuf = vfbd->buffer; |
- | |
1379 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
- | |
1380 | struct drm_crtc *crtc; |
- | |
1381 | size_t fifo_size; |
- | |
1382 | int i, k, ret, num_units, blits_pos; |
- | |
1383 | - | ||
1384 | struct { |
- | |
1385 | uint32_t header; |
- | |
1386 | SVGAFifoCmdDefineGMRFB body; |
- | |
1387 | } *cmd; |
1091 | int32_t destX, int32_t destY, |
1388 | struct { |
- | |
1389 | uint32_t header; |
- | |
1390 | SVGAFifoCmdBlitScreenToGMRFB body; |
- | |
1391 | } *blits; |
- | |
1392 | - | ||
1393 | num_units = 0; |
- | |
1394 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { |
- | |
1395 | if (crtc->primary->fb != &vfb->base) |
- | |
1396 | continue; |
- | |
1397 | units[num_units++] = vmw_crtc_to_du(crtc); |
- | |
1398 | } |
- | |
1399 | - | ||
1400 | BUG_ON(dmabuf == NULL); |
- | |
1401 | BUG_ON(!clips || !num_clips); |
- | |
1402 | - | ||
1403 | /* take a safe guess at fifo size */ |
- | |
1404 | fifo_size = sizeof(*cmd) + sizeof(*blits) * num_clips * num_units; |
- | |
1405 | cmd = kmalloc(fifo_size, GFP_KERNEL); |
- | |
1406 | if (unlikely(cmd == NULL)) { |
- | |
1407 | DRM_ERROR("Failed to allocate temporary fifo memory.\n"); |
- | |
1408 | return -ENOMEM; |
- | |
1409 | } |
- | |
1410 | - | ||
1411 | memset(cmd, 0, fifo_size); |
- | |
1412 | cmd->header = SVGA_CMD_DEFINE_GMRFB; |
- | |
1413 | cmd->body.format.bitsPerPixel = vfb->base.bits_per_pixel; |
- | |
1414 | cmd->body.format.colorDepth = vfb->base.depth; |
- | |
1415 | cmd->body.format.reserved = 0; |
- | |
1416 | cmd->body.bytesPerLine = vfb->base.pitches[0]; |
- | |
1417 | cmd->body.ptr.gmrId = vfb->user_handle; |
- | |
1418 | cmd->body.ptr.offset = 0; |
- | |
1419 | - | ||
1420 | blits = (void *)&cmd[1]; |
- | |
1421 | blits_pos = 0; |
- | |
1422 | for (i = 0; i < num_units; i++) { |
- | |
1423 | struct drm_vmw_rect *c = clips; |
- | |
1424 | for (k = 0; k < num_clips; k++, c++) { |
- | |
1425 | /* transform clip coords to crtc origin based coords */ |
- | |
1426 | int clip_x1 = c->x - units[i]->crtc.x; |
- | |
1427 | int clip_x2 = c->x - units[i]->crtc.x + c->w; |
- | |
1428 | int clip_y1 = c->y - units[i]->crtc.y; |
- | |
1429 | int clip_y2 = c->y - units[i]->crtc.y + c->h; |
- | |
1430 | int dest_x = c->x; |
- | |
1431 | int dest_y = c->y; |
- | |
1432 | - | ||
1433 | /* compensate for clipping, we negate |
- | |
1434 | * a negative number and add that. |
- | |
1435 | */ |
- | |
1436 | if (clip_x1 < 0) |
- | |
1437 | dest_x += -clip_x1; |
- | |
1438 | if (clip_y1 < 0) |
- | |
1439 | dest_y += -clip_y1; |
- | |
1440 | - | ||
1441 | /* clip */ |
- | |
1442 | clip_x1 = max(clip_x1, 0); |
- | |
1443 | clip_y1 = max(clip_y1, 0); |
- | |
1444 | clip_x2 = min(clip_x2, units[i]->crtc.mode.hdisplay); |
- | |
1445 | clip_y2 = min(clip_y2, units[i]->crtc.mode.vdisplay); |
- | |
1446 | - | ||
1447 | /* and cull any rects that misses the crtc */ |
- | |
1448 | if (clip_x1 >= units[i]->crtc.mode.hdisplay || |
- | |
1449 | clip_y1 >= units[i]->crtc.mode.vdisplay || |
- | |
1450 | clip_x2 <= 0 || clip_y2 <= 0) |
- | |
1451 | continue; |
- | |
1452 | - | ||
Line -... | Line 1092... | ||
- | 1092 | struct drm_vmw_rect *clips, |
|
- | 1093 | uint32_t num_clips) |
|
1453 | blits[blits_pos].header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB; |
1094 | { |
1454 | blits[blits_pos].body.srcScreenId = units[i]->unit; |
1095 | int ret; |
- | 1096 | ||
- | 1097 | switch (dev_priv->active_display_unit) { |
|
- | 1098 | case vmw_du_screen_target: |
|
- | 1099 | ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, clips, |
|
1455 | blits[blits_pos].body.destOrigin.x = dest_x; |
1100 | &surface->res, destX, destY, |
- | 1101 | num_clips, 1, NULL); |
|
- | 1102 | break; |
|
- | 1103 | case vmw_du_screen_object: |
|
- | 1104 | ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, |
|
1456 | blits[blits_pos].body.destOrigin.y = dest_y; |
1105 | sid, destX, destY, clips, |
1457 | 1106 | num_clips); |
|
1458 | blits[blits_pos].body.srcRect.left = clip_x1; |
1107 | break; |
1459 | blits[blits_pos].body.srcRect.top = clip_y1; |
1108 | default: |
1460 | blits[blits_pos].body.srcRect.right = clip_x2; |
- | |
1461 | blits[blits_pos].body.srcRect.bottom = clip_y2; |
1109 | WARN_ONCE(true, |
1462 | blits_pos++; |
- | |
1463 | } |
- | |
1464 | } |
1110 | "Present called with invalid display system.\n"); |
Line 1465... | Line 1111... | ||
1465 | /* reset size here and use calculated exact size from loops */ |
1111 | ret = -ENOSYS; |
Line 1466... | Line 1112... | ||
1466 | fifo_size = sizeof(*cmd) + sizeof(*blits) * blits_pos; |
1112 | break; |
1467 | 1113 | } |
|
Line 1468... | Line 1114... | ||
1468 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, |
1114 | if (ret) |
1469 | 0, user_fence_rep, NULL); |
1115 | return ret; |
1470 | 1116 | ||
Line 1480... | Line 1126... | ||
1480 | 1126 | ||
1481 | drm_mode_config_init(dev); |
1127 | drm_mode_config_init(dev); |
1482 | dev->mode_config.funcs = &vmw_kms_funcs; |
1128 | dev->mode_config.funcs = &vmw_kms_funcs; |
1483 | dev->mode_config.min_width = 1; |
1129 | dev->mode_config.min_width = 1; |
1484 | dev->mode_config.min_height = 1; |
- | |
1485 | /* assumed largest fb size */ |
1130 | dev->mode_config.min_height = 1; |
1486 | dev->mode_config.max_width = 8192; |
1131 | dev->mode_config.max_width = dev_priv->texture_max_width; |
Line 1487... | Line 1132... | ||
1487 | dev->mode_config.max_height = 8192; |
1132 | dev->mode_config.max_height = dev_priv->texture_max_height; |
- | 1133 | ||
- | 1134 | ret = vmw_kms_stdu_init_display(dev_priv); |
|
- | 1135 | if (ret) { |
|
- | 1136 | ret = vmw_kms_sou_init_display(dev_priv); |
|
- | 1137 | if (ret) /* Fallback */ |
|
Line 1488... | Line 1138... | ||
1488 | 1138 | ret = vmw_kms_ldu_init_display(dev_priv); |
|
1489 | ret = vmw_kms_init_screen_object_display(dev_priv); |
1139 | } |
Line 1490... | Line 1140... | ||
1490 | 1140 | ||
1491 | return 0; |
1141 | return ret; |
- | 1142 | } |
|
- | 1143 | ||
1492 | } |
1144 | int vmw_kms_close(struct vmw_private *dev_priv) |
1493 | 1145 | { |
|
1494 | int vmw_kms_close(struct vmw_private *dev_priv) |
1146 | int ret; |
1495 | { |
1147 | |
1496 | /* |
1148 | /* |
1497 | * Docs says we should take the lock before calling this function |
1149 | * Docs says we should take the lock before calling this function |
- | 1150 | * but since it destroys encoders and our destructor calls |
|
1498 | * but since it destroys encoders and our destructor calls |
1151 | * drm_encoder_cleanup which takes the lock we deadlock. |
- | 1152 | */ |
|
1499 | * drm_encoder_cleanup which takes the lock we deadlock. |
1153 | drm_mode_config_cleanup(dev_priv->dev); |
1500 | */ |
1154 | if (dev_priv->active_display_unit == vmw_du_screen_object) |
1501 | // drm_mode_config_cleanup(dev_priv->dev); |
1155 | ret = vmw_kms_sou_close_display(dev_priv); |
- | 1156 | else if (dev_priv->active_display_unit == vmw_du_screen_target) |
|
1502 | // if (dev_priv->sou_priv) |
1157 | ret = vmw_kms_stdu_close_display(dev_priv); |
1503 | // vmw_kms_close_screen_object_display(dev_priv); |
1158 | else |
Line 1504... | Line 1159... | ||
1504 | // else |
1159 | ret = vmw_kms_ldu_close_display(dev_priv); |
1505 | // vmw_kms_close_legacy_display_system(dev_priv); |
1160 | |
1506 | return 0; |
1161 | return ret; |
Line 1552... | Line 1207... | ||
1552 | unsigned bpp, unsigned depth) |
1207 | unsigned bpp, unsigned depth) |
1553 | { |
1208 | { |
1554 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
1209 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
1555 | vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch); |
1210 | vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch); |
1556 | else if (vmw_fifo_have_pitchlock(vmw_priv)) |
1211 | else if (vmw_fifo_have_pitchlock(vmw_priv)) |
1557 | iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); |
1212 | vmw_mmio_write(pitch, vmw_priv->mmio_virt + |
- | 1213 | SVGA_FIFO_PITCHLOCK); |
|
1558 | vmw_write(vmw_priv, SVGA_REG_WIDTH, width); |
1214 | vmw_write(vmw_priv, SVGA_REG_WIDTH, width); |
1559 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); |
1215 | vmw_write(vmw_priv, SVGA_REG_HEIGHT, height); |
1560 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bpp); |
1216 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bpp); |
Line 1561... | Line 1217... | ||
1561 | 1217 | ||
Line 1578... | Line 1234... | ||
1578 | vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); |
1234 | vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); |
1579 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
1235 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
1580 | vmw_priv->vga_pitchlock = |
1236 | vmw_priv->vga_pitchlock = |
1581 | vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); |
1237 | vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); |
1582 | else if (vmw_fifo_have_pitchlock(vmw_priv)) |
1238 | else if (vmw_fifo_have_pitchlock(vmw_priv)) |
1583 | vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt + |
1239 | vmw_priv->vga_pitchlock = vmw_mmio_read(vmw_priv->mmio_virt + |
1584 | SVGA_FIFO_PITCHLOCK); |
1240 | SVGA_FIFO_PITCHLOCK); |
Line 1585... | Line 1241... | ||
1585 | 1241 | ||
1586 | if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) |
1242 | if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) |
Line 1627... | Line 1283... | ||
1627 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); |
1283 | vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp); |
1628 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
1284 | if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK) |
1629 | vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, |
1285 | vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, |
1630 | vmw_priv->vga_pitchlock); |
1286 | vmw_priv->vga_pitchlock); |
1631 | else if (vmw_fifo_have_pitchlock(vmw_priv)) |
1287 | else if (vmw_fifo_have_pitchlock(vmw_priv)) |
1632 | iowrite32(vmw_priv->vga_pitchlock, |
1288 | vmw_mmio_write(vmw_priv->vga_pitchlock, |
1633 | vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); |
1289 | vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK); |
Line 1634... | Line 1290... | ||
1634 | 1290 | ||
1635 | if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) |
1291 | if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) |
Line 1651... | Line 1307... | ||
1651 | 1307 | ||
1652 | bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, |
1308 | bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, |
1653 | uint32_t pitch, |
1309 | uint32_t pitch, |
1654 | uint32_t height) |
1310 | uint32_t height) |
1655 | { |
1311 | { |
- | 1312 | return ((u64) pitch * (u64) height) < (u64) |
|
- | 1313 | ((dev_priv->active_display_unit == vmw_du_screen_target) ? |
|
1656 | return ((u64) pitch * (u64) height) < (u64) dev_priv->prim_bb_mem; |
1314 | dev_priv->prim_bb_mem : dev_priv->vram_size); |
Line 1657... | Line 1315... | ||
1657 | } |
1315 | } |
1658 | 1316 | ||
1659 | 1317 | ||
1660 | /** |
1318 | /** |
1661 | * Function called by DRM code called with vbl_lock held. |
1319 | * Function called by DRM code called with vbl_lock held. |
1662 | */ |
1320 | */ |
1663 | u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc) |
1321 | u32 vmw_get_vblank_counter(struct drm_device *dev, unsigned int pipe) |
Line 1664... | Line 1322... | ||
1664 | { |
1322 | { |
1665 | return 0; |
1323 | return 0; |
1666 | } |
1324 | } |
1667 | 1325 | ||
1668 | /** |
1326 | /** |
1669 | * Function called by DRM code called with vbl_lock held. |
1327 | * Function called by DRM code called with vbl_lock held. |
1670 | */ |
1328 | */ |
Line 1671... | Line 1329... | ||
1671 | int vmw_enable_vblank(struct drm_device *dev, int crtc) |
1329 | int vmw_enable_vblank(struct drm_device *dev, unsigned int pipe) |
1672 | { |
1330 | { |
1673 | return -ENOSYS; |
1331 | return -ENOSYS; |
1674 | } |
1332 | } |
1675 | 1333 | ||
1676 | /** |
1334 | /** |
Line 1677... | Line 1335... | ||
1677 | * Function called by DRM code called with vbl_lock held. |
1335 | * Function called by DRM code called with vbl_lock held. |
Line 1725... | Line 1383... | ||
1725 | mutex_unlock(&dev->mode_config.mutex); |
1383 | mutex_unlock(&dev->mode_config.mutex); |
Line 1726... | Line 1384... | ||
1726 | 1384 | ||
1727 | return 0; |
1385 | return 0; |
Line 1728... | Line -... | ||
1728 | } |
- | |
1729 | - | ||
1730 | #if 0 |
- | |
1731 | int vmw_du_page_flip(struct drm_crtc *crtc, |
- | |
1732 | struct drm_framebuffer *fb, |
- | |
1733 | struct drm_pending_vblank_event *event, |
- | |
1734 | uint32_t page_flip_flags) |
- | |
1735 | { |
- | |
1736 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
- | |
1737 | struct drm_framebuffer *old_fb = crtc->primary->fb; |
- | |
1738 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); |
- | |
1739 | struct drm_file *file_priv ; |
- | |
1740 | struct vmw_fence_obj *fence = NULL; |
- | |
1741 | struct drm_clip_rect clips; |
- | |
1742 | int ret; |
- | |
1743 | - | ||
1744 | if (event == NULL) |
- | |
1745 | return -EINVAL; |
- | |
1746 | - | ||
1747 | /* require ScreenObject support for page flipping */ |
- | |
1748 | if (!dev_priv->sou_priv) |
- | |
1749 | return -ENOSYS; |
- | |
1750 | - | ||
1751 | file_priv = event->base.file_priv; |
- | |
1752 | if (!vmw_kms_screen_object_flippable(dev_priv, crtc)) |
- | |
1753 | return -EINVAL; |
- | |
1754 | - | ||
1755 | crtc->primary->fb = fb; |
- | |
1756 | - | ||
1757 | /* do a full screen dirty update */ |
- | |
1758 | clips.x1 = clips.y1 = 0; |
- | |
1759 | clips.x2 = fb->width; |
- | |
1760 | clips.y2 = fb->height; |
- | |
1761 | - | ||
1762 | if (vfb->dmabuf) |
- | |
1763 | ret = do_dmabuf_dirty_sou(file_priv, dev_priv, vfb, |
- | |
1764 | 0, 0, &clips, 1, 1, &fence); |
- | |
1765 | else |
- | |
1766 | ret = do_surface_dirty_sou(dev_priv, file_priv, vfb, |
- | |
1767 | 0, 0, &clips, 1, 1, &fence); |
- | |
1768 | - | ||
1769 | - | ||
1770 | if (ret != 0) |
- | |
1771 | goto out_no_fence; |
- | |
1772 | if (!fence) { |
- | |
1773 | ret = -EINVAL; |
- | |
1774 | goto out_no_fence; |
- | |
1775 | } |
- | |
1776 | - | ||
1777 | ret = vmw_event_fence_action_queue(file_priv, fence, |
- | |
1778 | &event->base, |
- | |
1779 | &event->event.tv_sec, |
- | |
1780 | &event->event.tv_usec, |
- | |
1781 | true); |
- | |
1782 | - | ||
1783 | /* |
- | |
1784 | * No need to hold on to this now. The only cleanup |
- | |
1785 | * we need to do if we fail is unref the fence. |
- | |
1786 | */ |
- | |
1787 | vmw_fence_obj_unreference(&fence); |
- | |
1788 | - | ||
1789 | if (vmw_crtc_to_du(crtc)->is_implicit) |
- | |
1790 | vmw_kms_screen_object_update_implicit_fb(dev_priv, crtc); |
- | |
1791 | - | ||
1792 | return ret; |
- | |
1793 | - | ||
1794 | out_no_fence: |
- | |
1795 | crtc->primary->fb = old_fb; |
- | |
1796 | return ret; |
- | |
1797 | } |
- | |
1798 | #endif |
1386 | } |
1799 | 1387 | ||
1800 | void vmw_du_crtc_save(struct drm_crtc *crtc) |
1388 | void vmw_du_crtc_save(struct drm_crtc *crtc) |
Line 1801... | Line 1389... | ||
1801 | { |
1389 | { |
Line 1819... | Line 1407... | ||
1819 | vmw_write(dev_priv, SVGA_PALETTE_BASE + i * 3 + 1, g[i] >> 8); |
1407 | vmw_write(dev_priv, SVGA_PALETTE_BASE + i * 3 + 1, g[i] >> 8); |
1820 | vmw_write(dev_priv, SVGA_PALETTE_BASE + i * 3 + 2, b[i] >> 8); |
1408 | vmw_write(dev_priv, SVGA_PALETTE_BASE + i * 3 + 2, b[i] >> 8); |
1821 | } |
1409 | } |
1822 | } |
1410 | } |
Line 1823... | Line 1411... | ||
1823 | 1411 | ||
1824 | void vmw_du_connector_dpms(struct drm_connector *connector, int mode) |
1412 | int vmw_du_connector_dpms(struct drm_connector *connector, int mode) |
- | 1413 | { |
|
1825 | { |
1414 | return 0; |
Line 1826... | Line 1415... | ||
1826 | } |
1415 | } |
1827 | 1416 | ||
1828 | void vmw_du_connector_save(struct drm_connector *connector) |
1417 | void vmw_du_connector_save(struct drm_connector *connector) |
Line 1839... | Line 1428... | ||
1839 | uint32_t num_displays; |
1428 | uint32_t num_displays; |
1840 | struct drm_device *dev = connector->dev; |
1429 | struct drm_device *dev = connector->dev; |
1841 | struct vmw_private *dev_priv = vmw_priv(dev); |
1430 | struct vmw_private *dev_priv = vmw_priv(dev); |
1842 | struct vmw_display_unit *du = vmw_connector_to_du(connector); |
1431 | struct vmw_display_unit *du = vmw_connector_to_du(connector); |
Line 1843... | Line -... | ||
1843 | - | ||
1844 | mutex_lock(&dev_priv->hw_mutex); |
1432 | |
1845 | num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); |
- | |
Line 1846... | Line 1433... | ||
1846 | mutex_unlock(&dev_priv->hw_mutex); |
1433 | num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); |
1847 | 1434 | ||
1848 | return ((vmw_connector_to_du(connector)->unit < num_displays && |
1435 | return ((vmw_connector_to_du(connector)->unit < num_displays && |
1849 | du->pref_active) ? |
1436 | du->pref_active) ? |
Line 1936... | Line 1523... | ||
1936 | * 60Hz vrefresh mode. |
1523 | * 60Hz vrefresh mode. |
1937 | * |
1524 | * |
1938 | * @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay |
1525 | * @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay |
1939 | * members filled in. |
1526 | * members filled in. |
1940 | */ |
1527 | */ |
1941 | static void vmw_guess_mode_timing(struct drm_display_mode *mode) |
1528 | void vmw_guess_mode_timing(struct drm_display_mode *mode) |
1942 | { |
1529 | { |
1943 | mode->hsync_start = mode->hdisplay + 50; |
1530 | mode->hsync_start = mode->hdisplay + 50; |
1944 | mode->hsync_end = mode->hsync_start + 50; |
1531 | mode->hsync_end = mode->hsync_start + 50; |
1945 | mode->htotal = mode->hsync_end + 50; |
1532 | mode->htotal = mode->hsync_end + 50; |
Line 1965... | Line 1552... | ||
1965 | DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, |
1552 | DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, |
1966 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
1553 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
1967 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) |
1554 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) |
1968 | }; |
1555 | }; |
1969 | int i; |
1556 | int i; |
- | 1557 | u32 assumed_bpp = 2; |
|
- | 1558 | ||
- | 1559 | /* |
|
- | 1560 | * If using screen objects, then assume 32-bpp because that's what the |
|
- | 1561 | * SVGA device is assuming |
|
- | 1562 | */ |
|
- | 1563 | if (dev_priv->active_display_unit == vmw_du_screen_object) |
|
- | 1564 | assumed_bpp = 4; |
|
- | 1565 | ||
- | 1566 | if (dev_priv->active_display_unit == vmw_du_screen_target) { |
|
- | 1567 | max_width = min(max_width, dev_priv->stdu_max_width); |
|
- | 1568 | max_height = min(max_height, dev_priv->stdu_max_height); |
|
- | 1569 | } |
|
Line 1970... | Line 1570... | ||
1970 | 1570 | ||
1971 | /* Add preferred mode */ |
- | |
1972 | { |
1571 | /* Add preferred mode */ |
1973 | mode = drm_mode_duplicate(dev, &prefmode); |
1572 | mode = drm_mode_duplicate(dev, &prefmode); |
1974 | if (!mode) |
1573 | if (!mode) |
1975 | return 0; |
1574 | return 0; |
1976 | mode->hdisplay = du->pref_width; |
1575 | mode->hdisplay = du->pref_width; |
1977 | mode->vdisplay = du->pref_height; |
1576 | mode->vdisplay = du->pref_height; |
Line 1978... | Line 1577... | ||
1978 | vmw_guess_mode_timing(mode); |
1577 | vmw_guess_mode_timing(mode); |
- | 1578 | ||
1979 | 1579 | if (vmw_kms_validate_mode_vram(dev_priv, |
|
1980 | if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2, |
1580 | mode->hdisplay * assumed_bpp, |
1981 | mode->vdisplay)) { |
1581 | mode->vdisplay)) { |
1982 | drm_mode_probed_add(connector, mode); |
1582 | drm_mode_probed_add(connector, mode); |
1983 | } else { |
1583 | } else { |
Line 1990... | Line 1590... | ||
1990 | drm_mode_destroy(dev, du->pref_mode); |
1590 | drm_mode_destroy(dev, du->pref_mode); |
1991 | } |
1591 | } |
Line 1992... | Line 1592... | ||
1992 | 1592 | ||
1993 | /* mode might be null here, this is intended */ |
1593 | /* mode might be null here, this is intended */ |
1994 | du->pref_mode = mode; |
- | |
Line 1995... | Line 1594... | ||
1995 | } |
1594 | du->pref_mode = mode; |
1996 | 1595 | ||
1997 | for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { |
1596 | for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { |
1998 | bmode = &vmw_kms_connector_builtin[i]; |
1597 | bmode = &vmw_kms_connector_builtin[i]; |
1999 | if (bmode->hdisplay > max_width || |
1598 | if (bmode->hdisplay > max_width || |
Line 2000... | Line 1599... | ||
2000 | bmode->vdisplay > max_height) |
1599 | bmode->vdisplay > max_height) |
- | 1600 | continue; |
|
2001 | continue; |
1601 | |
2002 | 1602 | if (!vmw_kms_validate_mode_vram(dev_priv, |
|
Line 2003... | Line 1603... | ||
2003 | if (!vmw_kms_validate_mode_vram(dev_priv, bmode->hdisplay * 2, |
1603 | bmode->hdisplay * assumed_bpp, |
2004 | bmode->vdisplay)) |
1604 | bmode->vdisplay)) |
Line 2010... | Line 1610... | ||
2010 | mode->vrefresh = drm_mode_vrefresh(mode); |
1610 | mode->vrefresh = drm_mode_vrefresh(mode); |
Line 2011... | Line 1611... | ||
2011 | 1611 | ||
2012 | drm_mode_probed_add(connector, mode); |
1612 | drm_mode_probed_add(connector, mode); |
Line 2013... | Line -... | ||
2013 | } |
- | |
2014 | - | ||
2015 | /* Move the prefered mode first, help apps pick the right mode. */ |
- | |
2016 | if (du->pref_mode) |
- | |
2017 | list_move(&du->pref_mode->head, &connector->probed_modes); |
1613 | } |
- | 1614 | ||
- | 1615 | drm_mode_connector_list_update(connector, true); |
|
Line 2018... | Line 1616... | ||
2018 | 1616 | /* Move the prefered mode first, help apps pick the right mode. */ |
|
2019 | drm_mode_connector_list_update(connector, true); |
1617 | drm_mode_sort(&connector->modes); |
Line 2020... | Line 1618... | ||
2020 | 1618 | ||
Line 2038... | Line 1636... | ||
2038 | void __user *user_rects; |
1636 | void __user *user_rects; |
2039 | struct drm_vmw_rect *rects; |
1637 | struct drm_vmw_rect *rects; |
2040 | unsigned rects_size; |
1638 | unsigned rects_size; |
2041 | int ret; |
1639 | int ret; |
2042 | int i; |
1640 | int i; |
- | 1641 | u64 total_pixels = 0; |
|
2043 | struct drm_mode_config *mode_config = &dev->mode_config; |
1642 | struct drm_mode_config *mode_config = &dev->mode_config; |
2044 | - | ||
2045 | ret = ttm_read_lock(&dev_priv->reservation_sem, true); |
1643 | struct drm_vmw_rect bounding_box = {0}; |
2046 | if (unlikely(ret != 0)) |
- | |
2047 | return ret; |
- | |
Line 2048... | Line 1644... | ||
2048 | 1644 | ||
2049 | if (!arg->num_outputs) { |
1645 | if (!arg->num_outputs) { |
2050 | struct drm_vmw_rect def_rect = {0, 0, 800, 600}; |
1646 | struct drm_vmw_rect def_rect = {0, 0, 800, 600}; |
2051 | vmw_du_update_layout(dev_priv, 1, &def_rect); |
1647 | vmw_du_update_layout(dev_priv, 1, &def_rect); |
2052 | goto out_unlock; |
1648 | return 0; |
Line 2053... | Line 1649... | ||
2053 | } |
1649 | } |
2054 | 1650 | ||
2055 | rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); |
1651 | rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); |
2056 | rects = kcalloc(arg->num_outputs, sizeof(struct drm_vmw_rect), |
1652 | rects = kcalloc(arg->num_outputs, sizeof(struct drm_vmw_rect), |
2057 | GFP_KERNEL); |
1653 | GFP_KERNEL); |
2058 | if (unlikely(!rects)) { |
- | |
2059 | ret = -ENOMEM; |
- | |
Line 2060... | Line 1654... | ||
2060 | goto out_unlock; |
1654 | if (unlikely(!rects)) |
2061 | } |
1655 | return -ENOMEM; |
2062 | 1656 | ||
2063 | user_rects = (void __user *)(unsigned long)arg->rects; |
1657 | user_rects = (void __user *)(unsigned long)arg->rects; |
Line 2075... | Line 1669... | ||
2075 | rects[i].y + rects[i].h > mode_config->max_height) { |
1669 | rects[i].y + rects[i].h > mode_config->max_height) { |
2076 | DRM_ERROR("Invalid GUI layout.\n"); |
1670 | DRM_ERROR("Invalid GUI layout.\n"); |
2077 | ret = -EINVAL; |
1671 | ret = -EINVAL; |
2078 | goto out_free; |
1672 | goto out_free; |
2079 | } |
1673 | } |
- | 1674 | ||
- | 1675 | /* |
|
- | 1676 | * bounding_box.w and bunding_box.h are used as |
|
- | 1677 | * lower-right coordinates |
|
- | 1678 | */ |
|
- | 1679 | if (rects[i].x + rects[i].w > bounding_box.w) |
|
- | 1680 | bounding_box.w = rects[i].x + rects[i].w; |
|
- | 1681 | ||
- | 1682 | if (rects[i].y + rects[i].h > bounding_box.h) |
|
- | 1683 | bounding_box.h = rects[i].y + rects[i].h; |
|
- | 1684 | ||
- | 1685 | total_pixels += (u64) rects[i].w * (u64) rects[i].h; |
|
- | 1686 | } |
|
- | 1687 | ||
- | 1688 | if (dev_priv->active_display_unit == vmw_du_screen_target) { |
|
- | 1689 | /* |
|
- | 1690 | * For Screen Targets, the limits for a toplogy are: |
|
- | 1691 | * 1. Bounding box (assuming 32bpp) must be < prim_bb_mem |
|
- | 1692 | * 2. Total pixels (assuming 32bpp) must be < prim_bb_mem |
|
- | 1693 | */ |
|
- | 1694 | u64 bb_mem = bounding_box.w * bounding_box.h * 4; |
|
- | 1695 | u64 pixel_mem = total_pixels * 4; |
|
- | 1696 | ||
- | 1697 | if (bb_mem > dev_priv->prim_bb_mem) { |
|
- | 1698 | DRM_ERROR("Topology is beyond supported limits.\n"); |
|
- | 1699 | ret = -EINVAL; |
|
- | 1700 | goto out_free; |
|
- | 1701 | } |
|
- | 1702 | ||
- | 1703 | if (pixel_mem > dev_priv->prim_bb_mem) { |
|
- | 1704 | DRM_ERROR("Combined output size too large\n"); |
|
- | 1705 | ret = -EINVAL; |
|
- | 1706 | goto out_free; |
|
- | 1707 | } |
|
2080 | } |
1708 | } |
Line 2081... | Line 1709... | ||
2081 | 1709 | ||
Line 2082... | Line 1710... | ||
2082 | vmw_du_update_layout(dev_priv, arg->num_outputs, rects); |
1710 | vmw_du_update_layout(dev_priv, arg->num_outputs, rects); |
2083 | 1711 | ||
2084 | out_free: |
- | |
2085 | kfree(rects); |
- | |
2086 | out_unlock: |
1712 | out_free: |
2087 | ttm_read_unlock(&dev_priv->reservation_sem); |
1713 | kfree(rects); |
2088 | return ret; |
1714 | return ret; |
- | 1715 | } |
|
- | 1716 | #endif |
|
- | 1717 | /** |
|
- | 1718 | * vmw_kms_helper_dirty - Helper to build commands and perform actions based |
|
- | 1719 | * on a set of cliprects and a set of display units. |
|
- | 1720 | * |
|
- | 1721 | * @dev_priv: Pointer to a device private structure. |
|
- | 1722 | * @framebuffer: Pointer to the framebuffer on which to perform the actions. |
|
- | 1723 | * @clips: A set of struct drm_clip_rect. Either this os @vclips must be NULL. |
|
- | 1724 | * Cliprects are given in framebuffer coordinates. |
|
- | 1725 | * @vclips: A set of struct drm_vmw_rect cliprects. Either this or @clips must |
|
- | 1726 | * be NULL. Cliprects are given in source coordinates. |
|
- | 1727 | * @dest_x: X coordinate offset for the crtc / destination clip rects. |
|
- | 1728 | * @dest_y: Y coordinate offset for the crtc / destination clip rects. |
|
- | 1729 | * @num_clips: Number of cliprects in the @clips or @vclips array. |
|
- | 1730 | * @increment: Integer with which to increment the clip counter when looping. |
|
- | 1731 | * Used to skip a predetermined number of clip rects. |
|
- | 1732 | * @dirty: Closure structure. See the description of struct vmw_kms_dirty. |
|
- | 1733 | */ |
|
- | 1734 | int vmw_kms_helper_dirty(struct vmw_private *dev_priv, |
|
- | 1735 | struct vmw_framebuffer *framebuffer, |
|
- | 1736 | const struct drm_clip_rect *clips, |
|
- | 1737 | const struct drm_vmw_rect *vclips, |
|
- | 1738 | s32 dest_x, s32 dest_y, |
|
- | 1739 | int num_clips, |
|
- | 1740 | int increment, |
|
- | 1741 | struct vmw_kms_dirty *dirty) |
|
- | 1742 | { |
|
- | 1743 | struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; |
|
- | 1744 | struct drm_crtc *crtc; |
|
- | 1745 | u32 num_units = 0; |
|
- | 1746 | u32 i, k; |
|
- | 1747 | ||
- | 1748 | dirty->dev_priv = dev_priv; |
|
- | 1749 | ||
- | 1750 | list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { |
|
- | 1751 | if (crtc->primary->fb != &framebuffer->base) |
|
- | 1752 | continue; |
|
- | 1753 | units[num_units++] = vmw_crtc_to_du(crtc); |
|
- | 1754 | } |
|
- | 1755 | ||
- | 1756 | for (k = 0; k < num_units; k++) { |
|
- | 1757 | struct vmw_display_unit *unit = units[k]; |
|
- | 1758 | s32 crtc_x = unit->crtc.x; |
|
- | 1759 | s32 crtc_y = unit->crtc.y; |
|
- | 1760 | s32 crtc_width = unit->crtc.mode.hdisplay; |
|
- | 1761 | s32 crtc_height = unit->crtc.mode.vdisplay; |
|
- | 1762 | const struct drm_clip_rect *clips_ptr = clips; |
|
- | 1763 | const struct drm_vmw_rect *vclips_ptr = vclips; |
|
- | 1764 | ||
- | 1765 | dirty->unit = unit; |
|
- | 1766 | if (dirty->fifo_reserve_size > 0) { |
|
- | 1767 | dirty->cmd = vmw_fifo_reserve(dev_priv, |
|
- | 1768 | dirty->fifo_reserve_size); |
|
- | 1769 | if (!dirty->cmd) { |
|
- | 1770 | DRM_ERROR("Couldn't reserve fifo space " |
|
- | 1771 | "for dirty blits.\n"); |
|
- | 1772 | return -ENOMEM; |
|
- | 1773 | } |
|
- | 1774 | memset(dirty->cmd, 0, dirty->fifo_reserve_size); |
|
- | 1775 | } |
|
- | 1776 | dirty->num_hits = 0; |
|
- | 1777 | for (i = 0; i < num_clips; i++, clips_ptr += increment, |
|
- | 1778 | vclips_ptr += increment) { |
|
- | 1779 | s32 clip_left; |
|
- | 1780 | s32 clip_top; |
|
- | 1781 | ||
- | 1782 | /* |
|
- | 1783 | * Select clip array type. Note that integer type |
|
- | 1784 | * in @clips is unsigned short, whereas in @vclips |
|
- | 1785 | * it's 32-bit. |
|
- | 1786 | */ |
|
- | 1787 | if (clips) { |
|
- | 1788 | dirty->fb_x = (s32) clips_ptr->x1; |
|
- | 1789 | dirty->fb_y = (s32) clips_ptr->y1; |
|
- | 1790 | dirty->unit_x2 = (s32) clips_ptr->x2 + dest_x - |
|
- | 1791 | crtc_x; |
|
- | 1792 | dirty->unit_y2 = (s32) clips_ptr->y2 + dest_y - |
|
- | 1793 | crtc_y; |
|
- | 1794 | } else { |
|
- | 1795 | dirty->fb_x = vclips_ptr->x; |
|
- | 1796 | dirty->fb_y = vclips_ptr->y; |
|
- | 1797 | dirty->unit_x2 = dirty->fb_x + vclips_ptr->w + |
|
- | 1798 | dest_x - crtc_x; |
|
- | 1799 | dirty->unit_y2 = dirty->fb_y + vclips_ptr->h + |
|
- | 1800 | dest_y - crtc_y; |
|
- | 1801 | } |
|
- | 1802 | ||
- | 1803 | dirty->unit_x1 = dirty->fb_x + dest_x - crtc_x; |
|
- | 1804 | dirty->unit_y1 = dirty->fb_y + dest_y - crtc_y; |
|
- | 1805 | ||
- | 1806 | /* Skip this clip if it's outside the crtc region */ |
|
- | 1807 | if (dirty->unit_x1 >= crtc_width || |
|
- | 1808 | dirty->unit_y1 >= crtc_height || |
|
- | 1809 | dirty->unit_x2 <= 0 || dirty->unit_y2 <= 0) |
|
- | 1810 | continue; |
|
- | 1811 | ||
- | 1812 | /* Clip right and bottom to crtc limits */ |
|
- | 1813 | dirty->unit_x2 = min_t(s32, dirty->unit_x2, |
|
- | 1814 | crtc_width); |
|
- | 1815 | dirty->unit_y2 = min_t(s32, dirty->unit_y2, |
|
- | 1816 | crtc_height); |
|
- | 1817 | ||
- | 1818 | /* Clip left and top to crtc limits */ |
|
- | 1819 | clip_left = min_t(s32, dirty->unit_x1, 0); |
|
- | 1820 | clip_top = min_t(s32, dirty->unit_y1, 0); |
|
- | 1821 | dirty->unit_x1 -= clip_left; |
|
- | 1822 | dirty->unit_y1 -= clip_top; |
|
- | 1823 | dirty->fb_x -= clip_left; |
|
- | 1824 | dirty->fb_y -= clip_top; |
|
- | 1825 | ||
- | 1826 | dirty->clip(dirty); |
|
- | 1827 | } |
|
- | 1828 | ||
- | 1829 | dirty->fifo_commit(dirty); |
|
- | 1830 | } |
|
- | 1831 | ||
- | 1832 | return 0; |
|
- | 1833 | } |
|
- | 1834 | ||
- | 1835 | /** |
|
- | 1836 | * vmw_kms_helper_buffer_prepare - Reserve and validate a buffer object before |
|
- | 1837 | * command submission. |
|
- | 1838 | * |
|
- | 1839 | * @dev_priv. Pointer to a device private structure. |
|
- | 1840 | * @buf: The buffer object |
|
- | 1841 | * @interruptible: Whether to perform waits as interruptible. |
|
- | 1842 | * @validate_as_mob: Whether the buffer should be validated as a MOB. If false, |
|
- | 1843 | * The buffer will be validated as a GMR. Already pinned buffers will not be |
|
- | 1844 | * validated. |
|
- | 1845 | * |
|
- | 1846 | * Returns 0 on success, negative error code on failure, -ERESTARTSYS if |
|
- | 1847 | * interrupted by a signal. |
|
- | 1848 | */ |
|
- | 1849 | int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, |
|
- | 1850 | struct vmw_dma_buffer *buf, |
|
- | 1851 | bool interruptible, |
|
- | 1852 | bool validate_as_mob) |
|
- | 1853 | { |
|
- | 1854 | struct ttm_buffer_object *bo = &buf->base; |
|
- | 1855 | int ret; |
|
- | 1856 | ||
- | 1857 | ttm_bo_reserve(bo, false, false, interruptible, NULL); |
|
- | 1858 | ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, |
|
- | 1859 | validate_as_mob); |
|
- | 1860 | if (ret) |
|
- | 1861 | ttm_bo_unreserve(bo); |
|
- | 1862 | ||
- | 1863 | return ret; |
|
- | 1864 | } |
|
- | 1865 | ||
- | 1866 | /** |
|
- | 1867 | * vmw_kms_helper_buffer_revert - Undo the actions of |
|
- | 1868 | * vmw_kms_helper_buffer_prepare. |
|
- | 1869 | * |
|
- | 1870 | * @res: Pointer to the buffer object. |
|
- | 1871 | * |
|
- | 1872 | * Helper to be used if an error forces the caller to undo the actions of |
|
- | 1873 | * vmw_kms_helper_buffer_prepare. |
|
- | 1874 | */ |
|
- | 1875 | void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf) |
|
- | 1876 | { |
|
- | 1877 | if (buf) |
|
- | 1878 | ttm_bo_unreserve(&buf->base); |
|
- | 1879 | } |
|
- | 1880 | ||
- | 1881 | /** |
|
- | 1882 | * vmw_kms_helper_buffer_finish - Unreserve and fence a buffer object after |
|
- | 1883 | * kms command submission. |
|
- | 1884 | * |
|
- | 1885 | * @dev_priv: Pointer to a device private structure. |
|
- | 1886 | * @file_priv: Pointer to a struct drm_file representing the caller's |
|
- | 1887 | * connection. Must be set to NULL if @user_fence_rep is NULL, and conversely |
|
- | 1888 | * if non-NULL, @user_fence_rep must be non-NULL. |
|
- | 1889 | * @buf: The buffer object. |
|
- | 1890 | * @out_fence: Optional pointer to a fence pointer. If non-NULL, a |
|
- | 1891 | * ref-counted fence pointer is returned here. |
|
- | 1892 | * @user_fence_rep: Optional pointer to a user-space provided struct |
|
- | 1893 | * drm_vmw_fence_rep. If provided, @file_priv must also be provided and the |
|
- | 1894 | * function copies fence data to user-space in a fail-safe manner. |
|
- | 1895 | */ |
|
- | 1896 | void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, |
|
- | 1897 | struct drm_file *file_priv, |
|
- | 1898 | struct vmw_dma_buffer *buf, |
|
- | 1899 | struct vmw_fence_obj **out_fence, |
|
- | 1900 | struct drm_vmw_fence_rep __user * |
|
- | 1901 | user_fence_rep) |
|
- | 1902 | { |
|
- | 1903 | struct vmw_fence_obj *fence; |
|
- | 1904 | uint32_t handle; |
|
- | 1905 | int ret; |
|
- | 1906 | ||
- | 1907 | ret = vmw_execbuf_fence_commands(file_priv, dev_priv, &fence, |
|
- | 1908 | file_priv ? &handle : NULL); |
|
- | 1909 | if (buf) |
|
- | 1910 | vmw_fence_single_bo(&buf->base, fence); |
|
- | 1911 | if (file_priv) |
|
- | 1912 | vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), |
|
- | 1913 | ret, user_fence_rep, fence, |
|
- | 1914 | handle); |
|
- | 1915 | if (out_fence) |
|
- | 1916 | *out_fence = fence; |
|
- | 1917 | else |
|
- | 1918 | vmw_fence_obj_unreference(&fence); |
|
- | 1919 | ||
- | 1920 | vmw_kms_helper_buffer_revert(buf); |
|
- | 1921 | } |
|
- | 1922 | ||
- | 1923 | ||
- | 1924 | /** |
|
- | 1925 | * vmw_kms_helper_resource_revert - Undo the actions of |
|
- | 1926 | * vmw_kms_helper_resource_prepare. |
|
- | 1927 | * |
|
- | 1928 | * @res: Pointer to the resource. Typically a surface. |
|
- | 1929 | * |
|
- | 1930 | * Helper to be used if an error forces the caller to undo the actions of |
|
- | 1931 | * vmw_kms_helper_resource_prepare. |
|
- | 1932 | */ |
|
- | 1933 | void vmw_kms_helper_resource_revert(struct vmw_resource *res) |
|
- | 1934 | { |
|
- | 1935 | vmw_kms_helper_buffer_revert(res->backup); |
|
- | 1936 | vmw_resource_unreserve(res, false, NULL, 0); |
|
- | 1937 | mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
|
- | 1938 | } |
|
- | 1939 | ||
- | 1940 | /** |
|
- | 1941 | * vmw_kms_helper_resource_prepare - Reserve and validate a resource before |
|
- | 1942 | * command submission. |
|
- | 1943 | * |
|
- | 1944 | * @res: Pointer to the resource. Typically a surface. |
|
- | 1945 | * @interruptible: Whether to perform waits as interruptible. |
|
- | 1946 | * |
|
- | 1947 | * Reserves and validates also the backup buffer if a guest-backed resource. |
|
- | 1948 | * Returns 0 on success, negative error code on failure. -ERESTARTSYS if |
|
- | 1949 | * interrupted by a signal. |
|
- | 1950 | */ |
|
- | 1951 | int vmw_kms_helper_resource_prepare(struct vmw_resource *res, |
|
- | 1952 | bool interruptible) |
|
- | 1953 | { |
|
- | 1954 | int ret = 0; |
|
- | 1955 | ||
- | 1956 | if (interruptible) |
|
- | 1957 | ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex); |
|
- | 1958 | else |
|
- | 1959 | mutex_lock(&res->dev_priv->cmdbuf_mutex); |
|
- | 1960 | ||
- | 1961 | if (unlikely(ret != 0)) |
|
- | 1962 | return -ERESTARTSYS; |
|
- | 1963 | ||
- | 1964 | ret = vmw_resource_reserve(res, interruptible, false); |
|
- | 1965 | if (ret) |
|
- | 1966 | goto out_unlock; |
|
- | 1967 | ||
- | 1968 | if (res->backup) { |
|
- | 1969 | ret = vmw_kms_helper_buffer_prepare(res->dev_priv, res->backup, |
|
- | 1970 | interruptible, |
|
- | 1971 | res->dev_priv->has_mob); |
|
- | 1972 | if (ret) |
|
- | 1973 | goto out_unreserve; |
|
- | 1974 | } |
|
- | 1975 | ret = vmw_resource_validate(res); |
|
- | 1976 | if (ret) |
|
- | 1977 | goto out_revert; |
|
- | 1978 | return 0; |
|
- | 1979 | ||
- | 1980 | out_revert: |
|
- | 1981 | vmw_kms_helper_buffer_revert(res->backup); |
|
- | 1982 | out_unreserve: |
|
- | 1983 | vmw_resource_unreserve(res, false, NULL, 0); |
|
- | 1984 | out_unlock: |
|
- | 1985 | mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
|
- | 1986 | return ret; |
|
- | 1987 | } |
|
- | 1988 | ||
- | 1989 | /** |
|
- | 1990 | * vmw_kms_helper_resource_finish - Unreserve and fence a resource after |
|
- | 1991 | * kms command submission. |
|
- | 1992 | * |
|
- | 1993 | * @res: Pointer to the resource. Typically a surface. |
|
- | 1994 | * @out_fence: Optional pointer to a fence pointer. If non-NULL, a |
|
- | 1995 | * ref-counted fence pointer is returned here. |
|
- | 1996 | */ |
|
- | 1997 | void vmw_kms_helper_resource_finish(struct vmw_resource *res, |
|
- | 1998 | struct vmw_fence_obj **out_fence) |
|
- | 1999 | { |
|
- | 2000 | if (res->backup || out_fence) |
|
- | 2001 | vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup, |
|
- | 2002 | out_fence, NULL); |
|
- | 2003 | ||
- | 2004 | vmw_resource_unreserve(res, false, NULL, 0); |
|
- | 2005 | mutex_unlock(&res->dev_priv->cmdbuf_mutex); |
|
- | 2006 | } |
|
- | 2007 | ||
- | 2008 | /** |
|
- | 2009 | * vmw_kms_update_proxy - Helper function to update a proxy surface from |
|
- | 2010 | * its backing MOB. |
|
- | 2011 | * |
|
- | 2012 | * @res: Pointer to the surface resource |
|
- | 2013 | * @clips: Clip rects in framebuffer (surface) space. |
|
- | 2014 | * @num_clips: Number of clips in @clips. |
|
- | 2015 | * @increment: Integer with which to increment the clip counter when looping. |
|
- | 2016 | * Used to skip a predetermined number of clip rects. |
|
- | 2017 | * |
|
- | 2018 | * This function makes sure the proxy surface is updated from its backing MOB |
|
- | 2019 | * using the region given by @clips. The surface resource @res and its backing |
|
- | 2020 | * MOB needs to be reserved and validated on call. |
|
- | 2021 | */ |
|
- | 2022 | int vmw_kms_update_proxy(struct vmw_resource *res, |
|
- | 2023 | const struct drm_clip_rect *clips, |
|
- | 2024 | unsigned num_clips, |
|
- | 2025 | int increment) |
|
- | 2026 | { |
|
- | 2027 | struct vmw_private *dev_priv = res->dev_priv; |
|
- | 2028 | struct drm_vmw_size *size = &vmw_res_to_srf(res)->base_size; |
|
- | 2029 | struct { |
|
- | 2030 | SVGA3dCmdHeader header; |
|
- | 2031 | SVGA3dCmdUpdateGBImage body; |
|
- | 2032 | } *cmd; |
|
- | 2033 | SVGA3dBox *box; |
|
- | 2034 | size_t copy_size = 0; |
|
- | 2035 | int i; |
|
- | 2036 | ||
- | 2037 | if (!clips) |
|
- | 2038 | return 0; |
|
- | 2039 | ||
- | 2040 | cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips); |
|
- | 2041 | if (!cmd) { |
|
- | 2042 | DRM_ERROR("Couldn't reserve fifo space for proxy surface " |
|
- | 2043 | "update.\n"); |
|
- | 2044 | return -ENOMEM; |
|
- | 2045 | } |
|
- | 2046 | ||
- | 2047 | for (i = 0; i < num_clips; ++i, clips += increment, ++cmd) { |
|
- | 2048 | box = &cmd->body.box; |
|
- | 2049 | ||
- | 2050 | cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; |
|
- | 2051 | cmd->header.size = sizeof(cmd->body); |
|
- | 2052 | cmd->body.image.sid = res->id; |
|
- | 2053 | cmd->body.image.face = 0; |
|
- | 2054 | cmd->body.image.mipmap = 0; |
|
- | 2055 | ||
- | 2056 | if (clips->x1 > size->width || clips->x2 > size->width || |
|
- | 2057 | clips->y1 > size->height || clips->y2 > size->height) { |
|
- | 2058 | DRM_ERROR("Invalid clips outsize of framebuffer.\n"); |
|
- | 2059 | return -EINVAL; |
|
- | 2060 | } |
|
- | 2061 | ||
- | 2062 | box->x = clips->x1; |
|
- | 2063 | box->y = clips->y1; |
|
- | 2064 | box->z = 0; |
|
- | 2065 | box->w = clips->x2 - clips->x1; |
|
- | 2066 | box->h = clips->y2 - clips->y1; |
|
- | 2067 | box->d = 1; |
|
- | 2068 | ||
- | 2069 | copy_size += sizeof(*cmd); |
|
- | 2070 | } |
|
- | 2071 | ||
- | 2072 | vmw_fifo_commit(dev_priv, copy_size); |
|
- | 2073 | ||
- | 2074 | return 0; |
|
- | 2075 | } |
|
- | 2076 | ||
- | 2077 | int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, |
|
- | 2078 | unsigned unit, |
|
- | 2079 | u32 max_width, |
|
- | 2080 | u32 max_height, |
|
- | 2081 | struct drm_connector **p_con, |
|
- | 2082 | struct drm_crtc **p_crtc, |
|
- | 2083 | struct drm_display_mode **p_mode) |
|
- | 2084 | { |
|
- | 2085 | struct drm_connector *con; |
|
- | 2086 | struct vmw_display_unit *du; |
|
- | 2087 | struct drm_display_mode *mode; |
|
- | 2088 | int i = 0; |
|
- | 2089 | ||
- | 2090 | list_for_each_entry(con, &dev_priv->dev->mode_config.connector_list, |
|
- | 2091 | head) { |
|
- | 2092 | if (i == unit) |
|
- | 2093 | break; |
|
- | 2094 | ||
- | 2095 | ++i; |
|
- | 2096 | } |
|
- | 2097 | ||
- | 2098 | if (i != unit) { |
|
- | 2099 | DRM_ERROR("Could not find initial display unit.\n"); |
|
- | 2100 | return -EINVAL; |
|
- | 2101 | } |
|
- | 2102 | ||
- | 2103 | if (list_empty(&con->modes)) |
|
- | 2104 | (void) vmw_du_connector_fill_modes(con, max_width, max_height); |
|
- | 2105 | ||
- | 2106 | if (list_empty(&con->modes)) { |
|
- | 2107 | DRM_ERROR("Could not find initial display mode.\n"); |
|
- | 2108 | return -EINVAL; |
|
- | 2109 | } |
|
- | 2110 | ||
- | 2111 | du = vmw_connector_to_du(con); |
|
- | 2112 | *p_con = con; |
|
- | 2113 | *p_crtc = &du->crtc; |
|
- | 2114 | ||
- | 2115 | list_for_each_entry(mode, &con->modes, head) { |
|
- | 2116 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
|
- | 2117 | break; |
|
- | 2118 | } |
|
- | 2119 | ||
- | 2120 | if (mode->type & DRM_MODE_TYPE_PREFERRED) |
|
- | 2121 | *p_mode = mode; |
|
- | 2122 | else { |
|
- | 2123 | WARN_ONCE(true, "Could not find initial preferred mode.\n"); |
|
- | 2124 | *p_mode = list_first_entry(&con->modes, |
|
- | 2125 | struct drm_display_mode, |
|
- | 2126 | head); |
|
- | 2127 | } |
|
- | 2128 |