aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_kms.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c166
1 files changed, 143 insertions, 23 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 8b14dfd513a..37d40545ed7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -105,12 +105,17 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
105 struct vmw_dma_buffer *dmabuf = NULL; 105 struct vmw_dma_buffer *dmabuf = NULL;
106 int ret; 106 int ret;
107 107
108 /* A lot of the code assumes this */
109 if (handle && (width != 64 || height != 64))
110 return -EINVAL;
111
108 if (handle) { 112 if (handle) {
109 ret = vmw_user_surface_lookup_handle(dev_priv, tfile, 113 ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
110 handle, &surface); 114 handle, &surface);
111 if (!ret) { 115 if (!ret) {
112 if (!surface->snooper.image) { 116 if (!surface->snooper.image) {
113 DRM_ERROR("surface not suitable for cursor\n"); 117 DRM_ERROR("surface not suitable for cursor\n");
118 vmw_surface_unreference(&surface);
114 return -EINVAL; 119 return -EINVAL;
115 } 120 }
116 } else { 121 } else {
@@ -176,7 +181,9 @@ err_unreserve:
176 return 0; 181 return 0;
177 } 182 }
178 183
179 vmw_cursor_update_position(dev_priv, true, du->cursor_x, du->cursor_y); 184 vmw_cursor_update_position(dev_priv, true,
185 du->cursor_x + du->hotspot_x,
186 du->cursor_y + du->hotspot_y);
180 187
181 return 0; 188 return 0;
182} 189}
@@ -191,7 +198,8 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
191 du->cursor_y = y + crtc->y; 198 du->cursor_y = y + crtc->y;
192 199
193 vmw_cursor_update_position(dev_priv, shown, 200 vmw_cursor_update_position(dev_priv, shown,
194 du->cursor_x, du->cursor_y); 201 du->cursor_x + du->hotspot_x,
202 du->cursor_y + du->hotspot_y);
195 203
196 return 0; 204 return 0;
197} 205}
@@ -212,7 +220,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
212 SVGA3dCmdHeader header; 220 SVGA3dCmdHeader header;
213 SVGA3dCmdSurfaceDMA dma; 221 SVGA3dCmdSurfaceDMA dma;
214 } *cmd; 222 } *cmd;
215 int ret; 223 int i, ret;
216 224
217 cmd = container_of(header, struct vmw_dma_cmd, header); 225 cmd = container_of(header, struct vmw_dma_cmd, header);
218 226
@@ -234,16 +242,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
234 box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / 242 box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) /
235 sizeof(SVGA3dCopyBox); 243 sizeof(SVGA3dCopyBox);
236 244
237 if (cmd->dma.guest.pitch != (64 * 4) || 245 if (cmd->dma.guest.ptr.offset % PAGE_SIZE ||
238 cmd->dma.guest.ptr.offset % PAGE_SIZE ||
239 box->x != 0 || box->y != 0 || box->z != 0 || 246 box->x != 0 || box->y != 0 || box->z != 0 ||
240 box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || 247 box->srcx != 0 || box->srcy != 0 || box->srcz != 0 ||
241 box->w != 64 || box->h != 64 || box->d != 1 || 248 box->d != 1 || box_count != 1) {
242 box_count != 1) {
243 /* TODO handle none page aligned offsets */ 249 /* TODO handle none page aligned offsets */
244 /* TODO handle partial uploads and pitch != 256 */ 250 /* TODO handle more dst & src != 0 */
245 /* TODO handle more then one copy (size != 64) */ 251 /* TODO handle more then one copy */
246 DRM_ERROR("lazy programmer, can't handle weird stuff\n"); 252 DRM_ERROR("Cant snoop dma request for cursor!\n");
253 DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n",
254 box->srcx, box->srcy, box->srcz,
255 box->x, box->y, box->z,
256 box->w, box->h, box->d, box_count,
257 cmd->dma.guest.ptr.offset);
247 return; 258 return;
248 } 259 }
249 260
@@ -262,7 +273,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
262 273
263 virtual = ttm_kmap_obj_virtual(&map, &dummy); 274 virtual = ttm_kmap_obj_virtual(&map, &dummy);
264 275
265 memcpy(srf->snooper.image, virtual, 64*64*4); 276 if (box->w == 64 && cmd->dma.guest.pitch == 64*4) {
277 memcpy(srf->snooper.image, virtual, 64*64*4);
278 } else {
279 /* Image is unsigned pointer. */
280 for (i = 0; i < box->h; i++)
281 memcpy(srf->snooper.image + i * 64,
282 virtual + i * cmd->dma.guest.pitch,
283 box->w * 4);
284 }
285
266 srf->snooper.age++; 286 srf->snooper.age++;
267 287
268 /* we can't call this function from this function since execbuf has 288 /* we can't call this function from this function since execbuf has
@@ -394,8 +414,9 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
394 top = clips->y1; 414 top = clips->y1;
395 bottom = clips->y2; 415 bottom = clips->y2;
396 416
397 clips_ptr = clips; 417 /* skip the first clip rect */
398 for (i = 1; i < num_clips; i++, clips_ptr += inc) { 418 for (i = 1, clips_ptr = clips + inc;
419 i < num_clips; i++, clips_ptr += inc) {
399 left = min_t(int, left, (int)clips_ptr->x1); 420 left = min_t(int, left, (int)clips_ptr->x1);
400 right = max_t(int, right, (int)clips_ptr->x2); 421 right = max_t(int, right, (int)clips_ptr->x2);
401 top = min_t(int, top, (int)clips_ptr->y1); 422 top = min_t(int, top, (int)clips_ptr->y1);
@@ -994,7 +1015,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
994 required_size = mode_cmd->pitch * mode_cmd->height; 1015 required_size = mode_cmd->pitch * mode_cmd->height;
995 if (unlikely(required_size > (u64) dev_priv->vram_size)) { 1016 if (unlikely(required_size > (u64) dev_priv->vram_size)) {
996 DRM_ERROR("VRAM size is too small for requested mode.\n"); 1017 DRM_ERROR("VRAM size is too small for requested mode.\n");
997 return NULL; 1018 return ERR_PTR(-ENOMEM);
998 } 1019 }
999 1020
1000 /* 1021 /*
@@ -1307,7 +1328,10 @@ int vmw_kms_close(struct vmw_private *dev_priv)
1307 * drm_encoder_cleanup which takes the lock we deadlock. 1328 * drm_encoder_cleanup which takes the lock we deadlock.
1308 */ 1329 */
1309 drm_mode_config_cleanup(dev_priv->dev); 1330 drm_mode_config_cleanup(dev_priv->dev);
1310 vmw_kms_close_legacy_display_system(dev_priv); 1331 if (dev_priv->sou_priv)
1332 vmw_kms_close_screen_object_display(dev_priv);
1333 else
1334 vmw_kms_close_legacy_display_system(dev_priv);
1311 return 0; 1335 return 0;
1312} 1336}
1313 1337
@@ -1517,6 +1541,8 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
1517 du->pref_width = rects[du->unit].w; 1541 du->pref_width = rects[du->unit].w;
1518 du->pref_height = rects[du->unit].h; 1542 du->pref_height = rects[du->unit].h;
1519 du->pref_active = true; 1543 du->pref_active = true;
1544 du->gui_x = rects[du->unit].x;
1545 du->gui_y = rects[du->unit].y;
1520 } else { 1546 } else {
1521 du->pref_width = 800; 1547 du->pref_width = 800;
1522 du->pref_height = 600; 1548 du->pref_height = 600;
@@ -1572,12 +1598,14 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force)
1572 uint32_t num_displays; 1598 uint32_t num_displays;
1573 struct drm_device *dev = connector->dev; 1599 struct drm_device *dev = connector->dev;
1574 struct vmw_private *dev_priv = vmw_priv(dev); 1600 struct vmw_private *dev_priv = vmw_priv(dev);
1601 struct vmw_display_unit *du = vmw_connector_to_du(connector);
1575 1602
1576 mutex_lock(&dev_priv->hw_mutex); 1603 mutex_lock(&dev_priv->hw_mutex);
1577 num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); 1604 num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS);
1578 mutex_unlock(&dev_priv->hw_mutex); 1605 mutex_unlock(&dev_priv->hw_mutex);
1579 1606
1580 return ((vmw_connector_to_du(connector)->unit < num_displays) ? 1607 return ((vmw_connector_to_du(connector)->unit < num_displays &&
1608 du->pref_active) ?
1581 connector_status_connected : connector_status_disconnected); 1609 connector_status_connected : connector_status_disconnected);
1582} 1610}
1583 1611
@@ -1658,6 +1686,28 @@ static struct drm_display_mode vmw_kms_connector_builtin[] = {
1658 { DRM_MODE("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }, 1686 { DRM_MODE("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) },
1659}; 1687};
1660 1688
1689/**
1690 * vmw_guess_mode_timing - Provide fake timings for a
1691 * 60Hz vrefresh mode.
1692 *
1693 * @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay
1694 * members filled in.
1695 */
1696static void vmw_guess_mode_timing(struct drm_display_mode *mode)
1697{
1698 mode->hsync_start = mode->hdisplay + 50;
1699 mode->hsync_end = mode->hsync_start + 50;
1700 mode->htotal = mode->hsync_end + 50;
1701
1702 mode->vsync_start = mode->vdisplay + 50;
1703 mode->vsync_end = mode->vsync_start + 50;
1704 mode->vtotal = mode->vsync_end + 50;
1705
1706 mode->clock = (u32)mode->htotal * (u32)mode->vtotal / 100 * 6;
1707 mode->vrefresh = drm_mode_vrefresh(mode);
1708}
1709
1710
1661int vmw_du_connector_fill_modes(struct drm_connector *connector, 1711int vmw_du_connector_fill_modes(struct drm_connector *connector,
1662 uint32_t max_width, uint32_t max_height) 1712 uint32_t max_width, uint32_t max_height)
1663{ 1713{
@@ -1680,18 +1730,23 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
1680 return 0; 1730 return 0;
1681 mode->hdisplay = du->pref_width; 1731 mode->hdisplay = du->pref_width;
1682 mode->vdisplay = du->pref_height; 1732 mode->vdisplay = du->pref_height;
1683 mode->vrefresh = drm_mode_vrefresh(mode); 1733 vmw_guess_mode_timing(mode);
1734
1684 if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2, 1735 if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2,
1685 mode->vdisplay)) { 1736 mode->vdisplay)) {
1686 drm_mode_probed_add(connector, mode); 1737 drm_mode_probed_add(connector, mode);
1738 } else {
1739 drm_mode_destroy(dev, mode);
1740 mode = NULL;
1741 }
1687 1742
1688 if (du->pref_mode) { 1743 if (du->pref_mode) {
1689 list_del_init(&du->pref_mode->head); 1744 list_del_init(&du->pref_mode->head);
1690 drm_mode_destroy(dev, du->pref_mode); 1745 drm_mode_destroy(dev, du->pref_mode);
1691 }
1692
1693 du->pref_mode = mode;
1694 } 1746 }
1747
1748 /* mode might be null here, this is intended */
1749 du->pref_mode = mode;
1695 } 1750 }
1696 1751
1697 for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { 1752 for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) {
@@ -1712,6 +1767,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
1712 drm_mode_probed_add(connector, mode); 1767 drm_mode_probed_add(connector, mode);
1713 } 1768 }
1714 1769
1770 /* Move the prefered mode first, help apps pick the right mode. */
1771 if (du->pref_mode)
1772 list_move(&du->pref_mode->head, &connector->probed_modes);
1773
1715 drm_mode_connector_list_update(connector); 1774 drm_mode_connector_list_update(connector);
1716 1775
1717 return 1; 1776 return 1;
@@ -1723,3 +1782,64 @@ int vmw_du_connector_set_property(struct drm_connector *connector,
1723{ 1782{
1724 return 0; 1783 return 0;
1725} 1784}
1785
1786
1787int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
1788 struct drm_file *file_priv)
1789{
1790 struct vmw_private *dev_priv = vmw_priv(dev);
1791 struct drm_vmw_update_layout_arg *arg =
1792 (struct drm_vmw_update_layout_arg *)data;
1793 struct vmw_master *vmaster = vmw_master(file_priv->master);
1794 void __user *user_rects;
1795 struct drm_vmw_rect *rects;
1796 unsigned rects_size;
1797 int ret;
1798 int i;
1799 struct drm_mode_config *mode_config = &dev->mode_config;
1800
1801 ret = ttm_read_lock(&vmaster->lock, true);
1802 if (unlikely(ret != 0))
1803 return ret;
1804
1805 if (!arg->num_outputs) {
1806 struct drm_vmw_rect def_rect = {0, 0, 800, 600};
1807 vmw_du_update_layout(dev_priv, 1, &def_rect);
1808 goto out_unlock;
1809 }
1810
1811 rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
1812 rects = kcalloc(arg->num_outputs, sizeof(struct drm_vmw_rect),
1813 GFP_KERNEL);
1814 if (unlikely(!rects)) {
1815 ret = -ENOMEM;
1816 goto out_unlock;
1817 }
1818
1819 user_rects = (void __user *)(unsigned long)arg->rects;
1820 ret = copy_from_user(rects, user_rects, rects_size);
1821 if (unlikely(ret != 0)) {
1822 DRM_ERROR("Failed to get rects.\n");
1823 ret = -EFAULT;
1824 goto out_free;
1825 }
1826
1827 for (i = 0; i < arg->num_outputs; ++i) {
1828 if (rects[i].x < 0 ||
1829 rects[i].y < 0 ||
1830 rects[i].x + rects[i].w > mode_config->max_width ||
1831 rects[i].y + rects[i].h > mode_config->max_height) {
1832 DRM_ERROR("Invalid GUI layout.\n");
1833 ret = -EINVAL;
1834 goto out_free;
1835 }
1836 }
1837
1838 vmw_du_update_layout(dev_priv, arg->num_outputs, rects);
1839
1840out_free:
1841 kfree(rects);
1842out_unlock:
1843 ttm_read_unlock(&vmaster->lock);
1844 return ret;
1845}