Skip to content

Commit

Permalink
Merge tag 'topic/core-stuff-2015-01-23' of git://anongit.freedesktop.…
Browse files Browse the repository at this point in the history
…org/drm-intel into drm-next

Just flushing out my drm-misc branch, nothing major. Well too old patches
I've dug out from years since a patch from Rob look eerily familiar ;-)

* tag 'topic/core-stuff-2015-01-23' of git://anongit.freedesktop.org/drm-intel:
  drm/probe-helper: clamp unknown connector status in the poll work
  drm/probe-helper: don't lose hotplug event
  next: drm/atomic: Use copy_from_user to copy 64 bit data from user space
  drm: Make drm_read() more robust against multithreaded races
  drm/fb-helper: Propagate errors from initial config failure
  drm: Drop superfluous "select VT_HW_CONSOLE_BINDING"
  • Loading branch information
Dave Airlie committed Jan 26, 2015
2 parents bdfcea4 + b770372 commit e451400
Show file tree
Hide file tree
Showing 19 changed files with 238 additions and 103 deletions.
21 changes: 15 additions & 6 deletions drivers/gpu/drm/ast/ast_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 12 additions & 2 deletions drivers/gpu/drm/bochs/bochs_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 6 additions & 6 deletions drivers/gpu/drm/cirrus/cirrus_fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/drm_atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,9 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
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;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_fb_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -1692,7 +1692,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
* 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;
Expand Down
89 changes: 42 additions & 47 deletions drivers/gpu/drm/drm_fops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
54 changes: 52 additions & 2 deletions drivers/gpu/drm/drm_probe_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand All @@ -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. */
Expand Down Expand Up @@ -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) {
Expand All @@ -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);

Expand All @@ -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);

Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/exynos/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 18 additions & 4 deletions drivers/gpu/drm/gma500/framebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
12 changes: 10 additions & 2 deletions drivers/gpu/drm/mgag200/mgag200_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit e451400

Please sign in to comment.