mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-03 17:40:04 +00:00
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:
commit
bd709bd027
8 changed files with 56 additions and 49 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) +
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue