From 8bcd45534ddf68ab71aeed709dacd9cf65dc0f75 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 7 Feb 2014 12:10:38 -0800 Subject: drm/i915: alloc intel_fb in the intel_fbdev struct Allocate this struct instead, so we can re-use another allocated elsewhere if needed. Signed-off-by: Jesse Barnes [danvet: WARN_ON if there's no backing storage attached to an fb, that's a bug.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_fbdev.c') diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index d6a8a716018..cd969c3c301 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -62,11 +62,20 @@ static int intelfb_alloc(struct drm_fb_helper *helper, { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); + struct intel_framebuffer *fb; struct drm_device *dev = helper->dev; struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; int size, ret; + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) { + ret = -ENOMEM; + goto out; + } + + ifbdev->fb = fb; + /* we don't do packed 24bpp */ if (sizes->surface_bpp == 24) sizes->surface_bpp = 32; @@ -97,7 +106,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper, goto out_unref; } - ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj); + ret = intel_framebuffer_init(dev, ifbdev->fb, &mode_cmd, obj); if (ret) goto out_unpin; @@ -116,7 +125,7 @@ static int intelfb_create(struct drm_fb_helper *helper, { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); - struct intel_framebuffer *intel_fb = &ifbdev->ifb; + struct intel_framebuffer *intel_fb = ifbdev->fb; struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; @@ -126,11 +135,12 @@ static int intelfb_create(struct drm_fb_helper *helper, mutex_lock(&dev->struct_mutex); - if (!intel_fb->obj) { + if (!intel_fb || WARN_ON(!intel_fb->obj)) { DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); ret = intelfb_alloc(helper, sizes); if (ret) goto out_unlock; + intel_fb = ifbdev->fb; } else { DRM_DEBUG_KMS("re-using BIOS fb\n"); sizes->fb_width = intel_fb->base.width; @@ -148,7 +158,7 @@ static int intelfb_create(struct drm_fb_helper *helper, info->par = helper; - fb = &ifbdev->ifb.base; + fb = &ifbdev->fb->base; ifbdev->helper.fb = fb; ifbdev->helper.fbdev = info; @@ -194,7 +204,7 @@ static int intelfb_create(struct drm_fb_helper *helper, * If the object is stolen however, it will be full of whatever * garbage was left in there. */ - if (ifbdev->ifb.obj->stolen) + if (ifbdev->fb->obj->stolen) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ @@ -258,8 +268,9 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_fb_helper_fini(&ifbdev->helper); - drm_framebuffer_unregister_private(&ifbdev->ifb.base); - intel_framebuffer_fini(&ifbdev->ifb); + drm_framebuffer_unregister_private(&ifbdev->fb->base); + intel_framebuffer_fini(ifbdev->fb); + kfree(ifbdev->fb); } int intel_fbdev_init(struct drm_device *dev) @@ -322,7 +333,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state) * been restored from swap. If the object is stolen however, it will be * full of whatever garbage was left in there. */ - if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen) + if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen) memset_io(info->screen_base, 0, info->screen_size); fb_set_suspend(info, state); -- cgit v1.2.3-70-g09d2 From ef2d633e9bcfdb73e536ca81b835dd015fe24ceb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 10 Feb 2014 18:00:38 +0100 Subject: drm/i915: Use normal fb deref for the fbcon framebuffer Now that it's a normally kmalloce buffer we can use the usual cleanup paths. The upside here is that if we get the refcounting wrong will be able to catch it, since the drm core will complain about leftover framebuffers and kref about underflows. v2: Kill intel_framebuffer_fini - no longer needed now that we refcount all fbs properly and only confusing. v3: We actually still need to call unregister_private to remove the fb from the idr and drop the idr reference - the final unref doesn't do that. So much for remembering my own fb liftime rules. Reported by Imre Deak. Cc: Jesse Barnes Reviewed-by: Jesse Barnes (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 +++-------- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_fbdev.c | 3 +-- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_fbdev.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b2faa44764..6600931f213 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10526,18 +10526,13 @@ static void intel_setup_outputs(struct drm_device *dev) drm_helper_move_panel_connectors_to_head(dev); } -void intel_framebuffer_fini(struct intel_framebuffer *fb) -{ - drm_framebuffer_cleanup(&fb->base); - WARN_ON(!fb->obj->framebuffer_references--); - drm_gem_object_unreference_unlocked(&fb->obj->base); -} - static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) { struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - intel_framebuffer_fini(intel_fb); + drm_framebuffer_cleanup(fb); + WARN_ON(!intel_fb->obj->framebuffer_references--); + drm_gem_object_unreference_unlocked(&intel_fb->obj->base); kfree(intel_fb); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4386faf34a9..59348a4d023 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -685,7 +685,6 @@ int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); -void intel_framebuffer_fini(struct intel_framebuffer *fb); void intel_prepare_page_flip(struct drm_device *dev, int plane); void intel_finish_page_flip(struct drm_device *dev, int pipe); void intel_finish_page_flip_plane(struct drm_device *dev, int plane); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index cd969c3c301..9aa26e59a1a 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -269,8 +269,7 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_fb_helper_fini(&ifbdev->helper); drm_framebuffer_unregister_private(&ifbdev->fb->base); - intel_framebuffer_fini(ifbdev->fb); - kfree(ifbdev->fb); + drm_framebuffer_unreference(&ifbdev->fb->base); } int intel_fbdev_init(struct drm_device *dev) -- cgit v1.2.3-70-g09d2 From a8bb6818270c32126dba0fd2ddb139d885c5687d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 10 Feb 2014 18:00:39 +0100 Subject: drm/i915: Fix error path leak in fbdev fb allocation In Jesse's patch to switch the fbdev framebuffer from an embedded struct to a pointer the kfree in case of an error was missed. Fix this up by using our own internal fb allocation helper directly instead of reinventing that wheel. We need a to_intel_framebuffer cast unfortunately since all the other callers of _create still look better whith using a drm_framebuffer as return pointer. v2: Add an unlocked __intel_framebuffer_create function since our dev->struct_mutex locking is too much a mess. With ppgtt we even need it to take a look at the global gtt offset of pinned objects, since the vma list might chance from underneath us. At least with the current global gtt lookup functions. Reported by Mika. Cc: Mika Kuoppala Cc: Jesse Barnes Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 35 ++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 4 ++-- drivers/gpu/drm/i915/intel_fbdev.c | 20 ++++++++------------ 3 files changed, 36 insertions(+), 23 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_fbdev.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6600931f213..6ac4c23acc7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7690,10 +7690,15 @@ static struct drm_display_mode load_detect_mode = { 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), }; -static struct drm_framebuffer * -intel_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_i915_gem_object *obj) +static int intel_framebuffer_init(struct drm_device *dev, + struct intel_framebuffer *ifb, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_i915_gem_object *obj); + +struct drm_framebuffer * +__intel_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_i915_gem_object *obj) { struct intel_framebuffer *intel_fb; int ret; @@ -7704,12 +7709,7 @@ intel_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOMEM); } - ret = i915_mutex_lock_interruptible(dev); - if (ret) - goto err; - ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); - mutex_unlock(&dev->struct_mutex); if (ret) goto err; @@ -7721,6 +7721,23 @@ err: return ERR_PTR(ret); } +struct drm_framebuffer * +intel_framebuffer_create(struct drm_device *dev, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_i915_gem_object *obj) +{ + struct drm_framebuffer *fb; + int ret; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ERR_PTR(ret); + fb = __intel_framebuffer_create(dev, mode_cmd, obj); + mutex_unlock(&dev->struct_mutex); + + return fb; +} + static u32 intel_framebuffer_pitch_for_width(int width, int bpp) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 59348a4d023..aff9171a91d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -681,8 +681,8 @@ int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, struct intel_ring_buffer *pipelined); void intel_unpin_fb_obj(struct drm_i915_gem_object *obj); -int intel_framebuffer_init(struct drm_device *dev, - struct intel_framebuffer *ifb, +struct drm_framebuffer * +__intel_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); void intel_prepare_page_flip(struct drm_device *dev, int plane); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 9aa26e59a1a..cf4627387c5 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -62,20 +62,12 @@ static int intelfb_alloc(struct drm_fb_helper *helper, { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); - struct intel_framebuffer *fb; + struct drm_framebuffer *fb; struct drm_device *dev = helper->dev; struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; int size, ret; - fb = kzalloc(sizeof(*fb), GFP_KERNEL); - if (!fb) { - ret = -ENOMEM; - goto out; - } - - ifbdev->fb = fb; - /* we don't do packed 24bpp */ if (sizes->surface_bpp == 24) sizes->surface_bpp = 32; @@ -102,13 +94,17 @@ static int intelfb_alloc(struct drm_fb_helper *helper, /* Flush everything out, we'll be doing GTT only from now on */ ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) { - DRM_ERROR("failed to pin fb: %d\n", ret); + DRM_ERROR("failed to pin obj: %d\n", ret); goto out_unref; } - ret = intel_framebuffer_init(dev, ifbdev->fb, &mode_cmd, obj); - if (ret) + fb = __intel_framebuffer_create(dev, &mode_cmd, obj); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); goto out_unpin; + } + + ifbdev->fb = to_intel_framebuffer(fb); return 0; -- cgit v1.2.3-70-g09d2 From 9d6612516da0b7592dac221d1c836d7a906bb3c5 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 12 Feb 2014 00:01:10 +0200 Subject: drm/i915: unbind fbs from crtcs during driver unload So far during driver unload we called drm_framebuffer_cleanup() for the fbdev fb, which only removes the fb from the drm fb list regardless of its reference count, but leaves the fb bound on an active crtc. Since the fb's backing storage was freed this could mean we scan some random memory content out afterwards. It's not a big issue since the fb is allocated from stolen memory and afaik there is no other user for that than i915. It's still cleaner to properly unbind the fb and disable the crtc, which is what drm_framebuffer_remove() does. Note that after commit 88891eb1e9eca0ba619518bed31580f91e9cf84d Author: Daniel Vetter Date: Mon Feb 10 18:00:38 2014 +0100 we call drm_framebuffer_cleanup() only after dropping the last reference on the fb, but that won't happen since we don't unbind the fb. This results in a drm core warn about a leaked fb. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/i915/intel_fbdev.c') diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index cf4627387c5..3a53ee30706 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -265,7 +265,7 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_fb_helper_fini(&ifbdev->helper); drm_framebuffer_unregister_private(&ifbdev->fb->base); - drm_framebuffer_unreference(&ifbdev->fb->base); + drm_framebuffer_remove(&ifbdev->fb->base); } int intel_fbdev_init(struct drm_device *dev) -- cgit v1.2.3-70-g09d2 From eb1bfe807cb7b62a326fa20df5e3118a32c6f923 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 12 Feb 2014 12:26:25 -0800 Subject: drm/i915: allow re-use BIOS connector config for initial fbdev config v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BIOS or boot loader will generally create an initial display configuration for us that includes some set of active pipes and displays. This routine tries to figure out which pipes and connectors are active and stuffs them into the crtcs and modes array given to us by the drm_fb_helper code. The overall sequence is: intel_fbdev_init - from driver load intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data drm_fb_helper_init - build fb helper structs drm_fb_helper_single_add_all_connectors - more fb helper structs intel_fbdev_initial_config - apply the config drm_fb_helper_initial_config - call ->probe then register_framebuffer() drm_setup_crtcs - build crtc config for fbdev intel_fb_initial_config - find active connectors etc drm_fb_helper_single_fb_probe - set up fbdev intelfb_create - re-use or alloc fb, build out fbdev structs v2: use BIOS connector config unconditionally if possible (Daniel) check for crtc cloning and reject (Daniel) fix up comments (Daniel) v3: use command line args and preferred modes first (Ville) Signed-off-by: Jesse Barnes Tested-by: Ville Syrjälä [danvet: Re-add the WARN_ON for a missing encoder crtc - the state sanitizer should take care of this. And spell-ocd the comments.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 ++- drivers/gpu/drm/i915/intel_fbdev.c | 123 +++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_fbdev.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2cc18e516a2..ede87aa3b24 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -51,7 +51,10 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc, static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *old_fb); - +static int intel_framebuffer_init(struct drm_device *dev, + struct intel_framebuffer *ifb, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_i915_gem_object *obj); typedef struct { int min, max; @@ -7692,11 +7695,6 @@ static struct drm_display_mode load_detect_mode = { 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), }; -static int intel_framebuffer_init(struct drm_device *dev, - struct intel_framebuffer *ifb, - struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_i915_gem_object *obj); - struct drm_framebuffer * __intel_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 3a53ee30706..25d2746fe69 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -242,7 +242,130 @@ static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, *blue = intel_crtc->lut_b[regno] << 8; } +static struct drm_fb_helper_crtc * +intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) +{ + int i; + + for (i = 0; i < fb_helper->crtc_count; i++) + if (fb_helper->crtc_info[i].mode_set.crtc == crtc) + return &fb_helper->crtc_info[i]; + + return NULL; +} + +/* + * Try to read the BIOS display configuration and use it for the initial + * fb configuration. + * + * The BIOS or boot loader will generally create an initial display + * configuration for us that includes some set of active pipes and displays. + * This routine tries to figure out which pipes and connectors are active + * and stuffs them into the crtcs and modes array given to us by the + * drm_fb_helper code. + * + * The overall sequence is: + * intel_fbdev_init - from driver load + * intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data + * drm_fb_helper_init - build fb helper structs + * drm_fb_helper_single_add_all_connectors - more fb helper structs + * intel_fbdev_initial_config - apply the config + * drm_fb_helper_initial_config - call ->probe then register_framebuffer() + * drm_setup_crtcs - build crtc config for fbdev + * intel_fb_initial_config - find active connectors etc + * drm_fb_helper_single_fb_probe - set up fbdev + * intelfb_create - re-use or alloc fb, build out fbdev structs + * + * Note that we don't make special consideration whether we could actually + * switch to the selected modes without a full modeset. E.g. when the display + * is in VGA mode we need to recalculate watermarks and set a new high-res + * framebuffer anyway. + */ +static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_crtc **crtcs, + struct drm_display_mode **modes, + bool *enabled, int width, int height) +{ + int i, j; + + for (i = 0; i < fb_helper->connector_count; i++) { + struct drm_fb_helper_connector *fb_conn; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_fb_helper_crtc *new_crtc; + + fb_conn = fb_helper->connector_info[i]; + connector = fb_conn->connector; + if (!enabled[i]) { + DRM_DEBUG_KMS("connector %d not enabled, skipping\n", + connector->base.id); + continue; + } + + encoder = connector->encoder; + if (!encoder || WARN_ON(!encoder->crtc)) { + DRM_DEBUG_KMS("connector %d has no encoder or crtc, skipping\n", + connector->base.id); + enabled[i] = false; + continue; + } + + new_crtc = intel_fb_helper_crtc(fb_helper, encoder->crtc); + + /* + * Make sure we're not trying to drive multiple connectors + * with a single CRTC, since our cloning support may not + * match the BIOS. + */ + for (j = 0; j < fb_helper->connector_count; j++) { + if (crtcs[j] == new_crtc) + return false; + } + + DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", + fb_conn->connector->base.id); + + /* go for command line mode first */ + modes[i] = drm_pick_cmdline_mode(fb_conn, width, height); + + /* try for preferred next */ + if (!modes[i]) { + DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", + fb_conn->connector->base.id); + modes[i] = drm_has_preferred_mode(fb_conn, width, + height); + } + + /* last resort: use current mode */ + if (!modes[i]) { + /* + * IMPORTANT: We want to use the adjusted mode (i.e. + * after the panel fitter upscaling) as the initial + * config, not the input mode, which is what crtc->mode + * usually contains. But since our current fastboot + * code puts a mode derived from the post-pfit timings + * into crtc->mode this works out correctly. We don't + * use hwmode anywhere right now, so use it for this + * since the fb helper layer wants a pointer to + * something we own. + */ + intel_mode_from_pipe_config(&encoder->crtc->hwmode, + &to_intel_crtc(encoder->crtc)->config); + modes[i] = &encoder->crtc->hwmode; + } + crtcs[i] = new_crtc; + + DRM_DEBUG_KMS("connector %s on crtc %d: %s\n", + drm_get_connector_name(connector), + encoder->crtc->base.id, + modes[i]->name); + } + + return true; +} + static struct drm_fb_helper_funcs intel_fb_helper_funcs = { + .initial_config = intel_fb_initial_config, .gamma_set = intel_crtc_fb_gamma_set, .gamma_get = intel_crtc_fb_gamma_get, .fb_probe = intelfb_create, -- cgit v1.2.3-70-g09d2 From 02f5eebb63ad52c832a81109d68718df6cb1155e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 12 Feb 2014 15:03:40 -0800 Subject: drm/i915: don't preserve inherited configs with nothing on v2 It can be corrected later and may be what was actually desired, but generally isn't, so if we find nothing is enabled, let the core DRM fb helper figure something out. v2: free the array too (Jesse) Note that this also undoes any changes in case we bail out due to hw cloning. Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_fbdev.c') diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 25d2746fe69..19be4bfbcc5 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -286,7 +286,17 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, struct drm_display_mode **modes, bool *enabled, int width, int height) { + struct drm_device *dev = fb_helper->dev; int i, j; + bool *save_enabled; + bool any_enabled = false; + + save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), + GFP_KERNEL); + if (!save_enabled) + return false; + + memcpy(save_enabled, enabled, dev->mode_config.num_connector); for (i = 0; i < fb_helper->connector_count; i++) { struct drm_fb_helper_connector *fb_conn; @@ -318,8 +328,10 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, * match the BIOS. */ for (j = 0; j < fb_helper->connector_count; j++) { - if (crtcs[j] == new_crtc) - return false; + if (crtcs[j] == new_crtc) { + any_enabled = false; + goto out; + } } DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", @@ -359,8 +371,18 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, drm_get_connector_name(connector), encoder->crtc->base.id, modes[i]->name); + + any_enabled = true; + } + +out: + if (!any_enabled) { + memcpy(enabled, save_enabled, dev->mode_config.num_connector); + kfree(save_enabled); + return false; } + kfree(save_enabled); return true; } -- cgit v1.2.3-70-g09d2