Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756394AbZLWVne (ORCPT ); Wed, 23 Dec 2009 16:43:34 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753612AbZLWVnd (ORCPT ); Wed, 23 Dec 2009 16:43:33 -0500 Received: from mail.windriver.com ([147.11.1.11]:48127 "EHLO mail.windriver.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751165AbZLWVnd (ORCPT ); Wed, 23 Dec 2009 16:43:33 -0500 From: Jason Wessel To: linux-kernel@vger.kernel.org Cc: kgdb-bugreport@lists.sourceforge.net, kdb@oss.sgi.com, mingo@elte.hu, Jesse Barnes Subject: [PATCH 33/37] drm: add KGDB/KDB support Add support for KDB entry/exit. Date: Wed, 23 Dec 2009 15:43:00 -0600 Message-Id: <1261604584-5796-1-git-send-email-jason.wessel@windriver.com> X-Mailer: git-send-email 1.6.4.rc1 In-Reply-To: <1261603190-5036-33-git-send-email-jason.wessel@windriver.com> References: <1261603190-5036-33-git-send-email-jason.wessel@windriver.com> X-OriginalArrivalTime: 23 Dec 2009 21:43:15.0029 (UTC) FILETIME=[EE94C850:01CA8418] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8287 Lines: 280 From: Jesse Barnes --- drivers/gpu/drm/drm_fb_helper.c | 83 ++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 93 ++++++++++++++++++++++++++++++++++ include/drm/drm_crtc_helper.h | 2 + include/drm/drm_fb_helper.h | 4 ++ 4 files changed, 182 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 1b49fa0..80aab3c 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -29,6 +29,7 @@ */ #include #include +#include #include "drmP.h" #include "drm_crtc.h" #include "drm_fb_helper.h" @@ -233,6 +234,84 @@ int drm_fb_helper_parse_command_line(struct drm_device *dev) return 0; } +#define to_fb_helper(ops) (container_of((ops), struct drm_fb_helper, kdb_ops)) + +static int drm_fb_kdb_enter(struct dbg_kms_console_ops *ops) +{ + struct drm_fb_helper *helper = to_fb_helper(ops); + struct drm_crtc_helper_funcs *funcs; + int i; + + if (atomic_read(&kgdb_active)) + goto out; /* already in KDB, don't reset mode */ + + if (list_empty(&kernel_fb_helper_list)) + return false; + + list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { + for (i = 0; i < helper->crtc_count; i++) { + struct drm_mode_set *mode_set = + &helper->crtc_info[i].mode_set; + + if (!mode_set->crtc->enabled) + continue; + + funcs = mode_set->crtc->helper_private; + funcs->mode_set_base_atomic(mode_set->crtc, + mode_set->fb, + mode_set->x, + mode_set->y); + + } + } + +out: + return 0; +} + +/* Find the real fb for a given fb helper CRTC */ +static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_crtc *c; + + list_for_each_entry(c, &dev->mode_config.crtc_list, head) { + if (crtc->base.id == c->base.id) + return c->fb; + } + + return NULL; +} + +static int drm_fb_kdb_exit(struct dbg_kms_console_ops *ops) +{ + struct drm_fb_helper *helper = to_fb_helper(ops); + struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *funcs; + struct drm_framebuffer *fb; + int i; + + for (i = 0; i < helper->crtc_count; i++) { + struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; + crtc = mode_set->crtc; + funcs = crtc->helper_private; + fb = drm_mode_config_fb(crtc); + + if (!crtc->enabled) + continue; + + if (!fb) { + DRM_ERROR("no fb to restore??\n"); + continue; + } + + funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, + crtc->y); + } + + return 0; +} + bool drm_fb_helper_force_kernel_mode(void) { int i = 0; @@ -924,6 +1003,9 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, /* Switch back to kernel console on panic */ /* multi card linked list maybe */ if (list_empty(&kernel_fb_helper_list)) { + fb_helper->kdb_ops.activate_console = drm_fb_kdb_enter; + fb_helper->kdb_ops.restore_console = drm_fb_kdb_exit; + dbg_kms_console_ops_register(&fb_helper->kdb_ops); printk(KERN_INFO "registered panic notifier\n"); atomic_notifier_chain_register(&panic_notifier_list, &paniced); @@ -938,6 +1020,7 @@ void drm_fb_helper_free(struct drm_fb_helper *helper) { list_del(&helper->kernel_fb_list); if (list_empty(&kernel_fb_helper_list)) { + dbg_kms_console_ops_unregister(&helper->kdb_ops); printk(KERN_INFO "unregistered panic notifier\n"); atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 52cd9b0..e134a81 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1234,6 +1234,98 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) return 0; } +/* Assume fb object is pinned & idle & fenced and just update base pointers */ +static int +intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *obj; + int plane = intel_crtc->plane; + unsigned long Start, Offset; + int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR); + int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF); + int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; + int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + u32 dspcntr; + + switch (plane) { + case 0: + case 1: + break; + default: + DRM_ERROR("Can't update plane %d in SAREA\n", plane); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + obj_priv = obj->driver_private; + + dspcntr = I915_READ(dspcntr_reg); + /* Mask out pixel format bits in case we change it */ + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + switch (fb->bits_per_pixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (fb->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 24: + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + DRM_ERROR("Unknown color depth\n"); + return -EINVAL; + } + if (IS_I965G(dev)) { + if (obj_priv->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else + dspcntr &= ~DISPPLANE_TILED; + } + + if (IS_IRONLAKE(dev)) + /* must disable */ + dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + + I915_WRITE(dspcntr_reg, dspcntr); + + Start = obj_priv->gtt_offset; + Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); + + DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); + I915_WRITE(dspstride, fb->pitch); + if (IS_I965G(dev)) { + I915_WRITE(dspbase, Offset); + I915_READ(dspbase); + I915_WRITE(dspsurf, Start); + I915_READ(dspsurf); + I915_WRITE(dsptileoff, (y << 16) | x); + } else { + I915_WRITE(dspbase, Start + Offset); + I915_READ(dspbase); + } + + if ((IS_I965G(dev) || plane == 0)) + intel_update_fbc(crtc, &crtc->mode); + + intel_wait_for_vblank(dev); + intel_increase_pllclock(crtc, true); + + return 0; +} + static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) @@ -4243,6 +4335,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, + .mode_set_base_atomic = intel_pipe_set_base_atomic, .prepare = intel_crtc_prepare, .commit = intel_crtc_commit, .load_lut = intel_crtc_load_lut, diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index b29e201..4c12319 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -61,6 +61,8 @@ struct drm_crtc_helper_funcs { /* Move the crtc on the current fb to the given position *optional* */ int (*mode_set_base)(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); + int (*mode_set_base_atomic)(struct drm_crtc *crtc, + struct drm_framebuffer *fb, int x, int y); /* reload the current crtc LUT */ void (*load_lut)(struct drm_crtc *crtc); diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 58c892a..c4f87a5 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -30,6 +30,8 @@ #ifndef DRM_FB_HELPER_H #define DRM_FB_HELPER_H +#include + struct drm_fb_helper_crtc { uint32_t crtc_id; struct drm_mode_set mode_set; @@ -63,8 +65,10 @@ struct drm_fb_helper_connector { struct drm_fb_helper { struct drm_framebuffer *fb; + struct drm_framebuffer *saved_fb; struct drm_device *dev; struct drm_display_mode *mode; + struct dbg_kms_console_ops kdb_ops; int crtc_count; struct drm_fb_helper_crtc *crtc_info; struct drm_fb_helper_funcs *funcs; -- 1.6.4.rc1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/