diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-02-22 13:01:39 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-02-22 13:01:39 +1100 |
commit | 2735af74e1d9760a867997110d0c69a750100c0f (patch) | |
tree | 19092da2ef87b77654f0660f9d17da1affa7b418 /drivers/gpu | |
parent | c6299bd70e82739cb1eea346d070e33cfe5c0681 (diff) | |
parent | ee3f030e2fa19f968556c5bc3e80ba8b250e8bfb (diff) |
Merge remote branch 'kgdb/kgdb-next'
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 93 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 114 |
2 files changed, 195 insertions, 12 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 0f9e90552dc4..713e101f0c05 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -29,6 +29,7 @@ */ #include <linux/sysrq.h> #include <linux/fb.h> +#include <linux/kgdb.h> #include "drmP.h" #include "drm_crtc.h" #include "drm_fb_helper.h" @@ -233,6 +234,80 @@ 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_ops *ops) +{ + struct drm_fb_helper *helper = to_fb_helper(ops); + struct drm_crtc_helper_funcs *funcs; + int i; + + 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); + + } + } + + 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_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; @@ -321,9 +396,9 @@ static void drm_fb_helper_on(struct fb_info *info) !crtc->enabled) continue; - mutex_lock(&dev->mode_config.mutex); + dbg_safe_mutex_lock(&dev->mode_config.mutex); crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); + dbg_safe_mutex_unlock(&dev->mode_config.mutex); /* Found a CRTC on this fb, now find encoders */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -331,9 +406,9 @@ static void drm_fb_helper_on(struct fb_info *info) struct drm_encoder_helper_funcs *encoder_funcs; encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); + dbg_safe_mutex_lock(&dev->mode_config.mutex); encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); + dbg_safe_mutex_unlock(&dev->mode_config.mutex); } } } @@ -602,7 +677,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct drm_framebuffer *fb = fb_helper->fb; int depth; - if (var->pixclock != 0) + if (var->pixclock != 0 || in_dbg_master()) return -EINVAL; /* Need to resize the fb object !!! */ @@ -744,9 +819,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, modeset->y = var->yoffset; if (modeset->num_connectors) { - mutex_lock(&dev->mode_config.mutex); + dbg_safe_mutex_lock(&dev->mode_config.mutex); ret = crtc->funcs->set_config(modeset); - mutex_unlock(&dev->mode_config.mutex); + dbg_safe_mutex_unlock(&dev->mode_config.mutex); if (!ret) { info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; @@ -923,6 +998,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_ops_register(&fb_helper->kdb_ops); printk(KERN_INFO "registered panic notifier\n"); atomic_notifier_chain_register(&panic_notifier_list, &paniced); @@ -937,6 +1015,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_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 b27202d23ebc..700d4b134240 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -991,6 +991,13 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, void intel_wait_for_vblank(struct drm_device *dev) { + if (in_dbg_master()) { + /* When in the kernel debugger we cannot sleep */ + preempt_disable(); + mdelay(20); + preempt_enable(); + return; + } /* Wait for 20ms, i.e. one cycle at 50hz. */ msleep(20); } @@ -1210,6 +1217,10 @@ static void intel_update_fbc(struct drm_crtc *crtc, goto out_disable; } + /* If the kernel debugger is active, always disable compression */ + if (in_dbg_master()) + goto out_disable; + if (dev_priv->display.fbc_enabled(crtc)) { /* We can re-enable it in this case, but need to update pitch */ if (fb->pitch > dev_priv->cfb_pitch) @@ -1278,6 +1289,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) @@ -1319,17 +1422,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, obj = intel_fb->obj; obj_priv = obj->driver_private; - mutex_lock(&dev->struct_mutex); + dbg_safe_mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, obj); if (ret != 0) { - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); return ret; } ret = i915_gem_object_set_to_display_plane(obj); if (ret != 0) { i915_gem_object_unpin(obj); - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); return ret; } @@ -1356,7 +1459,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, default: DRM_ERROR("Unknown color depth\n"); i915_gem_object_unpin(obj); - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); return -EINVAL; } if (IS_I965G(dev)) { @@ -1400,7 +1503,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } intel_increase_pllclock(crtc, true); - mutex_unlock(&dev->struct_mutex); + dbg_safe_mutex_unlock(&dev->struct_mutex); if (!dev->primary->master) return 0; @@ -4257,6 +4360,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, |