diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/ast/ast_fb.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/bochs/bochs_fbdev.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/cirrus/cirrus_fbdev.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_atomic.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 89 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_probe_helper.c | 54 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/gma500/framebuffer.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/mgag200/mgag200_fb.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_fbdev.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_fbdev.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_fb.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_fb.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/udl/udl_fb.c | 22 |
17 files changed, 236 insertions, 102 deletions
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index 5c60ae524c45..ff68eefae273 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -335,18 +335,27 @@ int ast_fbdev_init(struct drm_device *dev) ret = drm_fb_helper_init(dev, &afbdev->helper, 1, 1); - if (ret) { - kfree(afbdev); - return ret; - } + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&afbdev->helper); + ret = drm_fb_helper_single_add_all_connectors(&afbdev->helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - drm_fb_helper_initial_config(&afbdev->helper, 32); + ret = drm_fb_helper_initial_config(&afbdev->helper, 32); + if (ret) + goto fini; + return 0; + +fini: + drm_fb_helper_fini(&afbdev->helper); +free: + kfree(afbdev); + return ret; } void ast_fbdev_fini(struct drm_device *dev) diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index 61dbf09dff5d..976d9798dc99 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -207,12 +207,22 @@ int bochs_fbdev_init(struct bochs_device *bochs) if (ret) return ret; - drm_fb_helper_single_add_all_connectors(&bochs->fb.helper); + ret = drm_fb_helper_single_add_all_connectors(&bochs->fb.helper); + if (ret) + goto fini; + drm_helper_disable_unused_functions(bochs->dev); - drm_fb_helper_initial_config(&bochs->fb.helper, 32); + + ret = drm_fb_helper_initial_config(&bochs->fb.helper, 32); + if (ret) + goto fini; bochs->fb.initialized = true; return 0; + +fini: + drm_fb_helper_fini(&bochs->fb.helper); + return ret; } void bochs_fbdev_fini(struct bochs_device *bochs) diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 502a89eb54b5..13ddf1c4bb8e 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -317,17 +317,17 @@ int cirrus_fbdev_init(struct cirrus_device *cdev) ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper, cdev->num_crtc, CIRRUSFB_CONN_LIMIT); - if (ret) { - kfree(gfbdev); + if (ret) + return ret; + + ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper); + if (ret) return ret; - } - drm_fb_helper_single_add_all_connectors(&gfbdev->helper); /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(cdev->dev); - drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel); - return 0; + return drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel); } void cirrus_fbdev_fini(struct cirrus_device *cdev) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1e38dfc8e462..af3f3dfdb49f 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1259,7 +1259,9 @@ retry: goto fail; } - if (get_user(prop_value, prop_values_ptr + copied_props)) { + if (copy_from_user(&prop_value, + prop_values_ptr + copied_props, + sizeof(prop_value))) { ret = -EFAULT; goto fail; } diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index cf775a4449c1..d5c1db55abf7 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1692,7 +1692,7 @@ out: * RETURNS: * Zero if everything went ok, nonzero otherwise. */ -bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) +int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) { struct drm_device *dev = fb_helper->dev; int count = 0; diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 0b9514b6cd64..076dd606b580 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -478,64 +478,59 @@ int drm_release(struct inode *inode, struct file *filp) } EXPORT_SYMBOL(drm_release); -static bool -drm_dequeue_event(struct drm_file *file_priv, - size_t total, size_t max, struct drm_pending_event **out) +ssize_t drm_read(struct file *filp, char __user *buffer, + size_t count, loff_t *offset) { + struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->minor->dev; - struct drm_pending_event *e; - unsigned long flags; - bool ret = false; - - spin_lock_irqsave(&dev->event_lock, flags); + ssize_t ret = 0; - *out = NULL; - if (list_empty(&file_priv->event_list)) - goto out; - e = list_first_entry(&file_priv->event_list, - struct drm_pending_event, link); - if (e->event->length + total > max) - goto out; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; - file_priv->event_space += e->event->length; - list_del(&e->link); - *out = e; - ret = true; + spin_lock_irq(&dev->event_lock); + for (;;) { + if (list_empty(&file_priv->event_list)) { + if (ret) + break; -out: - spin_unlock_irqrestore(&dev->event_lock, flags); - return ret; -} - -ssize_t drm_read(struct file *filp, char __user *buffer, - size_t count, loff_t *offset) -{ - struct drm_file *file_priv = filp->private_data; - struct drm_pending_event *e; - size_t total; - ssize_t ret; + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } - if ((filp->f_flags & O_NONBLOCK) == 0) { - ret = wait_event_interruptible(file_priv->event_wait, - !list_empty(&file_priv->event_list)); - if (ret < 0) - return ret; - } + spin_unlock_irq(&dev->event_lock); + ret = wait_event_interruptible(file_priv->event_wait, + !list_empty(&file_priv->event_list)); + spin_lock_irq(&dev->event_lock); + if (ret < 0) + break; + + ret = 0; + } else { + struct drm_pending_event *e; + + e = list_first_entry(&file_priv->event_list, + struct drm_pending_event, link); + if (e->event->length + ret > count) + break; + + if (__copy_to_user_inatomic(buffer + ret, + e->event, e->event->length)) { + if (ret == 0) + ret = -EFAULT; + break; + } - total = 0; - while (drm_dequeue_event(file_priv, total, count, &e)) { - if (copy_to_user(buffer + total, - e->event, e->event->length)) { - total = -EFAULT; + file_priv->event_space += e->event->length; + ret += e->event->length; + list_del(&e->link); e->destroy(e); - break; } - - total += e->event->length; - e->destroy(e); } + spin_unlock_irq(&dev->event_lock); - return total ?: -EAGAIN; + return ret; } EXPORT_SYMBOL(drm_read); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 2fbdcca7ca9a..6591d48c1b9d 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -103,6 +103,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect int count = 0; int mode_flags = 0; bool verbose_prune = true; + enum drm_connector_status old_status; WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); @@ -121,7 +122,33 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect if (connector->funcs->force) connector->funcs->force(connector); } else { + old_status = connector->status; + connector->status = connector->funcs->detect(connector, true); + + /* + * Normally either the driver's hpd code or the poll loop should + * pick up any changes and fire the hotplug event. But if + * userspace sneaks in a probe, we might miss a change. Hence + * check here, and if anything changed start the hotplug code. + */ + if (old_status != connector->status) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", + connector->base.id, + connector->name, + old_status, connector->status); + + /* + * The hotplug event code might call into the fb + * helpers, and so expects that we do not hold any + * locks. Fire up the poll struct instead, it will + * disable itself again. + */ + dev->mode_config.delayed_event = true; + if (dev->mode_config.poll_enabled) + schedule_delayed_work(&dev->mode_config.output_poll_work, + 0); + } } /* Re-enable polling in case the global poll config changed. */ @@ -274,10 +301,14 @@ static void output_poll_execute(struct work_struct *work) struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); struct drm_connector *connector; enum drm_connector_status old_status; - bool repoll = false, changed = false; + bool repoll = false, changed; + + /* Pick up any changes detected by the probe functions. */ + changed = dev->mode_config.delayed_event; + dev->mode_config.delayed_event = false; if (!drm_kms_helper_poll) - return; + goto out; mutex_lock(&dev->mode_config.mutex); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -304,6 +335,24 @@ static void output_poll_execute(struct work_struct *work) if (old_status != connector->status) { const char *old, *new; + /* + * The poll work sets force=false when calling detect so + * that drivers can avoid to do disruptive tests (e.g. + * when load detect cycles could cause flickering on + * other, running displays). This bears the risk that we + * flip-flop between unknown here in the poll work and + * the real state when userspace forces a full detect + * call after receiving a hotplug event due to this + * change. + * + * Hence clamp an unknown detect status to the old + * value. + */ + if (connector->status == connector_status_unknown) { + connector->status = old_status; + continue; + } + old = drm_get_connector_status_name(old_status); new = drm_get_connector_status_name(connector->status); @@ -319,6 +368,7 @@ static void output_poll_execute(struct work_struct *work) mutex_unlock(&dev->mode_config.mutex); +out: if (changed) drm_kms_helper_hotplug_event(dev); diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 7f9f6f9e9b7e..c072999b7e03 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -6,7 +6,6 @@ config DRM_EXYNOS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE select VIDEOMODE_HELPERS help Choose this option if you have a Samsung SoC EXYNOS chipset. diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index ddd90ddbc200..2d42ce6d3757 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -593,6 +593,7 @@ int psb_fbdev_init(struct drm_device *dev) { struct psb_fbdev *fbdev; struct drm_psb_private *dev_priv = dev->dev_private; + int ret; fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL); if (!fbdev) { @@ -604,16 +605,29 @@ int psb_fbdev_init(struct drm_device *dev) drm_fb_helper_prepare(dev, &fbdev->psb_fb_helper, &psb_fb_helper_funcs); - drm_fb_helper_init(dev, &fbdev->psb_fb_helper, dev_priv->ops->crtcs, - INTELFB_CONN_LIMIT); + ret = drm_fb_helper_init(dev, &fbdev->psb_fb_helper, + dev_priv->ops->crtcs, INTELFB_CONN_LIMIT); + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper); + ret = drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32); + ret = drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32); + if (ret) + goto fini; + return 0; + +fini: + drm_fb_helper_fini(&fbdev->psb_fb_helper); +free: + kfree(fbdev); + return ret; } static void psb_fbdev_fini(struct drm_device *dev) diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index 4415af3666ab..c36b8304042b 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -303,14 +303,22 @@ int mgag200_fbdev_init(struct mga_device *mdev) if (ret) return ret; - drm_fb_helper_single_add_all_connectors(&mfbdev->helper); + ret = drm_fb_helper_single_add_all_connectors(&mfbdev->helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(mdev->dev); - drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel); + ret = drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel); + if (ret) + goto fini; return 0; + +fini: + drm_fb_helper_fini(&mfbdev->helper); + return ret; } void mgag200_fbdev_fini(struct mga_device *mdev) diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 1f3af13ccede..115b509a4a00 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -241,17 +241,23 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) goto fail; } - drm_fb_helper_single_add_all_connectors(helper); + ret = drm_fb_helper_single_add_all_connectors(helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - drm_fb_helper_initial_config(helper, 32); + ret = drm_fb_helper_initial_config(helper, 32); + if (ret) + goto fini; priv->fbdev = helper; return helper; +fini: + drm_fb_helper_fini(helper); fail: kfree(fbdev); return NULL; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index d6e6958bc5f8..79924e4b1b49 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -526,12 +526,12 @@ nouveau_fbcon_init(struct drm_device *dev) ret = drm_fb_helper_init(dev, &fbcon->helper, dev->mode_config.num_crtc, 4); - if (ret) { - kfree(fbcon); - return ret; - } + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&fbcon->helper); + ret = drm_fb_helper_single_add_all_connectors(&fbcon->helper); + if (ret) + goto fini; if (drm->device.info.ram_size <= 32 * 1024 * 1024) preferred_bpp = 8; @@ -544,8 +544,17 @@ nouveau_fbcon_init(struct drm_device *dev) /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); + ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp); + if (ret) + goto fini; + return 0; + +fini: + drm_fb_helper_fini(&fbcon->helper); +free: + kfree(fbcon); + return ret; } void diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 8436c6857cda..d292d24b3a6e 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -334,17 +334,23 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) goto fail; } - drm_fb_helper_single_add_all_connectors(helper); + ret = drm_fb_helper_single_add_all_connectors(helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - drm_fb_helper_initial_config(helper, 32); + ret = drm_fb_helper_initial_config(helper, 32); + if (ret) + goto fini; priv->fbdev = helper; return helper; +fini: + drm_fb_helper_fini(helper); fail: kfree(fbdev); return NULL; diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 3d7c1d00a424..f778c0e8ae3c 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -686,14 +686,24 @@ int qxl_fbdev_init(struct qxl_device *qdev) ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper, qxl_num_crtc /* num_crtc - QXL supports just 1 */, QXLFB_CONN_LIMIT); - if (ret) { - kfree(qfbdev); - return ret; - } + if (ret) + goto free; + + ret = drm_fb_helper_single_add_all_connectors(&qfbdev->helper); + if (ret) + goto fini; + + ret = drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel); + if (ret) + goto fini; - drm_fb_helper_single_add_all_connectors(&qfbdev->helper); - drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel); return 0; + +fini: + drm_fb_helper_fini(&qfbdev->helper); +free: + kfree(qfbdev); + return ret; } void qxl_fbdev_fini(struct qxl_device *qdev) diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 29b9220ec399..3000bc4c136b 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -390,18 +390,27 @@ int radeon_fbdev_init(struct radeon_device *rdev) ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper, rdev->num_crtc, RADEONFB_CONN_LIMIT); - if (ret) { - kfree(rfbdev); - return ret; - } + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(rdev->ddev); - drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); + ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); + if (ret) + goto fini; + return 0; + +fini: + drm_fb_helper_fini(&rfbdev->helper); +free: + kfree(rfbdev); + return ret; } void radeon_fbdev_fini(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 0d87bf6ddd96..cb21e3821244 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -7,7 +7,6 @@ config DRM_ROCKCHIP select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE select VIDEOMODE_HELPERS help Choose this option if you have a Rockchip soc chipset. diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 8cbcb4589bd3..5fc16cecd3ba 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -589,19 +589,27 @@ int udl_fbdev_init(struct drm_device *dev) ret = drm_fb_helper_init(dev, &ufbdev->helper, 1, 1); - if (ret) { - kfree(ufbdev); - return ret; - - } + if (ret) + goto free; - drm_fb_helper_single_add_all_connectors(&ufbdev->helper); + ret = drm_fb_helper_single_add_all_connectors(&ufbdev->helper); + if (ret) + goto fini; /* disable all the possible outputs/crtcs before entering KMS mode */ drm_helper_disable_unused_functions(dev); - drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel); + ret = drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel); + if (ret) + goto fini; + return 0; + +fini: + drm_fb_helper_fini(&ufbdev->helper); +free: + kfree(ufbdev); + return ret; } void udl_fbdev_cleanup(struct drm_device *dev) |