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

Pull DRM fixes from Dave Airlie:
 "Two core fixes, both regressions, along with some intel and some
  nouveau fixes for regressions and oopses"

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux:
  drm: correctly restore mappings if drm_open fails
  drm/nouveau: fix NULL ptr dereference from nv50_disp_intr()
  drm/nouveau: fix handling empty channel list in ioctl's
  drm: don't unlock in the addfb error paths
  drm/i915: Fix build failure
  drm/i915: Be sure to turn hsync/vsync back on at crt enable (v2)
  drm/i915: duct-tape locking when eDP init fails
This commit is contained in:
Linus Torvalds 2013-04-02 18:52:24 -07:00
commit bd709bd027
8 changed files with 56 additions and 49 deletions

View file

@ -2326,7 +2326,6 @@ int drm_mode_addfb(struct drm_device *dev,
fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r); fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
if (IS_ERR(fb)) { if (IS_ERR(fb)) {
DRM_DEBUG_KMS("could not create framebuffer\n"); DRM_DEBUG_KMS("could not create framebuffer\n");
drm_modeset_unlock_all(dev);
return PTR_ERR(fb); return PTR_ERR(fb);
} }
@ -2506,7 +2505,6 @@ int drm_mode_addfb2(struct drm_device *dev,
fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
if (IS_ERR(fb)) { if (IS_ERR(fb)) {
DRM_DEBUG_KMS("could not create framebuffer\n"); DRM_DEBUG_KMS("could not create framebuffer\n");
drm_modeset_unlock_all(dev);
return PTR_ERR(fb); return PTR_ERR(fb);
} }

View file

@ -123,6 +123,7 @@ int drm_open(struct inode *inode, struct file *filp)
int retcode = 0; int retcode = 0;
int need_setup = 0; int need_setup = 0;
struct address_space *old_mapping; struct address_space *old_mapping;
struct address_space *old_imapping;
minor = idr_find(&drm_minors_idr, minor_id); minor = idr_find(&drm_minors_idr, minor_id);
if (!minor) if (!minor)
@ -137,6 +138,7 @@ int drm_open(struct inode *inode, struct file *filp)
if (!dev->open_count++) if (!dev->open_count++)
need_setup = 1; need_setup = 1;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
old_imapping = inode->i_mapping;
old_mapping = dev->dev_mapping; old_mapping = dev->dev_mapping;
if (old_mapping == NULL) if (old_mapping == NULL)
dev->dev_mapping = &inode->i_data; dev->dev_mapping = &inode->i_data;
@ -159,8 +161,8 @@ int drm_open(struct inode *inode, struct file *filp)
err_undo: err_undo:
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
filp->f_mapping = old_mapping; filp->f_mapping = old_imapping;
inode->i_mapping = old_mapping; inode->i_mapping = old_imapping;
iput(container_of(dev->dev_mapping, struct inode, i_data)); iput(container_of(dev->dev_mapping, struct inode, i_data));
dev->dev_mapping = old_mapping; dev->dev_mapping = old_mapping;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);

View file

@ -57,7 +57,7 @@ eb_create(struct drm_i915_gem_execbuffer2 *args)
if (eb == NULL) { if (eb == NULL) {
int size = args->buffer_count; int size = args->buffer_count;
int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head))); BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head));
while (count > 2*size) while (count > 2*size)
count >>= 1; count >>= 1;
eb = kzalloc(count*sizeof(struct hlist_head) + eb = kzalloc(count*sizeof(struct hlist_head) +

View file

@ -45,6 +45,9 @@
struct intel_crt { struct intel_crt {
struct intel_encoder base; struct intel_encoder base;
/* DPMS state is stored in the connector, which we need in the
* encoder's enable/disable callbacks */
struct intel_connector *connector;
bool force_hotplug_required; bool force_hotplug_required;
u32 adpa_reg; u32 adpa_reg;
}; };
@ -81,29 +84,6 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
return true; return true;
} }
static void intel_disable_crt(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 temp;
temp = I915_READ(crt->adpa_reg);
temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
temp &= ~ADPA_DAC_ENABLE;
I915_WRITE(crt->adpa_reg, temp);
}
static void intel_enable_crt(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder);
u32 temp;
temp = I915_READ(crt->adpa_reg);
temp |= ADPA_DAC_ENABLE;
I915_WRITE(crt->adpa_reg, temp);
}
/* Note: The caller is required to filter out dpms modes not supported by the /* Note: The caller is required to filter out dpms modes not supported by the
* platform. */ * platform. */
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@ -135,6 +115,19 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
I915_WRITE(crt->adpa_reg, temp); I915_WRITE(crt->adpa_reg, temp);
} }
static void intel_disable_crt(struct intel_encoder *encoder)
{
intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF);
}
static void intel_enable_crt(struct intel_encoder *encoder)
{
struct intel_crt *crt = intel_encoder_to_crt(encoder);
intel_crt_set_dpms(encoder, crt->connector->base.dpms);
}
static void intel_crt_dpms(struct drm_connector *connector, int mode) static void intel_crt_dpms(struct drm_connector *connector, int mode)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
@ -746,6 +739,7 @@ void intel_crt_init(struct drm_device *dev)
} }
connector = &intel_connector->base; connector = &intel_connector->base;
crt->connector = intel_connector;
drm_connector_init(dev, &intel_connector->base, drm_connector_init(dev, &intel_connector->base,
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);

View file

@ -2559,12 +2559,15 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
{ {
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
struct intel_dp *intel_dp = &intel_dig_port->dp; struct intel_dp *intel_dp = &intel_dig_port->dp;
struct drm_device *dev = intel_dp_to_dev(intel_dp);
i2c_del_adapter(&intel_dp->adapter); i2c_del_adapter(&intel_dp->adapter);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work); cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
mutex_lock(&dev->mode_config.mutex);
ironlake_panel_vdd_off_sync(intel_dp); ironlake_panel_vdd_off_sync(intel_dp);
mutex_unlock(&dev->mode_config.mutex);
} }
kfree(intel_dig_port); kfree(intel_dig_port);
} }

View file

@ -391,7 +391,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nv_device(drm->device); struct nouveau_device *device = nv_device(drm->device);
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
struct nouveau_abi16_chan *chan, *temp; struct nouveau_abi16_chan *chan = NULL, *temp;
struct nouveau_abi16_ntfy *ntfy; struct nouveau_abi16_ntfy *ntfy;
struct nouveau_object *object; struct nouveau_object *object;
struct nv_dma_class args = {}; struct nv_dma_class args = {};
@ -404,10 +404,11 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
if (unlikely(nv_device(abi16->device)->card_type >= NV_C0)) if (unlikely(nv_device(abi16->device)->card_type >= NV_C0))
return nouveau_abi16_put(abi16, -EINVAL); return nouveau_abi16_put(abi16, -EINVAL);
list_for_each_entry_safe(chan, temp, &abi16->channels, head) { list_for_each_entry(temp, &abi16->channels, head) {
if (chan->chan->handle == (NVDRM_CHAN | info->channel)) if (temp->chan->handle == (NVDRM_CHAN | info->channel)) {
chan = temp;
break; break;
chan = NULL; }
} }
if (!chan) if (!chan)
@ -459,17 +460,18 @@ nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
{ {
struct drm_nouveau_gpuobj_free *fini = data; struct drm_nouveau_gpuobj_free *fini = data;
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
struct nouveau_abi16_chan *chan, *temp; struct nouveau_abi16_chan *chan = NULL, *temp;
struct nouveau_abi16_ntfy *ntfy; struct nouveau_abi16_ntfy *ntfy;
int ret; int ret;
if (unlikely(!abi16)) if (unlikely(!abi16))
return -ENOMEM; return -ENOMEM;
list_for_each_entry_safe(chan, temp, &abi16->channels, head) { list_for_each_entry(temp, &abi16->channels, head) {
if (chan->chan->handle == (NVDRM_CHAN | fini->channel)) if (temp->chan->handle == (NVDRM_CHAN | fini->channel)) {
chan = temp;
break; break;
chan = NULL; }
} }
if (!chan) if (!chan)

View file

@ -71,12 +71,26 @@ module_param_named(modeset, nouveau_modeset, int, 0400);
static struct drm_driver driver; static struct drm_driver driver;
static int
nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
{
struct nouveau_drm *drm =
container_of(event, struct nouveau_drm, vblank[head]);
drm_handle_vblank(drm->dev, head);
return NVKM_EVENT_KEEP;
}
static int static int
nouveau_drm_vblank_enable(struct drm_device *dev, int head) nouveau_drm_vblank_enable(struct drm_device *dev, int head)
{ {
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device); struct nouveau_disp *pdisp = nouveau_disp(drm->device);
nouveau_event_get(pdisp->vblank, head, &drm->vblank);
if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank)))
return -EIO;
WARN_ON_ONCE(drm->vblank[head].func);
drm->vblank[head].func = nouveau_drm_vblank_handler;
nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]);
return 0; return 0;
} }
@ -85,16 +99,11 @@ nouveau_drm_vblank_disable(struct drm_device *dev, int head)
{ {
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device); struct nouveau_disp *pdisp = nouveau_disp(drm->device);
nouveau_event_put(pdisp->vblank, head, &drm->vblank); if (drm->vblank[head].func)
} nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]);
else
static int WARN_ON_ONCE(1);
nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head) drm->vblank[head].func = NULL;
{
struct nouveau_drm *drm =
container_of(event, struct nouveau_drm, vblank);
drm_handle_vblank(drm->dev, head);
return NVKM_EVENT_KEEP;
} }
static u64 static u64
@ -292,7 +301,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = drm; dev->dev_private = drm;
drm->dev = dev; drm->dev = dev;
drm->vblank.func = nouveau_drm_vblank_handler;
INIT_LIST_HEAD(&drm->clients); INIT_LIST_HEAD(&drm->clients);
spin_lock_init(&drm->tile.lock); spin_lock_init(&drm->tile.lock);

View file

@ -113,7 +113,7 @@ struct nouveau_drm {
struct nvbios vbios; struct nvbios vbios;
struct nouveau_display *display; struct nouveau_display *display;
struct backlight_device *backlight; struct backlight_device *backlight;
struct nouveau_eventh vblank; struct nouveau_eventh vblank[4];
/* power management */ /* power management */
struct nouveau_pm *pm; struct nouveau_pm *pm;