Commit c0ee755f authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel into drm-next

So small drm stuff all over for 3.18. Biggest one is the cmdline parsing
from Chris with a few fixes from me to make it work for stupid kernel
configs.

Plus the atomic prep series.

Tested for more than a week in -nightly and Ville/Imre indeed discovered
some fun which is now fixed (and i915 vblank patches postponed since the
fixups need this branch plus drm-intel-next merged together).

* tag 'topic/core-stuff-2014-08-15' of git://anongit.freedesktop.org/drm-intel:
  drm: Use the type of the array element when reallocating
  drm: Don't return 0 for a value used as a denominator
  drm: Docbook fixes
  drm/irq: Implement a generic vblank_wait function
  drm: Add a plane->reset hook
  drm: trylock modest locking for fbdev panics
  drm: Move ->old_fb from crtc to plane
  drm: Handle legacy per-crtc locking with full acquire ctx
  drm: Move modeset_lock_all helpers to drm_modeset_lock.[hc]
  drm: Add drm_plane/connector_index
  drm: idiot-proof vblank
  drm: Warn when leaking flip events on close
  drm: Perform cmdline mode parsing during connector initialisation
  video/fbdev: Always built-in video= cmdline parsing
  drm: Don't grab an fb reference for the idr
parents 52addcf9 14f476fa
...@@ -8,6 +8,7 @@ menuconfig DRM ...@@ -8,6 +8,7 @@ menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA
select HDMI select HDMI
select FB_CMDLINE
select I2C select I2C
select I2C_ALGOBIT select I2C_ALGOBIT
select DMA_SHARED_BUFFER select DMA_SHARED_BUFFER
......
...@@ -45,101 +45,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev, ...@@ -45,101 +45,6 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
struct drm_mode_fb_cmd2 *r, struct drm_mode_fb_cmd2 *r,
struct drm_file *file_priv); struct drm_file *file_priv);
/**
* drm_modeset_lock_all - take all modeset locks
* @dev: drm device
*
* This function takes all modeset locks, suitable where a more fine-grained
* scheme isn't (yet) implemented. Locks must be dropped with
* drm_modeset_unlock_all.
*/
void drm_modeset_lock_all(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx;
int ret;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (WARN_ON(!ctx))
return;
mutex_lock(&config->mutex);
drm_modeset_acquire_init(ctx, 0);
retry:
ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret)
goto fail;
ret = drm_modeset_lock_all_crtcs(dev, ctx);
if (ret)
goto fail;
WARN_ON(config->acquire_ctx);
/* now we hold the locks, so now that it is safe, stash the
* ctx for drm_modeset_unlock_all():
*/
config->acquire_ctx = ctx;
drm_warn_on_modeset_not_all_locked(dev);
return;
fail:
if (ret == -EDEADLK) {
drm_modeset_backoff(ctx);
goto retry;
}
}
EXPORT_SYMBOL(drm_modeset_lock_all);
/**
* drm_modeset_unlock_all - drop all modeset locks
* @dev: device
*
* This function drop all modeset locks taken by drm_modeset_lock_all.
*/
void drm_modeset_unlock_all(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
if (WARN_ON(!ctx))
return;
config->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
kfree(ctx);
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_modeset_unlock_all);
/**
* drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
* @dev: device
*
* Useful as a debug assert.
*/
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
{
struct drm_crtc *crtc;
/* Locking is currently fubar in the panic handler. */
if (oops_in_progress)
return;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
}
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
/* Avoid boilerplate. I'm tired of typing. */ /* Avoid boilerplate. I'm tired of typing. */
#define DRM_ENUM_NAME_FN(fnname, list) \ #define DRM_ENUM_NAME_FN(fnname, list) \
const char *fnname(int val) \ const char *fnname(int val) \
...@@ -515,9 +420,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, ...@@ -515,9 +420,6 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
if (ret) if (ret)
goto out; goto out;
/* Grab the idr reference. */
drm_framebuffer_reference(fb);
dev->mode_config.num_fb++; dev->mode_config.num_fb++;
list_add(&fb->head, &dev->mode_config.fb_list); list_add(&fb->head, &dev->mode_config.fb_list);
out: out:
...@@ -527,10 +429,34 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, ...@@ -527,10 +429,34 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
} }
EXPORT_SYMBOL(drm_framebuffer_init); EXPORT_SYMBOL(drm_framebuffer_init);
/* dev->mode_config.fb_lock must be held! */
static void __drm_framebuffer_unregister(struct drm_device *dev,
struct drm_framebuffer *fb)
{
mutex_lock(&dev->mode_config.idr_mutex);
idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
mutex_unlock(&dev->mode_config.idr_mutex);
fb->base.id = 0;
}
static void drm_framebuffer_free(struct kref *kref) static void drm_framebuffer_free(struct kref *kref)
{ {
struct drm_framebuffer *fb = struct drm_framebuffer *fb =
container_of(kref, struct drm_framebuffer, refcount); container_of(kref, struct drm_framebuffer, refcount);
struct drm_device *dev = fb->dev;
/*
* The lookup idr holds a weak reference, which has not necessarily been
* removed at this point. Check for that.
*/
mutex_lock(&dev->mode_config.fb_lock);
if (fb->base.id) {
/* Mark fb as reaped and drop idr ref. */
__drm_framebuffer_unregister(dev, fb);
}
mutex_unlock(&dev->mode_config.fb_lock);
fb->funcs->destroy(fb); fb->funcs->destroy(fb);
} }
...@@ -567,8 +493,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, ...@@ -567,8 +493,10 @@ struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
mutex_lock(&dev->mode_config.fb_lock); mutex_lock(&dev->mode_config.fb_lock);
fb = __drm_framebuffer_lookup(dev, id); fb = __drm_framebuffer_lookup(dev, id);
if (fb) if (fb) {
drm_framebuffer_reference(fb); if (!kref_get_unless_zero(&fb->refcount))
fb = NULL;
}
mutex_unlock(&dev->mode_config.fb_lock); mutex_unlock(&dev->mode_config.fb_lock);
return fb; return fb;
...@@ -612,19 +540,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) ...@@ -612,19 +540,6 @@ static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
kref_put(&fb->refcount, drm_framebuffer_free_bug); kref_put(&fb->refcount, drm_framebuffer_free_bug);
} }
/* dev->mode_config.fb_lock must be held! */
static void __drm_framebuffer_unregister(struct drm_device *dev,
struct drm_framebuffer *fb)
{
mutex_lock(&dev->mode_config.idr_mutex);
idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
mutex_unlock(&dev->mode_config.idr_mutex);
fb->base.id = 0;
__drm_framebuffer_unreference(fb);
}
/** /**
* drm_framebuffer_unregister_private - unregister a private fb from the lookup idr * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
* @fb: fb to unregister * @fb: fb to unregister
...@@ -852,6 +767,59 @@ static void drm_mode_remove(struct drm_connector *connector, ...@@ -852,6 +767,59 @@ static void drm_mode_remove(struct drm_connector *connector,
drm_mode_destroy(connector->dev, mode); drm_mode_destroy(connector->dev, mode);
} }
/**
* drm_connector_get_cmdline_mode - reads the user's cmdline mode
* @connector: connector to quwery
* @mode: returned mode
*
* The kernel supports per-connector configration of its consoles through
* use of the video= parameter. This function parses that option and
* extracts the user's specified mode (or enable/disable status) for a
* particular connector. This is typically only used during the early fbdev
* setup.
*/
static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
{
struct drm_cmdline_mode *mode = &connector->cmdline_mode;
char *option = NULL;
if (fb_get_options(connector->name, &option))
return;
if (!drm_mode_parse_command_line_for_connector(option,
connector,
mode))
return;
if (mode->force) {
const char *s;
switch (mode->force) {
case DRM_FORCE_OFF:
s = "OFF";
break;
case DRM_FORCE_ON_DIGITAL:
s = "ON - dig";
break;
default:
case DRM_FORCE_ON:
s = "ON";
break;
}
DRM_INFO("forcing %s connector %s\n", connector->name, s);
connector->force = mode->force;
}
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
connector->name,
mode->xres, mode->yres,
mode->refresh_specified ? mode->refresh : 60,
mode->rb ? " reduced blanking" : "",
mode->margins ? " with margins" : "",
mode->interlace ? " interlaced" : "");
}
/** /**
* drm_connector_init - Init a preallocated connector * drm_connector_init - Init a preallocated connector
* @dev: DRM device * @dev: DRM device
...@@ -904,6 +872,8 @@ int drm_connector_init(struct drm_device *dev, ...@@ -904,6 +872,8 @@ int drm_connector_init(struct drm_device *dev,
connector->edid_blob_ptr = NULL; connector->edid_blob_ptr = NULL;
connector->status = connector_status_unknown; connector->status = connector_status_unknown;
drm_connector_get_cmdline_mode(connector);
list_add_tail(&connector->head, &dev->mode_config.connector_list); list_add_tail(&connector->head, &dev->mode_config.connector_list);
dev->mode_config.num_connector++; dev->mode_config.num_connector++;
...@@ -956,6 +926,29 @@ void drm_connector_cleanup(struct drm_connector *connector) ...@@ -956,6 +926,29 @@ void drm_connector_cleanup(struct drm_connector *connector)
} }
EXPORT_SYMBOL(drm_connector_cleanup); EXPORT_SYMBOL(drm_connector_cleanup);
/**
* drm_connector_index - find the index of a registered connector
* @connector: connector to find index for
*
* Given a registered connector, return the index of that connector within a DRM
* device's list of connectors.
*/
unsigned int drm_connector_index(struct drm_connector *connector)
{
unsigned int index = 0;
struct drm_connector *tmp;
list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) {
if (tmp == connector)
return index;
index++;
}
BUG();
}
EXPORT_SYMBOL(drm_connector_index);
/** /**
* drm_connector_register - register a connector * drm_connector_register - register a connector
* @connector: the connector to register * @connector: the connector to register
...@@ -1260,6 +1253,29 @@ void drm_plane_cleanup(struct drm_plane *plane) ...@@ -1260,6 +1253,29 @@ void drm_plane_cleanup(struct drm_plane *plane)
} }
EXPORT_SYMBOL(drm_plane_cleanup); EXPORT_SYMBOL(drm_plane_cleanup);
/**
* drm_plane_index - find the index of a registered plane
* @plane: plane to find index for
*
* Given a registered plane, return the index of that CRTC within a DRM
* device's list of planes.
*/
unsigned int drm_plane_index(struct drm_plane *plane)
{
unsigned int index = 0;
struct drm_plane *tmp;
list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) {
if (tmp == plane)
return index;
index++;
}
BUG();
}
EXPORT_SYMBOL(drm_plane_index);
/** /**
* drm_plane_force_disable - Forcibly disable a plane * drm_plane_force_disable - Forcibly disable a plane
* @plane: plane to disable * @plane: plane to disable
...@@ -1271,19 +1287,21 @@ EXPORT_SYMBOL(drm_plane_cleanup); ...@@ -1271,19 +1287,21 @@ EXPORT_SYMBOL(drm_plane_cleanup);
*/ */
void drm_plane_force_disable(struct drm_plane *plane) void drm_plane_force_disable(struct drm_plane *plane)
{ {
struct drm_framebuffer *old_fb = plane->fb;
int ret; int ret;
if (!old_fb) if (!plane->fb)
return; return;
plane->old_fb = plane->fb;
ret = plane->funcs->disable_plane(plane); ret = plane->funcs->disable_plane(plane);
if (ret) { if (ret) {
DRM_ERROR("failed to disable plane with busy fb\n"); DRM_ERROR("failed to disable plane with busy fb\n");
plane->old_fb = NULL;
return; return;
} }
/* disconnect the plane from the fb and crtc: */ /* disconnect the plane from the fb and crtc: */
__drm_framebuffer_unreference(old_fb); __drm_framebuffer_unreference(plane->old_fb);
plane->old_fb = NULL;
plane->fb = NULL; plane->fb = NULL;
plane->crtc = NULL; plane->crtc = NULL;
} }
...@@ -2259,23 +2277,21 @@ static int setplane_internal(struct drm_plane *plane, ...@@ -2259,23 +2277,21 @@ static int setplane_internal(struct drm_plane *plane,
uint32_t src_w, uint32_t src_h) uint32_t src_w, uint32_t src_h)
{ {
struct drm_device *dev = plane->dev; struct drm_device *dev = plane->dev;
struct drm_framebuffer *old_fb = NULL;
int ret = 0; int ret = 0;
unsigned int fb_width, fb_height; unsigned int fb_width, fb_height;
int i; int i;
drm_modeset_lock_all(dev);
/* No fb means shut it down */ /* No fb means shut it down */
if (!fb) { if (!fb) {
drm_modeset_lock_all(dev); plane->old_fb = plane->fb;
old_fb = plane->fb;
ret = plane->funcs->disable_plane(plane); ret = plane->funcs->disable_plane(plane);
if (!ret) { if (!ret) {
plane->crtc = NULL; plane->crtc = NULL;
plane->fb = NULL; plane->fb = NULL;
} else { } else {
old_fb = NULL; plane->old_fb = NULL;
} }
drm_modeset_unlock_all(dev);
goto out; goto out;
} }
...@@ -2315,8 +2331,7 @@ static int setplane_internal(struct drm_plane *plane, ...@@ -2315,8 +2331,7 @@ static int setplane_internal(struct drm_plane *plane,
goto out; goto out;
} }
drm_modeset_lock_all(dev); plane->old_fb = plane->fb;
old_fb = plane->fb;
ret = plane->funcs->update_plane(plane, crtc, fb, ret = plane->funcs->update_plane(plane, crtc, fb,
crtc_x, crtc_y, crtc_w, crtc_h, crtc_x, crtc_y, crtc_w, crtc_h,
src_x, src_y, src_w, src_h); src_x, src_y, src_w, src_h);
...@@ -2325,15 +2340,16 @@ static int setplane_internal(struct drm_plane *plane, ...@@ -2325,15 +2340,16 @@ static int setplane_internal(struct drm_plane *plane,
plane->fb = fb; plane->fb = fb;
fb = NULL; fb = NULL;
} else { } else {
old_fb = NULL; plane->old_fb = NULL;
} }
drm_modeset_unlock_all(dev);
out: out:
if (fb) if (fb)
drm_framebuffer_unreference(fb); drm_framebuffer_unreference(fb);
if (old_fb) if (plane->old_fb)
drm_framebuffer_unreference(old_fb); drm_framebuffer_unreference(plane->old_fb);
plane->old_fb = NULL;
drm_modeset_unlock_all(dev);
return ret; return ret;
...@@ -2440,7 +2456,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) ...@@ -2440,7 +2456,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
* crtcs. Atomic modeset will have saner semantics ... * crtcs. Atomic modeset will have saner semantics ...
*/ */
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
tmp->old_fb = tmp->primary->fb; tmp->primary->old_fb = tmp->primary->fb;
fb = set->fb; fb = set->fb;
...@@ -2453,8 +2469,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) ...@@ -2453,8 +2469,9 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
if (tmp->primary->fb) if (tmp->primary->fb)
drm_framebuffer_reference(tmp->primary->fb); drm_framebuffer_reference(tmp->primary->fb);
if (tmp->old_fb) if (tmp->primary->old_fb)
drm_framebuffer_unreference(tmp->old_fb); drm_framebuffer_unreference(tmp->primary->old_fb);
tmp->primary->old_fb = NULL;
} }
return ret; return ret;
...@@ -2785,7 +2802,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, ...@@ -2785,7 +2802,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
if (crtc->cursor) if (crtc->cursor)
return drm_mode_cursor_universal(crtc, req, file_priv); return drm_mode_cursor_universal(crtc, req, file_priv);
drm_modeset_lock(&crtc->mutex, NULL); drm_modeset_lock_crtc(crtc);
if (req->flags & DRM_MODE_CURSOR_BO) { if (req->flags & DRM_MODE_CURSOR_BO) {
if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) { if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
ret = -ENXIO; ret = -ENXIO;
...@@ -2809,7 +2826,7 @@ static int drm_mode_cursor_common(struct drm_device *dev, ...@@ -2809,7 +2826,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
} }
} }
out: out:
drm_modeset_unlock(&crtc->mutex); drm_modeset_unlock_crtc(crtc);
return ret; return ret;
...@@ -3495,9 +3512,10 @@ EXPORT_SYMBOL(drm_property_create_enum); ...@@ -3495,9 +3512,10 @@ EXPORT_SYMBOL(drm_property_create_enum);
* @flags: flags specifying the property type * @flags: flags specifying the property type
* @name: name of the property * @name: name of the property
* @props: enumeration lists with property bitflags * @props: enumeration lists with property bitflags
* @num_values: number of pre-defined values * @num_props: size of the @props array
* @supported_bits: bitmask of all supported enumeration values
* *
* This creates a new generic drm property which can then be attached to a drm * This creates a new bitmask drm property which can then be attached to a drm
* object with drm_object_attach_property. The returned property object must be * object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy. * freed with drm_property_destroy.
* *
...@@ -4529,7 +4547,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -4529,7 +4547,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
{ {
struct drm_mode_crtc_page_flip *page_flip = data; struct drm_mode_crtc_page_flip *page_flip = data;
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_framebuffer *fb = NULL, *old_fb = NULL; struct drm_framebuffer *fb = NULL;
struct drm_pending_vblank_event *e = NULL; struct drm_pending_vblank_event *e = NULL;
unsigned long flags; unsigned long flags;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -4545,7 +4563,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -4545,7 +4563,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if (!crtc) if (!crtc)
return -ENOENT; return -ENOENT;
drm_modeset_lock(&crtc->mutex, NULL); drm_modeset_lock_crtc(crtc);
if (crtc->primary->fb == NULL) { if (crtc->primary->fb == NULL) {
/* The framebuffer is currently unbound, presumably /* The framebuffer is currently unbound, presumably
* due to a hotplug event, that userspace has not * due to a hotplug event, that userspace has not
...@@ -4601,7 +4619,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -4601,7 +4619,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
(void (*) (struct drm_pending_event *)) kfree; (void (*) (struct drm_pending_event *)) kfree;
} }
old_fb = crtc->primary->fb; crtc->primary->old_fb = crtc->primary->fb;
ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
if (ret) { if (ret) {
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
...@@ -4611,7 +4629,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -4611,7 +4629,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
kfree(e); kfree(e);
} }
/* Keep the old fb, don't unref it. */ /* Keep the old fb, don't unref it. */
old_fb = NULL; crtc->primary->old_fb = NULL;
} else { } else {
/* /*
* Warn if the driver hasn't properly updated the crtc->fb * Warn if the driver hasn't properly updated the crtc->fb
...@@ -4627,9 +4645,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -4627,9 +4645,10 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
out: out:
if (fb) if (fb)
drm_framebuffer_unreference(fb); drm_framebuffer_unreference(fb);
if (old_fb) if (crtc->primary->old_fb)
drm_framebuffer_unreference(old_fb); drm_framebuffer_unreference(crtc->primary->old_fb);
drm_modeset_unlock(&crtc->mutex); crtc->primary->old_fb = NULL;
drm_modeset_unlock_crtc(crtc);
return ret; return ret;
} }
...@@ -4645,9 +4664,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -4645,9 +4664,14 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
void drm_mode_config_reset(struct drm_device *dev) void drm_mode_config_reset(struct drm_device *dev)
{ {
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_connector *connector; struct drm_connector *connector;
list_for_each_entry(plane, &dev->mode_config.plane_list, head)
if (plane->funcs->reset)
plane->funcs->reset(plane);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
if (crtc->funcs->reset) if (crtc->funcs->reset)
crtc->funcs->reset(crtc); crtc->funcs->reset(crtc);
......
...@@ -1772,7 +1772,7 @@ static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count) ...@@ -1772,7 +1772,7 @@ static int drm_dp_get_vc_payload_bw(int dp_link_bw, int dp_link_count)
case DP_LINK_BW_5_4: case DP_LINK_BW_5_4:
return 10 * dp_link_count; return 10 * dp_link_count;
} }
return 0; BUG();
} }
/** /**
...@@ -2071,6 +2071,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) ...@@ -2071,6 +2071,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
* drm_dp_mst_hpd_irq() - MST hotplug IRQ notify * drm_dp_mst_hpd_irq() - MST hotplug IRQ notify
* @mgr: manager to notify irq for. * @mgr: manager to notify irq for.
* @esi: 4 bytes from SINK_COUNT_ESI * @esi: 4 bytes from SINK_COUNT_ESI
* @handled: whether the hpd interrupt was consumed or not
* *
* This should be called from the driver when it detects a short IRQ, * This should be called from the driver when it detects a short IRQ,
* along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The * along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The
......
...@@ -3433,10 +3433,10 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable); ...@@ -3433,10 +3433,10 @@ EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
/** /**
* drm_assign_hdmi_deep_color_info - detect whether monitor supports * drm_assign_hdmi_deep_color_info - detect whether monitor supports
* hdmi deep color modes and update drm_display_info if so. * hdmi deep color modes and update drm_display_info if so.
*
* @edid: monitor EDID information * @edid: monitor EDID information
* @info: Updated with maximum supported deep color bpc and color format * @info: Updated with maximum supported deep color bpc and color format
* if deep color supported. * if deep color supported.
* @connector: DRM connector, used only for debug output
* *
* Parse the CEA extension according to CEA-861-B. * Parse the CEA extension according to CEA-861-B.
* Return true if HDMI deep color supported, false if not or unknown. * Return true if HDMI deep color supported, false if not or unknown.
......
...@@ -126,7 +126,7 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_ ...@@ -126,7 +126,7 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex)); WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) { if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) {
temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector) * (fb_helper->connector_count + 1), GFP_KERNEL); temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL);
if (!temp) if (!temp)
return -ENOMEM; return -ENOMEM;
...@@ -171,60 +171,6 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, ...@@ -171,60 +171,6 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
} }
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
{
struct drm_fb_helper_connector *fb_helper_conn;
int i;
for (i = 0; i < fb_helper->connector_count; i++) {
struct drm_cmdline_mode *mode;
struct drm_connector *connector;
char *option = NULL;
fb_helper_conn = fb_helper->connector_info[i];
connector = fb_helper_conn->connector;
mode = &fb_helper_conn->cmdline_mode;
/* do something on return - turn off connector maybe */
if (fb_get_options(connector->name, &option))
continue;
if (drm_mode_parse_command_line_for_connector(option,
connector,
mode)) {
if (mode->force) {
const char *s;
switch (mode->force) {
case DRM_FORCE_OFF:
s = "OFF";
break;
case DRM_FORCE_ON_DIGITAL:
s = "ON - dig";
break;
default:
case DRM_FORCE_ON:
s = "ON";
break;
}
DRM_INFO("forcing %s connector %s\n",
connector->name, s);
connector->force = mode->force;
}
DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
connector->name,
mode->xres, mode->yres,
mode->refresh_specified ? mode->refresh : 60,
mode->rb ? " reduced blanking" : "",
mode->margins ? " with margins" : "",
mode->interlace ? " interlaced" : "");
}
}
return 0;
}
static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
{ {
uint16_t *r_base, *g_base, *b_base; uint16_t *r_base, *g_base, *b_base;
...@@ -419,11 +365,11 @@ static bool drm_fb_helper_force_kernel_mode(void) ...@@ -419,11 +365,11 @@ static bool drm_fb_helper_force_kernel_mode(void)
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
continue; continue;
/* NOTE: we use lockless flag below to avoid grabbing other /*
* modeset locks. So just trylock the underlying mutex * NOTE: Use trylock mode to avoid deadlocks and sleeping in
* directly: * panic context.
*/ */
if (!mutex_trylock(&dev->mode_config.mutex)) { if (__drm_modeset_lock_all(dev, true) != 0) {
error = true; error = true;
continue; continue;
} }
...@@ -432,7 +378,7 @@ static bool drm_fb_helper_force_kernel_mode(void) ...@@ -432,7 +378,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
if (ret) if (ret)
error = true; error = true;
mutex_unlock(&dev->mode_config.mutex); drm_modeset_unlock_all(dev);
} }
return error; return error;
} }
...@@ -1013,7 +959,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, ...@@ -1013,7 +959,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
struct drm_cmdline_mode *cmdline_mode; struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_helper_conn->cmdline_mode; cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
if (cmdline_mode->bpp_specified) { if (cmdline_mode->bpp_specified) {
switch (cmdline_mode->bpp) { switch (cmdline_mode->bpp) {
...@@ -1260,9 +1206,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode); ...@@ -1260,9 +1206,7 @@ EXPORT_SYMBOL(drm_has_preferred_mode);
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector) static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
{ {
struct drm_cmdline_mode *cmdline_mode; return fb_connector->connector->cmdline_mode.specified;
cmdline_mode = &fb_connector->cmdline_mode;
return cmdline_mode->specified;
} }
struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
...@@ -1272,7 +1216,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f ...@@ -1272,7 +1216,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
struct drm_display_mode *mode = NULL; struct drm_display_mode *mode = NULL;
bool prefer_non_interlace; bool prefer_non_interlace;
cmdline_mode = &fb_helper_conn->cmdline_mode; cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
if (cmdline_mode->specified == false) if (cmdline_mode->specified == false)
return mode; return mode;
...@@ -1657,8 +1601,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) ...@@ -1657,8 +1601,6 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
struct drm_device *dev = fb_helper->dev; struct drm_device *dev = fb_helper->dev;
int count = 0; int count = 0;
drm_fb_helper_parse_command_line(fb_helper);
mutex_lock(&dev->mode_config.mutex); mutex_lock(&dev->mode_config.mutex);
count = drm_fb_helper_probe_connector_modes(fb_helper, count = drm_fb_helper_probe_connector_modes(fb_helper,
dev->mode_config.max_width, dev->mode_config.max_width,
......
...@@ -464,6 +464,8 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -464,6 +464,8 @@ int drm_release(struct inode *inode, struct file *filp)
if (drm_core_check_feature(dev, DRIVER_PRIME)) if (drm_core_check_feature(dev, DRIVER_PRIME))
drm_prime_destroy_file_private(&file_priv->prime); drm_prime_destroy_file_private(&file_priv->prime);
WARN_ON(!list_empty(&file_priv->event_list));
put_pid(file_priv->pid); put_pid(file_priv->pid);
kfree(file_priv); kfree(file_priv);
......
...@@ -720,6 +720,8 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp); ...@@ -720,6 +720,8 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp);
*/ */
u32 drm_vblank_count(struct drm_device *dev, int crtc) u32 drm_vblank_count(struct drm_device *dev, int crtc)
{ {
if (WARN_ON(crtc >= dev->num_crtcs))
return 0;
return atomic_read(&dev->vblank[crtc].count); return atomic_read(&dev->vblank[crtc].count);
} }
EXPORT_SYMBOL(drm_vblank_count); EXPORT_SYMBOL(drm_vblank_count);
...@@ -742,6 +744,9 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, ...@@ -742,6 +744,9 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
{ {
u32 cur_vblank; u32 cur_vblank;
if (WARN_ON(crtc >= dev->num_crtcs))
return 0;
/* Read timestamp from slot of _vblank_time ringbuffer /* Read timestamp from slot of _vblank_time ringbuffer
* that corresponds to current vblank count. Retry if * that corresponds to current vblank count. Retry if
* count has incremented during readout. This works like * count has incremented during readout. This works like
...@@ -917,6 +922,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc) ...@@ -917,6 +922,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
unsigned long irqflags; unsigned long irqflags;
int ret = 0; int ret = 0;
if (WARN_ON(crtc >= dev->num_crtcs))
return -EINVAL;
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* Going from 0->1 means we have to enable interrupts again */ /* Going from 0->1 means we have to enable interrupts again */
if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) {
...@@ -965,6 +973,9 @@ void drm_vblank_put(struct drm_device *dev, int crtc) ...@@ -965,6 +973,9 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
{ {
BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0); BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0);
if (WARN_ON(crtc >= dev->num_crtcs))
return;
/* Last user schedules interrupt disable */ /* Last user schedules interrupt disable */
if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
(drm_vblank_offdelay > 0)) (drm_vblank_offdelay > 0))
...@@ -988,6 +999,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc) ...@@ -988,6 +999,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc)
} }
EXPORT_SYMBOL(drm_crtc_vblank_put); EXPORT_SYMBOL(drm_crtc_vblank_put);
/**
* drm_wait_one_vblank - wait for one vblank
* @dev: DRM device
* @crtc: crtc index
*
* This waits for one vblank to pass on @crtc, using the irq driver interfaces.
* It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
* due to lack of driver support or because the crtc is off.
*/
void drm_wait_one_vblank(struct drm_device *dev, int crtc)
{
int ret;
u32 last;
ret = drm_vblank_get(dev, crtc);
if (WARN_ON(ret))
return;
last = drm_vblank_count(dev, crtc);
ret = wait_event_timeout(dev->vblank[crtc].queue,
last != drm_vblank_count(dev, crtc),
msecs_to_jiffies(100));
WARN_ON(ret == 0);
drm_vblank_put(dev, crtc);
}
EXPORT_SYMBOL(drm_wait_one_vblank);
/**
* drm_crtc_wait_one_vblank - wait for one vblank
* @crtc: DRM crtc
*
* This waits for one vblank to pass on @crtc, using the irq driver interfaces.
* It is a failure to call this when the vblank irq for @crtc is disabled, e.g.
* due to lack of driver support or because the crtc is off.
*/
void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
{
drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc));
}
EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
/** /**
* drm_vblank_off - disable vblank events on a CRTC * drm_vblank_off - disable vblank events on a CRTC
* @dev: DRM device * @dev: DRM device
...@@ -1009,6 +1064,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) ...@@ -1009,6 +1064,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
unsigned long irqflags; unsigned long irqflags;
unsigned int seq; unsigned int seq;
if (WARN_ON(crtc >= dev->num_crtcs))
return;
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
vblank_disable_and_save(dev, crtc); vblank_disable_and_save(dev, crtc);
wake_up(&dev->vblank[crtc].queue); wake_up(&dev->vblank[crtc].queue);
...@@ -1068,6 +1126,9 @@ void drm_vblank_on(struct drm_device *dev, int crtc) ...@@ -1068,6 +1126,9 @@ void drm_vblank_on(struct drm_device *dev, int crtc)
{ {
unsigned long irqflags; unsigned long irqflags;
if (WARN_ON(crtc >= dev->num_crtcs))
return;
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
/* re-enable interrupts if there's are users left */ /* re-enable interrupts if there's are users left */
if (atomic_read(&dev->vblank[crtc].refcount) != 0) if (atomic_read(&dev->vblank[crtc].refcount) != 0)
...@@ -1121,6 +1182,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) ...@@ -1121,6 +1182,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
/* vblank is not initialized (IRQ not installed ?), or has been freed */ /* vblank is not initialized (IRQ not installed ?), or has been freed */
if (!dev->num_crtcs) if (!dev->num_crtcs)
return; return;
if (WARN_ON(crtc >= dev->num_crtcs))
return;
/* /*
* To avoid all the problems that might happen if interrupts * To avoid all the problems that might happen if interrupts
* were enabled/disabled around or between these calls, we just * were enabled/disabled around or between these calls, we just
...@@ -1429,6 +1494,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) ...@@ -1429,6 +1494,9 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
if (!dev->num_crtcs) if (!dev->num_crtcs)
return false; return false;
if (WARN_ON(crtc >= dev->num_crtcs))
return false;
/* Need timestamp lock to prevent concurrent execution with /* Need timestamp lock to prevent concurrent execution with
* vblank enable/disable, as this would cause inconsistent * vblank enable/disable, as this would cause inconsistent
* or corrupted timestamps and vblank counts. * or corrupted timestamps and vblank counts.
......
...@@ -1259,6 +1259,7 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev, ...@@ -1259,6 +1259,7 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
if (!mode) if (!mode)
return NULL; return NULL;
mode->type |= DRM_MODE_TYPE_USERDEF;
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
return mode; return mode;
} }
......
...@@ -56,6 +56,212 @@ ...@@ -56,6 +56,212 @@
*/ */
/**
* __drm_modeset_lock_all - internal helper to grab all modeset locks
* @dev: DRM device
* @trylock: trylock mode for atomic contexts
*
* This is a special version of drm_modeset_lock_all() which can also be used in
* atomic contexts. Then @trylock must be set to true.
*
* Returns:
* 0 on success or negative error code on failure.
*/
int __drm_modeset_lock_all(struct drm_device *dev,
bool trylock)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx;
int ret;
ctx = kzalloc(sizeof(*ctx),
trylock ? GFP_ATOMIC : GFP_KERNEL);
if (!ctx)
return -ENOMEM;
if (trylock) {
if (!mutex_trylock(&config->mutex))
return -EBUSY;
} else {
mutex_lock(&config->mutex);
}
drm_modeset_acquire_init(ctx, 0);
ctx->trylock_only = trylock;
retry:
ret = drm_modeset_lock(&config->connection_mutex, ctx);
if (ret)
goto fail;
ret = drm_modeset_lock_all_crtcs(dev, ctx);
if (ret)
goto fail;
WARN_ON(config->acquire_ctx);
/* now we hold the locks, so now that it is safe, stash the
* ctx for drm_modeset_unlock_all():
*/
config->acquire_ctx = ctx;
drm_warn_on_modeset_not_all_locked(dev);
return 0;
fail:
if (ret == -EDEADLK) {
drm_modeset_backoff(ctx);
goto retry;
}
return ret;
}
EXPORT_SYMBOL(__drm_modeset_lock_all);
/**
* drm_modeset_lock_all - take all modeset locks
* @dev: drm device
*
* This function takes all modeset locks, suitable where a more fine-grained
* scheme isn't (yet) implemented. Locks must be dropped with
* drm_modeset_unlock_all.
*/
void drm_modeset_lock_all(struct drm_device *dev)
{
WARN_ON(__drm_modeset_lock_all(dev, false) != 0);
}
EXPORT_SYMBOL(drm_modeset_lock_all);
/**
* drm_modeset_unlock_all - drop all modeset locks
* @dev: device
*
* This function drop all modeset locks taken by drm_modeset_lock_all.
*/
void drm_modeset_unlock_all(struct drm_device *dev)
{
struct drm_mode_config *config = &dev->mode_config;
struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx;
if (WARN_ON(!ctx))
return;
config->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
kfree(ctx);
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_modeset_unlock_all);
/**
* drm_modeset_lock_crtc - lock crtc with hidden acquire ctx
* @crtc: drm crtc
*
* This function locks the given crtc using a hidden acquire context. This is
* necessary so that drivers internally using the atomic interfaces can grab
* further locks with the lock acquire context.
*/
void drm_modeset_lock_crtc(struct drm_crtc *crtc)
{
struct drm_modeset_acquire_ctx *ctx;
int ret;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (WARN_ON(!ctx))
return;
drm_modeset_acquire_init(ctx, 0);
retry:
ret = drm_modeset_lock(&crtc->mutex, ctx);
if (ret)
goto fail;
WARN_ON(crtc->acquire_ctx);
/* now we hold the locks, so now that it is safe, stash the
* ctx for drm_modeset_unlock_crtc():
*/
crtc->acquire_ctx = ctx;
return;
fail:
if (ret == -EDEADLK) {
drm_modeset_backoff(ctx);
goto retry;
}
}
EXPORT_SYMBOL(drm_modeset_lock_crtc);
/**
* drm_modeset_legacy_acquire_ctx - find acquire ctx for legacy ioctls
* @crtc: drm crtc
*
* Legacy ioctl operations like cursor updates or page flips only have per-crtc
* locking, and store the acquire ctx in the corresponding crtc. All other
* legacy operations take all locks and use a global acquire context. This
* function grabs the right one.
*/
struct drm_modeset_acquire_ctx *
drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc)
{
if (crtc->acquire_ctx)
return crtc->acquire_ctx;
WARN_ON(!crtc->dev->mode_config.acquire_ctx);
return crtc->dev->mode_config.acquire_ctx;
}
EXPORT_SYMBOL(drm_modeset_legacy_acquire_ctx);
/**
* drm_modeset_unlock_crtc - drop crtc lock
* @crtc: drm crtc
*
* This drops the crtc lock acquire with drm_modeset_lock_crtc() and all other
* locks acquired through the hidden context.
*/
void drm_modeset_unlock_crtc(struct drm_crtc *crtc)
{
struct drm_modeset_acquire_ctx *ctx = crtc->acquire_ctx;
if (WARN_ON(!ctx))
return;
crtc->acquire_ctx = NULL;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
kfree(ctx);
}
EXPORT_SYMBOL(drm_modeset_unlock_crtc);
/**
* drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
* @dev: device
*
* Useful as a debug assert.
*/
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
{
struct drm_crtc *crtc;
/* Locking is currently fubar in the panic handler. */
if (oops_in_progress)
return;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
}
EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
/** /**
* drm_modeset_acquire_init - initialize acquire context * drm_modeset_acquire_init - initialize acquire context
* @ctx: the acquire context * @ctx: the acquire context
...@@ -108,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock, ...@@ -108,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,
WARN_ON(ctx->contended); WARN_ON(ctx->contended);
if (interruptible && slow) { if (ctx->trylock_only) {
if (!ww_mutex_trylock(&lock->mutex))
return -EBUSY;
else
return 0;
} else if (interruptible && slow) {
ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx); ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
} else if (interruptible) { } else if (interruptible) {
ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx); ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
......
...@@ -82,6 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector, ...@@ -82,6 +82,22 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
return; return;
} }
static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
{
struct drm_display_mode *mode;
if (!connector->cmdline_mode.specified)
return 0;
mode = drm_mode_create_from_cmdline_mode(connector->dev,
&connector->cmdline_mode);
if (mode == NULL)
return 0;
drm_mode_probed_add(connector, mode);
return 1;
}
static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY, bool merge_type_bits) uint32_t maxX, uint32_t maxY, bool merge_type_bits)
{ {
...@@ -141,6 +157,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect ...@@ -141,6 +157,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
if (count == 0 && connector->status == connector_status_connected) if (count == 0 && connector->status == connector_status_connected)
count = drm_add_modes_noedid(connector, 1024, 768); count = drm_add_modes_noedid(connector, 1024, 768);
count += drm_helper_probe_add_cmdline_mode(connector);
if (count == 0) if (count == 0)
goto prune; goto prune;
......
...@@ -1483,11 +1483,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector, ...@@ -1483,11 +1483,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct mga_device *mdev = (struct mga_device*)dev->dev_private; struct mga_device *mdev = (struct mga_device*)dev->dev_private;
struct mga_fbdev *mfbdev = mdev->mfbdev;
struct drm_fb_helper *fb_helper = &mfbdev->helper;
struct drm_fb_helper_connector *fb_helper_conn = NULL;
int bpp = 32; int bpp = 32;
int i = 0;
if (IS_G200_SE(mdev)) { if (IS_G200_SE(mdev)) {
if (mdev->unique_rev_id == 0x01) { if (mdev->unique_rev_id == 0x01) {
...@@ -1537,21 +1533,14 @@ static int mga_vga_mode_valid(struct drm_connector *connector, ...@@ -1537,21 +1533,14 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
} }
/* Validate the mode input by the user */ /* Validate the mode input by the user */
for (i = 0; i < fb_helper->connector_count; i++) { if (connector->cmdline_mode.specified) {
if (fb_helper->connector_info[i]->connector == connector) { if (connector->cmdline_mode.bpp_specified)
/* Found the helper for this connector */ bpp = connector->cmdline_mode.bpp;
fb_helper_conn = fb_helper->connector_info[i];
if (fb_helper_conn->cmdline_mode.specified) {
if (fb_helper_conn->cmdline_mode.bpp_specified) {
bpp = fb_helper_conn->cmdline_mode.bpp;
}
}
}
} }
if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) { if ((mode->hdisplay * mode->vdisplay * (bpp/8)) > mdev->mc.vram_size) {
if (fb_helper_conn) if (connector->cmdline_mode.specified)
fb_helper_conn->cmdline_mode.specified = false; connector->cmdline_mode.specified = false;
return MODE_BAD; return MODE_BAD;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
menuconfig FB menuconfig FB
tristate "Support for frame buffer devices" tristate "Support for frame buffer devices"
select FB_CMDLINE
---help--- ---help---
The frame buffer device provides an abstraction for the graphics The frame buffer device provides an abstraction for the graphics
hardware. It represents the frame buffer of some video hardware and hardware. It represents the frame buffer of some video hardware and
...@@ -52,6 +53,9 @@ config FIRMWARE_EDID ...@@ -52,6 +53,9 @@ config FIRMWARE_EDID
combination with certain motherboards and monitors are known to combination with certain motherboards and monitors are known to
suffer from this problem. suffer from this problem.
config FB_CMDLINE
bool
config FB_DDC config FB_DDC
tristate tristate
depends on FB depends on FB
......
obj-y += fb_notify.o obj-y += fb_notify.o
obj-$(CONFIG_FB_CMDLINE) += fb_cmdline.o
obj-$(CONFIG_FB) += fb.o obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o modedb.o fbcvt.o
......
/*
* linux/drivers/video/fb_cmdline.c
*
* Copyright (C) 2014 Intel Corp
* Copyright (C) 1994 Martin Schaller
*
* 2001 - Documented with DocBook
* - Brad Douglas <brad@neruo.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
* Authors:
* Vetter <danie.vetter@ffwll.ch>
*/
#include <linux/init.h>
#include <linux/fb.h>
static char *video_options[FB_MAX] __read_mostly;
static int ofonly __read_mostly;
const char *fb_mode_option;
EXPORT_SYMBOL_GPL(fb_mode_option);
/**
* fb_get_options - get kernel boot parameters
* @name: framebuffer name as it would appear in
* the boot parameter line
* (video=<name>:<options>)
* @option: the option will be stored here
*
* NOTE: Needed to maintain backwards compatibility
*/
int fb_get_options(const char *name, char **option)
{
char *opt, *options = NULL;
int retval = 0;
int name_len = strlen(name), i;
if (name_len && ofonly && strncmp(name, "offb", 4))
retval = 1;
if (name_len && !retval) {
for (i = 0; i < FB_MAX; i++) {
if (video_options[i] == NULL)
continue;
if (!video_options[i][0])
continue;
opt = video_options[i];
if (!strncmp(name, opt, name_len) &&
opt[name_len] == ':')
options = opt + name_len + 1;
}
}
/* No match, pass global option */
if (!options && option && fb_mode_option)
options = kstrdup(fb_mode_option, GFP_KERNEL);
if (options && !strncmp(options, "off", 3))
retval = 1;
if (option)
*option = options;
return retval;
}
EXPORT_SYMBOL(fb_get_options);
/**
* video_setup - process command line options
* @options: string of options
*
* Process command line options for frame buffer subsystem.
*
* NOTE: This function is a __setup and __init function.
* It only stores the options. Drivers have to call
* fb_get_options() as necessary.
*
* Returns zero.
*
*/
static int __init video_setup(char *options)
{
int i, global = 0;
if (!options || !*options)
global = 1;
if (!global && !strncmp(options, "ofonly", 6)) {
ofonly = 1;
global = 1;
}
if (!global && !strchr(options, ':')) {
fb_mode_option = options;
global = 1;
}
if (!global) {
for (i = 0; i < FB_MAX; i++) {
if (video_options[i] == NULL) {
video_options[i] = options;
break;
}
}
}
return 1;
}
__setup("video=", video_setup);
...@@ -1908,96 +1908,4 @@ int fb_new_modelist(struct fb_info *info) ...@@ -1908,96 +1908,4 @@ int fb_new_modelist(struct fb_info *info)
return err; return err;
} }
static char *video_options[FB_MAX] __read_mostly;
static int ofonly __read_mostly;
/**
* fb_get_options - get kernel boot parameters
* @name: framebuffer name as it would appear in
* the boot parameter line
* (video=<name>:<options>)
* @option: the option will be stored here
*
* NOTE: Needed to maintain backwards compatibility
*/
int fb_get_options(const char *name, char **option)
{
char *opt, *options = NULL;
int retval = 0;
int name_len = strlen(name), i;
if (name_len && ofonly && strncmp(name, "offb", 4))
retval = 1;
if (name_len && !retval) {
for (i = 0; i < FB_MAX; i++) {
if (video_options[i] == NULL)
continue;
if (!video_options[i][0])
continue;
opt = video_options[i];
if (!strncmp(name, opt, name_len) &&
opt[name_len] == ':')
options = opt + name_len + 1;
}
}
/* No match, pass global option */
if (!options && option && fb_mode_option)
options = kstrdup(fb_mode_option, GFP_KERNEL);
if (options && !strncmp(options, "off", 3))
retval = 1;
if (option)
*option = options;
return retval;
}
EXPORT_SYMBOL(fb_get_options);
#ifndef MODULE
/**
* video_setup - process command line options
* @options: string of options
*
* Process command line options for frame buffer subsystem.
*
* NOTE: This function is a __setup and __init function.
* It only stores the options. Drivers have to call
* fb_get_options() as necessary.
*
* Returns zero.
*
*/
static int __init video_setup(char *options)
{
int i, global = 0;
if (!options || !*options)
global = 1;
if (!global && !strncmp(options, "ofonly", 6)) {
ofonly = 1;
global = 1;
}
if (!global && !strchr(options, ':')) {
fb_mode_option = options;
global = 1;
}
if (!global) {
for (i = 0; i < FB_MAX; i++) {
if (video_options[i] == NULL) {
video_options[i] = options;
break;
}
}
}
return 1;
}
__setup("video=", video_setup);
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -29,9 +29,6 @@ ...@@ -29,9 +29,6 @@
#define DPRINTK(fmt, args...) #define DPRINTK(fmt, args...)
#endif #endif
const char *fb_mode_option;
EXPORT_SYMBOL_GPL(fb_mode_option);
/* /*
* Standard video mode definitions (taken from XFree86) * Standard video mode definitions (taken from XFree86)
*/ */
......
...@@ -1294,6 +1294,8 @@ extern int drm_vblank_get(struct drm_device *dev, int crtc); ...@@ -1294,6 +1294,8 @@ extern int drm_vblank_get(struct drm_device *dev, int crtc);
extern void drm_vblank_put(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc);
extern int drm_crtc_vblank_get(struct drm_crtc *crtc); extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
extern void drm_crtc_vblank_put(struct drm_crtc *crtc); extern void drm_crtc_vblank_put(struct drm_crtc *crtc);
extern void drm_wait_one_vblank(struct drm_device *dev, int crtc);
extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
extern void drm_vblank_off(struct drm_device *dev, int crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc);
extern void drm_vblank_on(struct drm_device *dev, int crtc); extern void drm_vblank_on(struct drm_device *dev, int crtc);
extern void drm_crtc_vblank_off(struct drm_crtc *crtc); extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
......
...@@ -218,10 +218,6 @@ struct drm_property { ...@@ -218,10 +218,6 @@ struct drm_property {
struct list_head enum_blob_list; struct list_head enum_blob_list;
}; };
void drm_modeset_lock_all(struct drm_device *dev);
void drm_modeset_unlock_all(struct drm_device *dev);
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
struct drm_crtc; struct drm_crtc;
struct drm_connector; struct drm_connector;
struct drm_encoder; struct drm_encoder;
...@@ -345,10 +341,6 @@ struct drm_crtc { ...@@ -345,10 +341,6 @@ struct drm_crtc {
int cursor_x; int cursor_x;
int cursor_y; int cursor_y;
/* Temporary tracking of the old fb while a modeset is ongoing. Used
* by drm_mode_set_config_internal to implement correct refcounting. */
struct drm_framebuffer *old_fb;
bool enabled; bool enabled;
/* Requested mode from modesetting. */ /* Requested mode from modesetting. */
...@@ -375,6 +367,12 @@ struct drm_crtc { ...@@ -375,6 +367,12 @@ struct drm_crtc {
void *helper_private; void *helper_private;
struct drm_object_properties properties; struct drm_object_properties properties;
/*
* For legacy crtc ioctls so that atomic drivers can get at the locking
* acquire context.
*/
struct drm_modeset_acquire_ctx *acquire_ctx;
}; };
...@@ -548,6 +546,7 @@ struct drm_connector { ...@@ -548,6 +546,7 @@ struct drm_connector {
void *helper_private; void *helper_private;
/* forced on connector */ /* forced on connector */
struct drm_cmdline_mode cmdline_mode;
enum drm_connector_force force; enum drm_connector_force force;
bool override_edid; bool override_edid;
uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
...@@ -582,6 +581,7 @@ struct drm_plane_funcs { ...@@ -582,6 +581,7 @@ struct drm_plane_funcs {
uint32_t src_w, uint32_t src_h); uint32_t src_w, uint32_t src_h);
int (*disable_plane)(struct drm_plane *plane); int (*disable_plane)(struct drm_plane *plane);
void (*destroy)(struct drm_plane *plane); void (*destroy)(struct drm_plane *plane);
void (*reset)(struct drm_plane *plane);
int (*set_property)(struct drm_plane *plane, int (*set_property)(struct drm_plane *plane,
struct drm_property *property, uint64_t val); struct drm_property *property, uint64_t val);
...@@ -620,6 +620,10 @@ struct drm_plane { ...@@ -620,6 +620,10 @@ struct drm_plane {
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
/* Temporary tracking of the old fb while a modeset is ongoing. Used
* by drm_mode_set_config_internal to implement correct refcounting. */
struct drm_framebuffer *old_fb;
const struct drm_plane_funcs *funcs; const struct drm_plane_funcs *funcs;
struct drm_object_properties properties; struct drm_object_properties properties;
...@@ -903,6 +907,7 @@ int drm_connector_register(struct drm_connector *connector); ...@@ -903,6 +907,7 @@ int drm_connector_register(struct drm_connector *connector);
void drm_connector_unregister(struct drm_connector *connector); void drm_connector_unregister(struct drm_connector *connector);
extern void drm_connector_cleanup(struct drm_connector *connector); extern void drm_connector_cleanup(struct drm_connector *connector);
extern unsigned int drm_connector_index(struct drm_connector *connector);
/* helper to unplug all connectors from sysfs for device */ /* helper to unplug all connectors from sysfs for device */
extern void drm_connector_unplug_all(struct drm_device *dev); extern void drm_connector_unplug_all(struct drm_device *dev);
...@@ -942,6 +947,7 @@ extern int drm_plane_init(struct drm_device *dev, ...@@ -942,6 +947,7 @@ extern int drm_plane_init(struct drm_device *dev,
const uint32_t *formats, uint32_t format_count, const uint32_t *formats, uint32_t format_count,
bool is_primary); bool is_primary);
extern void drm_plane_cleanup(struct drm_plane *plane); extern void drm_plane_cleanup(struct drm_plane *plane);
extern unsigned int drm_plane_index(struct drm_plane *plane);
extern void drm_plane_force_disable(struct drm_plane *plane); extern void drm_plane_force_disable(struct drm_plane *plane);
extern int drm_crtc_check_viewport(const struct drm_crtc *crtc, extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
int x, int y, int x, int y,
......
...@@ -77,7 +77,6 @@ struct drm_fb_helper_funcs { ...@@ -77,7 +77,6 @@ struct drm_fb_helper_funcs {
struct drm_fb_helper_connector { struct drm_fb_helper_connector {
struct drm_connector *connector; struct drm_connector *connector;
struct drm_cmdline_mode cmdline_mode;
}; };
struct drm_fb_helper { struct drm_fb_helper {
......
...@@ -53,6 +53,11 @@ struct drm_modeset_acquire_ctx { ...@@ -53,6 +53,11 @@ struct drm_modeset_acquire_ctx {
* list of held locks (drm_modeset_lock) * list of held locks (drm_modeset_lock)
*/ */
struct list_head locked; struct list_head locked;
/**
* Trylock mode, use only for panic handlers!
*/
bool trylock_only;
}; };
/** /**
...@@ -120,6 +125,17 @@ int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock, ...@@ -120,6 +125,17 @@ int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock,
void drm_modeset_unlock(struct drm_modeset_lock *lock); void drm_modeset_unlock(struct drm_modeset_lock *lock);
struct drm_device; struct drm_device;
struct drm_crtc;
void drm_modeset_lock_all(struct drm_device *dev);
int __drm_modeset_lock_all(struct drm_device *dev, bool trylock);
void drm_modeset_unlock_all(struct drm_device *dev);
void drm_modeset_lock_crtc(struct drm_crtc *crtc);
void drm_modeset_unlock_crtc(struct drm_crtc *crtc);
void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
struct drm_modeset_acquire_ctx *
drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc);
int drm_modeset_lock_all_crtcs(struct drm_device *dev, int drm_modeset_lock_all_crtcs(struct drm_device *dev,
struct drm_modeset_acquire_ctx *ctx); struct drm_modeset_acquire_ctx *ctx);
......
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