Commit 4c44323d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/i915: lock correct mutex around object unreference.
  drm/i915: add support for physical memory objects
  drm/i915: make LVDS fixed mode a preferred mode
  drm: handle depth & bpp changes correctly
  drm: initial KMS config fixes
  drm/i915: setup sarea properly in master_priv
  drm/i915: set vblank enabled flag correctly across IRQ install/uninstall
  drm/i915: don't enable vblanks on disabled pipes
parents 50246dd4 34b8686e
This diff is collapsed.
...@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install); ...@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install);
*/ */
int drm_irq_uninstall(struct drm_device * dev) int drm_irq_uninstall(struct drm_device * dev)
{ {
int irq_enabled; unsigned long irqflags;
int irq_enabled, i;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL; return -EINVAL;
...@@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev) ...@@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev)
dev->irq_enabled = 0; dev->irq_enabled = 0;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
/*
* Wake up any waiters so they don't hang.
*/
spin_lock_irqsave(&dev->vbl_lock, irqflags);
for (i = 0; i < dev->num_crtcs; i++) {
DRM_WAKEUP(&dev->vbl_queue[i]);
dev->vblank_enabled[i] = 0;
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
if (!irq_enabled) if (!irq_enabled)
return -EINVAL; return -EINVAL;
...@@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, ...@@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
vblwait->request.sequence, crtc); vblwait->request.sequence, crtc);
dev->last_vblank_wait[crtc] = vblwait->request.sequence; dev->last_vblank_wait[crtc] = vblwait->request.sequence;
DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
((drm_vblank_count(dev, crtc) (((drm_vblank_count(dev, crtc) -
- vblwait->request.sequence) <= (1 << 23))); vblwait->request.sequence) <= (1 << 23)) ||
!dev->irq_enabled));
if (ret != -EINTR) { if (ret != -EINTR) {
struct timeval now; struct timeval now;
......
...@@ -177,6 +177,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) ...@@ -177,6 +177,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
master_priv->sarea = drm_getsarea(dev);
if (master_priv->sarea) {
master_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
} else {
DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
}
if (init->ring_size != 0) { if (init->ring_size != 0) {
if (dev_priv->ring.ring_obj != NULL) { if (dev_priv->ring.ring_obj != NULL) {
i915_dma_cleanup(dev); i915_dma_cleanup(dev);
...@@ -1152,6 +1160,8 @@ int i915_driver_unload(struct drm_device *dev) ...@@ -1152,6 +1160,8 @@ int i915_driver_unload(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_modeset_cleanup(dev); intel_modeset_cleanup(dev);
i915_gem_free_all_phys_object(dev);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev); i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
......
...@@ -72,6 +72,18 @@ enum pipe { ...@@ -72,6 +72,18 @@ enum pipe {
#define WATCH_INACTIVE 0 #define WATCH_INACTIVE 0
#define WATCH_PWRITE 0 #define WATCH_PWRITE 0
#define I915_GEM_PHYS_CURSOR_0 1
#define I915_GEM_PHYS_CURSOR_1 2
#define I915_GEM_PHYS_OVERLAY_REGS 3
#define I915_MAX_PHYS_OBJECT (I915_GEM_PHYS_OVERLAY_REGS)
struct drm_i915_gem_phys_object {
int id;
struct page **page_list;
drm_dma_handle_t *handle;
struct drm_gem_object *cur_obj;
};
typedef struct _drm_i915_ring_buffer { typedef struct _drm_i915_ring_buffer {
int tail_mask; int tail_mask;
unsigned long Size; unsigned long Size;
...@@ -358,6 +370,9 @@ typedef struct drm_i915_private { ...@@ -358,6 +370,9 @@ typedef struct drm_i915_private {
uint32_t bit_6_swizzle_x; uint32_t bit_6_swizzle_x;
/** Bit 6 swizzling required for Y tiling */ /** Bit 6 swizzling required for Y tiling */
uint32_t bit_6_swizzle_y; uint32_t bit_6_swizzle_y;
/* storage for physical objects */
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
} mm; } mm;
} drm_i915_private_t; } drm_i915_private_t;
...@@ -436,6 +451,9 @@ struct drm_i915_gem_object { ...@@ -436,6 +451,9 @@ struct drm_i915_gem_object {
/** User space pin count and filp owning the pin */ /** User space pin count and filp owning the pin */
uint32_t user_pin_count; uint32_t user_pin_count;
struct drm_file *pin_filp; struct drm_file *pin_filp;
/** for phy allocated objects */
struct drm_i915_gem_phys_object *phys_obj;
}; };
/** /**
...@@ -598,6 +616,11 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start, ...@@ -598,6 +616,11 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write); int write);
int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id);
void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev);
/* i915_gem_tiling.c */ /* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
......
...@@ -55,6 +55,9 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, ...@@ -55,6 +55,9 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj); static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
static int i915_gem_evict_something(struct drm_device *dev); static int i915_gem_evict_something(struct drm_device *dev);
static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv);
int i915_gem_do_init(struct drm_device *dev, unsigned long start, int i915_gem_do_init(struct drm_device *dev, unsigned long start,
unsigned long end) unsigned long end)
...@@ -386,8 +389,10 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, ...@@ -386,8 +389,10 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
* pread/pwrite currently are reading and writing from the CPU * pread/pwrite currently are reading and writing from the CPU
* perspective, requiring manual detiling by the client. * perspective, requiring manual detiling by the client.
*/ */
if (obj_priv->tiling_mode == I915_TILING_NONE && if (obj_priv->phys_obj)
dev->gtt_total != 0) ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
else if (obj_priv->tiling_mode == I915_TILING_NONE &&
dev->gtt_total != 0)
ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv); ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
else else
ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv); ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv);
...@@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj) ...@@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj)
while (obj_priv->pin_count > 0) while (obj_priv->pin_count > 0)
i915_gem_object_unpin(obj); i915_gem_object_unpin(obj);
if (obj_priv->phys_obj)
i915_gem_detach_phys_object(dev, obj);
i915_gem_object_unbind(obj); i915_gem_object_unbind(obj);
list = &obj->map_list; list = &obj->map_list;
...@@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *dev) ...@@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *dev)
i915_gem_detect_bit_6_swizzle(dev); i915_gem_detect_bit_6_swizzle(dev);
} }
/*
* Create a physically contiguous memory object for this object
* e.g. for cursor + overlay regs
*/
int i915_gem_init_phys_object(struct drm_device *dev,
int id, int size)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_phys_object *phys_obj;
int ret;
if (dev_priv->mm.phys_objs[id - 1] || !size)
return 0;
phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
if (!phys_obj)
return -ENOMEM;
phys_obj->id = id;
phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff);
if (!phys_obj->handle) {
ret = -ENOMEM;
goto kfree_obj;
}
#ifdef CONFIG_X86
set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif
dev_priv->mm.phys_objs[id - 1] = phys_obj;
return 0;
kfree_obj:
drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
return ret;
}
void i915_gem_free_phys_object(struct drm_device *dev, int id)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_phys_object *phys_obj;
if (!dev_priv->mm.phys_objs[id - 1])
return;
phys_obj = dev_priv->mm.phys_objs[id - 1];
if (phys_obj->cur_obj) {
i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
}
#ifdef CONFIG_X86
set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif
drm_pci_free(dev, phys_obj->handle);
kfree(phys_obj);
dev_priv->mm.phys_objs[id - 1] = NULL;
}
void i915_gem_free_all_phys_object(struct drm_device *dev)
{
int i;
for (i = 0; i < I915_MAX_PHYS_OBJECT; i++)
i915_gem_free_phys_object(dev, i);
}
void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj)
{
struct drm_i915_gem_object *obj_priv;
int i;
int ret;
int page_count;
obj_priv = obj->driver_private;
if (!obj_priv->phys_obj)
return;
ret = i915_gem_object_get_page_list(obj);
if (ret)
goto out;
page_count = obj->size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
char *dst = kmap_atomic(obj_priv->page_list[i], KM_USER0);
char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
memcpy(dst, src, PAGE_SIZE);
kunmap_atomic(dst, KM_USER0);
}
drm_clflush_pages(obj_priv->page_list, page_count);
drm_agp_chipset_flush(dev);
out:
obj_priv->phys_obj->cur_obj = NULL;
obj_priv->phys_obj = NULL;
}
int
i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int ret = 0;
int page_count;
int i;
if (id > I915_MAX_PHYS_OBJECT)
return -EINVAL;
obj_priv = obj->driver_private;
if (obj_priv->phys_obj) {
if (obj_priv->phys_obj->id == id)
return 0;
i915_gem_detach_phys_object(dev, obj);
}
/* create a new object */
if (!dev_priv->mm.phys_objs[id - 1]) {
ret = i915_gem_init_phys_object(dev, id,
obj->size);
if (ret) {
DRM_ERROR("failed to init phys object %d size: %d\n", id, obj->size);
goto out;
}
}
/* bind to the object */
obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
obj_priv->phys_obj->cur_obj = obj;
ret = i915_gem_object_get_page_list(obj);
if (ret) {
DRM_ERROR("failed to get page list\n");
goto out;
}
page_count = obj->size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
char *src = kmap_atomic(obj_priv->page_list[i], KM_USER0);
char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
memcpy(dst, src, PAGE_SIZE);
kunmap_atomic(src, KM_USER0);
}
return 0;
out:
return ret;
}
static int
i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
struct drm_i915_gem_object *obj_priv = obj->driver_private;
void *obj_addr;
int ret;
char __user *user_data;
user_data = (char __user *) (uintptr_t) args->data_ptr;
obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
ret = copy_from_user(obj_addr, user_data, args->size);
if (ret)
return -EFAULT;
drm_agp_chipset_flush(dev);
return 0;
}
...@@ -411,6 +411,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) ...@@ -411,6 +411,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags; unsigned long irqflags;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
u32 pipeconf;
pipeconf = I915_READ(pipeconf_reg);
if (!(pipeconf & PIPEACONF_ENABLE))
return -EINVAL;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (IS_I965G(dev)) if (IS_I965G(dev))
......
...@@ -401,6 +401,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, ...@@ -401,6 +401,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
I915_WRITE(dspstride, crtc->fb->pitch); I915_WRITE(dspstride, crtc->fb->pitch);
dspcntr = I915_READ(dspcntr_reg); dspcntr = I915_READ(dspcntr_reg);
/* Mask out pixel format bits in case we change it */
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (crtc->fb->bits_per_pixel) { switch (crtc->fb->bits_per_pixel) {
case 8: case 8:
dspcntr |= DISPPLANE_8BPP; dspcntr |= DISPPLANE_8BPP;
...@@ -1014,21 +1016,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -1014,21 +1016,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
if (bo->size < width * height * 4) { if (bo->size < width * height * 4) {
DRM_ERROR("buffer is to small\n"); DRM_ERROR("buffer is to small\n");
drm_gem_object_unreference(bo); ret = -ENOMEM;
return -ENOMEM; goto fail;
} }
if (dev_priv->cursor_needs_physical) { /* we only need to pin inside GTT if cursor is non-phy */
addr = dev->agp->base + obj_priv->gtt_offset; if (!dev_priv->cursor_needs_physical) {
} else { ret = i915_gem_object_pin(bo, PAGE_SIZE);
if (ret) {
DRM_ERROR("failed to pin cursor bo\n");
goto fail;
}
addr = obj_priv->gtt_offset; addr = obj_priv->gtt_offset;
} } else {
ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
ret = i915_gem_object_pin(bo, PAGE_SIZE); if (ret) {
if (ret) { DRM_ERROR("failed to attach phys object\n");
DRM_ERROR("failed to pin cursor bo\n"); goto fail;
drm_gem_object_unreference(bo); }
return ret; addr = obj_priv->phys_obj->handle->busaddr;
} }
temp = 0; temp = 0;
...@@ -1041,14 +1047,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -1041,14 +1047,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
I915_WRITE(base, addr); I915_WRITE(base, addr);
if (intel_crtc->cursor_bo) { if (intel_crtc->cursor_bo) {
i915_gem_object_unpin(intel_crtc->cursor_bo); if (dev_priv->cursor_needs_physical) {
if (intel_crtc->cursor_bo != bo)
i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
} else
i915_gem_object_unpin(intel_crtc->cursor_bo);
mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(intel_crtc->cursor_bo); drm_gem_object_unreference(intel_crtc->cursor_bo);
mutex_unlock(&dev->struct_mutex);
} }
intel_crtc->cursor_addr = addr; intel_crtc->cursor_addr = addr;
intel_crtc->cursor_bo = bo; intel_crtc->cursor_bo = bo;
return 0; return 0;
fail:
mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(bo);
mutex_unlock(&dev->struct_mutex);
return ret;
} }
static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
......
...@@ -456,6 +456,13 @@ void intel_lvds_init(struct drm_device *dev) ...@@ -456,6 +456,13 @@ void intel_lvds_init(struct drm_device *dev)
dev_priv->panel_fixed_mode = dev_priv->panel_fixed_mode =
drm_mode_duplicate(dev, dev_priv->vbt_mode); drm_mode_duplicate(dev, dev_priv->vbt_mode);
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
if (dev_priv->panel_fixed_mode) {
dev_priv->panel_fixed_mode->type |=
DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector,
dev_priv->panel_fixed_mode);
goto out;
}
} }
/* /*
......
...@@ -395,7 +395,7 @@ struct drm_connector_funcs { ...@@ -395,7 +395,7 @@ struct drm_connector_funcs {
void (*save)(struct drm_connector *connector); void (*save)(struct drm_connector *connector);
void (*restore)(struct drm_connector *connector); void (*restore)(struct drm_connector *connector);
enum drm_connector_status (*detect)(struct drm_connector *connector); enum drm_connector_status (*detect)(struct drm_connector *connector);
void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
int (*set_property)(struct drm_connector *connector, struct drm_property *property, int (*set_property)(struct drm_connector *connector, struct drm_property *property,
uint64_t val); uint64_t val);
void (*destroy)(struct drm_connector *connector); void (*destroy)(struct drm_connector *connector);
......
...@@ -88,7 +88,7 @@ struct drm_connector_helper_funcs { ...@@ -88,7 +88,7 @@ struct drm_connector_helper_funcs {
struct drm_encoder *(*best_encoder)(struct drm_connector *connector); struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
}; };
extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
extern void drm_helper_disable_unused_functions(struct drm_device *dev); extern void drm_helper_disable_unused_functions(struct drm_device *dev);
extern int drm_helper_hotplug_stage_two(struct drm_device *dev); extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment