Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux: (40 commits)
  vmwgfx: Snoop DMA transfers with non-covering sizes
  vmwgfx: Move the prefered mode first in the list
  vmwgfx: Unreference surface on cursor error path
  vmwgfx: Free prefered mode on error path
  vmwgfx: Use pointer return error codes
  vmwgfx: Fix hw cursor position
  vmwgfx: Infrastructure for explicit placement
  vmwgfx: Make the preferred autofit mode have a 60Hz vrefresh
  vmwgfx: Remove screen object active list
  vmwgfx: Screen object cleanups
  drm/radeon/kms: consolidate GART code, fix segfault after GPU lockup V2
  drm/radeon/kms: don't poll forever if MC GDDR link training fails
  drm/radeon/kms: fix DP setup on TRAVIS bridges
  drm/radeon/kms: set HPD polarity in hpd_init()
  drm/radeon/kms: add MSI module parameter
  drm/radeon/kms: Add MSI quirk for Dell RS690
  drm/radeon/kms: Add MSI quirk for HP RS690
  drm/radeon/kms: split MSI check into a separate function
  vmwgfx: Reinstate the update_layout ioctl
  drm/radeon/kms: always do extended edid probe
  ...
This commit is contained in:
Linus Torvalds
2011-11-07 10:01:56 -08:00
33 changed files with 2950 additions and 2659 deletions

View File

@@ -104,6 +104,9 @@
#define DRM_IOCTL_VMW_PRESENT_READBACK \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK, \
struct drm_vmw_present_readback_arg)
#define DRM_IOCTL_VMW_UPDATE_LAYOUT \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \
struct drm_vmw_update_layout_arg)
/**
* The core DRM version of this macro doesn't account for
@@ -166,6 +169,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
VMW_IOCTL_DEF(VMW_PRESENT_READBACK,
vmw_present_readback_ioctl,
DRM_MASTER | DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT,
vmw_kms_update_layout_ioctl,
DRM_MASTER | DRM_UNLOCKED),
};
static struct pci_device_id vmw_pci_id_list[] = {

View File

@@ -40,9 +40,9 @@
#include "ttm/ttm_module.h"
#include "vmwgfx_fence.h"
#define VMWGFX_DRIVER_DATE "20111008"
#define VMWGFX_DRIVER_DATE "20111025"
#define VMWGFX_DRIVER_MAJOR 2
#define VMWGFX_DRIVER_MINOR 2
#define VMWGFX_DRIVER_MINOR 3
#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -633,6 +633,8 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
struct drm_vmw_fence_rep __user *user_fence_rep,
struct drm_vmw_rect *clips,
uint32_t num_clips);
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/**
* Overlay control - vmwgfx_overlay.c

View File

@@ -111,6 +111,7 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
if (!ret) {
if (!surface->snooper.image) {
DRM_ERROR("surface not suitable for cursor\n");
vmw_surface_unreference(&surface);
return -EINVAL;
}
} else {
@@ -176,7 +177,9 @@ err_unreserve:
return 0;
}
vmw_cursor_update_position(dev_priv, true, du->cursor_x, du->cursor_y);
vmw_cursor_update_position(dev_priv, true,
du->cursor_x + du->hotspot_x,
du->cursor_y + du->hotspot_y);
return 0;
}
@@ -191,7 +194,8 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
du->cursor_y = y + crtc->y;
vmw_cursor_update_position(dev_priv, shown,
du->cursor_x, du->cursor_y);
du->cursor_x + du->hotspot_x,
du->cursor_y + du->hotspot_y);
return 0;
}
@@ -212,7 +216,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
SVGA3dCmdHeader header;
SVGA3dCmdSurfaceDMA dma;
} *cmd;
int ret;
int i, ret;
cmd = container_of(header, struct vmw_dma_cmd, header);
@@ -234,16 +238,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) /
sizeof(SVGA3dCopyBox);
if (cmd->dma.guest.pitch != (64 * 4) ||
cmd->dma.guest.ptr.offset % PAGE_SIZE ||
if (cmd->dma.guest.ptr.offset % PAGE_SIZE ||
box->x != 0 || box->y != 0 || box->z != 0 ||
box->srcx != 0 || box->srcy != 0 || box->srcz != 0 ||
box->w != 64 || box->h != 64 || box->d != 1 ||
box_count != 1) {
box->d != 1 || box_count != 1) {
/* TODO handle none page aligned offsets */
/* TODO handle partial uploads and pitch != 256 */
/* TODO handle more then one copy (size != 64) */
DRM_ERROR("lazy programmer, can't handle weird stuff\n");
/* TODO handle more dst & src != 0 */
/* TODO handle more then one copy */
DRM_ERROR("Cant snoop dma request for cursor!\n");
DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n",
box->srcx, box->srcy, box->srcz,
box->x, box->y, box->z,
box->w, box->h, box->d, box_count,
cmd->dma.guest.ptr.offset);
return;
}
@@ -262,7 +269,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
virtual = ttm_kmap_obj_virtual(&map, &dummy);
memcpy(srf->snooper.image, virtual, 64*64*4);
if (box->w == 64 && cmd->dma.guest.pitch == 64*4) {
memcpy(srf->snooper.image, virtual, 64*64*4);
} else {
/* Image is unsigned pointer. */
for (i = 0; i < box->h; i++)
memcpy(srf->snooper.image + i * 64,
virtual + i * cmd->dma.guest.pitch,
box->w * 4);
}
srf->snooper.age++;
/* we can't call this function from this function since execbuf has
@@ -994,7 +1010,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
required_size = mode_cmd->pitch * mode_cmd->height;
if (unlikely(required_size > (u64) dev_priv->vram_size)) {
DRM_ERROR("VRAM size is too small for requested mode.\n");
return NULL;
return ERR_PTR(-ENOMEM);
}
/*
@@ -1517,6 +1533,8 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
du->pref_width = rects[du->unit].w;
du->pref_height = rects[du->unit].h;
du->pref_active = true;
du->gui_x = rects[du->unit].x;
du->gui_y = rects[du->unit].y;
} else {
du->pref_width = 800;
du->pref_height = 600;
@@ -1572,12 +1590,14 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force)
uint32_t num_displays;
struct drm_device *dev = connector->dev;
struct vmw_private *dev_priv = vmw_priv(dev);
struct vmw_display_unit *du = vmw_connector_to_du(connector);
mutex_lock(&dev_priv->hw_mutex);
num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS);
mutex_unlock(&dev_priv->hw_mutex);
return ((vmw_connector_to_du(connector)->unit < num_displays) ?
return ((vmw_connector_to_du(connector)->unit < num_displays &&
du->pref_active) ?
connector_status_connected : connector_status_disconnected);
}
@@ -1658,6 +1678,28 @@ static struct drm_display_mode vmw_kms_connector_builtin[] = {
{ DRM_MODE("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) },
};
/**
* vmw_guess_mode_timing - Provide fake timings for a
* 60Hz vrefresh mode.
*
* @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay
* members filled in.
*/
static void vmw_guess_mode_timing(struct drm_display_mode *mode)
{
mode->hsync_start = mode->hdisplay + 50;
mode->hsync_end = mode->hsync_start + 50;
mode->htotal = mode->hsync_end + 50;
mode->vsync_start = mode->vdisplay + 50;
mode->vsync_end = mode->vsync_start + 50;
mode->vtotal = mode->vsync_end + 50;
mode->clock = (u32)mode->htotal * (u32)mode->vtotal / 100 * 6;
mode->vrefresh = drm_mode_vrefresh(mode);
}
int vmw_du_connector_fill_modes(struct drm_connector *connector,
uint32_t max_width, uint32_t max_height)
{
@@ -1680,18 +1722,23 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
return 0;
mode->hdisplay = du->pref_width;
mode->vdisplay = du->pref_height;
mode->vrefresh = drm_mode_vrefresh(mode);
vmw_guess_mode_timing(mode);
if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2,
mode->vdisplay)) {
drm_mode_probed_add(connector, mode);
if (du->pref_mode) {
list_del_init(&du->pref_mode->head);
drm_mode_destroy(dev, du->pref_mode);
}
du->pref_mode = mode;
} else {
drm_mode_destroy(dev, mode);
mode = NULL;
}
if (du->pref_mode) {
list_del_init(&du->pref_mode->head);
drm_mode_destroy(dev, du->pref_mode);
}
/* mode might be null here, this is intended */
du->pref_mode = mode;
}
for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) {
@@ -1712,6 +1759,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
drm_mode_probed_add(connector, mode);
}
/* Move the prefered mode first, help apps pick the right mode. */
if (du->pref_mode)
list_move(&du->pref_mode->head, &connector->probed_modes);
drm_mode_connector_list_update(connector);
return 1;
@@ -1723,3 +1774,63 @@ int vmw_du_connector_set_property(struct drm_connector *connector,
{
return 0;
}
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct drm_vmw_update_layout_arg *arg =
(struct drm_vmw_update_layout_arg *)data;
struct vmw_master *vmaster = vmw_master(file_priv->master);
void __user *user_rects;
struct drm_vmw_rect *rects;
unsigned rects_size;
int ret;
int i;
struct drm_mode_config *mode_config = &dev->mode_config;
ret = ttm_read_lock(&vmaster->lock, true);
if (unlikely(ret != 0))
return ret;
if (!arg->num_outputs) {
struct drm_vmw_rect def_rect = {0, 0, 800, 600};
vmw_du_update_layout(dev_priv, 1, &def_rect);
goto out_unlock;
}
rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
rects = kzalloc(rects_size, GFP_KERNEL);
if (unlikely(!rects)) {
ret = -ENOMEM;
goto out_unlock;
}
user_rects = (void __user *)(unsigned long)arg->rects;
ret = copy_from_user(rects, user_rects, rects_size);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed to get rects.\n");
ret = -EFAULT;
goto out_free;
}
for (i = 0; i < arg->num_outputs; ++i) {
if (rects->x < 0 ||
rects->y < 0 ||
rects->x + rects->w > mode_config->max_width ||
rects->y + rects->h > mode_config->max_height) {
DRM_ERROR("Invalid GUI layout.\n");
ret = -EINVAL;
goto out_free;
}
}
vmw_du_update_layout(dev_priv, arg->num_outputs, rects);
out_free:
kfree(rects);
out_unlock:
ttm_read_unlock(&vmaster->lock);
return ret;
}

View File

@@ -96,6 +96,13 @@ struct vmw_display_unit {
unsigned pref_height;
bool pref_active;
struct drm_display_mode *pref_mode;
/*
* Gui positioning
*/
int gui_x;
int gui_y;
bool is_implicit;
};
#define vmw_crtc_to_du(x) \
@@ -126,8 +133,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector,
int vmw_du_connector_set_property(struct drm_connector *connector,
struct drm_property *property,
uint64_t val);
int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
struct drm_vmw_rect *rects);
/*
* Legacy display unit functions - vmwgfx_ldu.c

View File

@@ -337,13 +337,14 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
ldu->base.pref_width = 800;
ldu->base.pref_height = 600;
ldu->base.pref_mode = NULL;
ldu->base.is_implicit = true;
drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
DRM_MODE_CONNECTOR_VIRTUAL);
connector->status = vmw_du_connector_detect(connector, true);
drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
DRM_MODE_ENCODER_LVDS);
DRM_MODE_ENCODER_VIRTUAL);
drm_mode_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = (1 << unit);
encoder->possible_clones = 0;

View File

@@ -36,12 +36,9 @@
container_of(x, struct vmw_screen_object_unit, base.connector)
struct vmw_screen_object_display {
struct list_head active;
unsigned num_implicit;
unsigned num_active;
unsigned last_num_active;
struct vmw_framebuffer *fb;
struct vmw_framebuffer *implicit_fb;
};
/**
@@ -54,13 +51,11 @@ struct vmw_screen_object_unit {
struct vmw_dma_buffer *buffer; /**< Backing store buffer */
bool defined;
struct list_head active;
bool active_implicit;
};
static void vmw_sou_destroy(struct vmw_screen_object_unit *sou)
{
list_del_init(&sou->active);
vmw_display_unit_cleanup(&sou->base);
kfree(sou);
}
@@ -75,58 +70,31 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc)
vmw_sou_destroy(vmw_crtc_to_sou(crtc));
}
static int vmw_sou_del_active(struct vmw_private *vmw_priv,
static void vmw_sou_del_active(struct vmw_private *vmw_priv,
struct vmw_screen_object_unit *sou)
{
struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
if (list_empty(&sou->active))
return 0;
/* Must init otherwise list_empty(&sou->active) will not work. */
list_del_init(&sou->active);
if (--(ld->num_active) == 0) {
BUG_ON(!ld->fb);
if (ld->fb->unpin)
ld->fb->unpin(ld->fb);
ld->fb = NULL;
if (sou->active_implicit) {
if (--(ld->num_implicit) == 0)
ld->implicit_fb = NULL;
sou->active_implicit = false;
}
return 0;
}
static int vmw_sou_add_active(struct vmw_private *vmw_priv,
static void vmw_sou_add_active(struct vmw_private *vmw_priv,
struct vmw_screen_object_unit *sou,
struct vmw_framebuffer *vfb)
{
struct vmw_screen_object_display *ld = vmw_priv->sou_priv;
struct vmw_screen_object_unit *entry;
struct list_head *at;
BUG_ON(!ld->num_active && ld->fb);
if (vfb != ld->fb) {
if (ld->fb && ld->fb->unpin)
ld->fb->unpin(ld->fb);
if (vfb->pin)
vfb->pin(vfb);
ld->fb = vfb;
BUG_ON(!ld->num_implicit && ld->implicit_fb);
if (!sou->active_implicit && sou->base.is_implicit) {
ld->implicit_fb = vfb;
sou->active_implicit = true;
ld->num_implicit++;
}
if (!list_empty(&sou->active))
return 0;
at = &ld->active;
list_for_each_entry(entry, &ld->active, active) {
if (entry->base.unit > sou->base.unit)
break;
at = &entry->active;
}
list_add(&sou->active, at);
ld->num_active++;
return 0;
}
/**
@@ -164,8 +132,13 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv,
(sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0);
cmd->obj.size.width = mode->hdisplay;
cmd->obj.size.height = mode->vdisplay;
cmd->obj.root.x = x;
cmd->obj.root.y = y;
if (sou->base.is_implicit) {
cmd->obj.root.x = x;
cmd->obj.root.y = y;
} else {
cmd->obj.root.x = sou->base.gui_x;
cmd->obj.root.y = sou->base.gui_y;
}
/* Ok to assume that buffer is pinned in vram */
vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr);
@@ -312,10 +285,11 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
}
/* sou only supports one fb active at the time */
if (dev_priv->sou_priv->fb && vfb &&
!(dev_priv->sou_priv->num_active == 1 &&
!list_empty(&sou->active)) &&
dev_priv->sou_priv->fb != vfb) {
if (sou->base.is_implicit &&
dev_priv->sou_priv->implicit_fb && vfb &&
!(dev_priv->sou_priv->num_implicit == 1 &&
sou->active_implicit) &&
dev_priv->sou_priv->implicit_fb != vfb) {
DRM_ERROR("Multiple framebuffers not supported\n");
return -EINVAL;
}
@@ -471,19 +445,20 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit)
encoder = &sou->base.encoder;
connector = &sou->base.connector;
INIT_LIST_HEAD(&sou->active);
sou->active_implicit = false;
sou->base.pref_active = (unit == 0);
sou->base.pref_width = 800;
sou->base.pref_height = 600;
sou->base.pref_mode = NULL;
sou->base.is_implicit = true;
drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
DRM_MODE_CONNECTOR_VIRTUAL);
connector->status = vmw_du_connector_detect(connector, true);
drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs,
DRM_MODE_ENCODER_LVDS);
DRM_MODE_ENCODER_VIRTUAL);
drm_mode_connector_attach_encoder(connector, encoder);
encoder->possible_crtcs = (1 << unit);
encoder->possible_clones = 0;
@@ -520,10 +495,8 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv)
if (unlikely(!dev_priv->sou_priv))
goto err_no_mem;
INIT_LIST_HEAD(&dev_priv->sou_priv->active);
dev_priv->sou_priv->num_active = 0;
dev_priv->sou_priv->last_num_active = 0;
dev_priv->sou_priv->fb = NULL;
dev_priv->sou_priv->num_implicit = 0;
dev_priv->sou_priv->implicit_fb = NULL;
ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
if (unlikely(ret != 0))
@@ -558,9 +531,6 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv)
drm_vblank_cleanup(dev);
if (!list_empty(&dev_priv->sou_priv->active))
DRM_ERROR("Still have active outputs when unloading driver");
kfree(dev_priv->sou_priv);
return 0;