X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fi915%2Fi915_drv.c;h=2c87f9b97b6fc4d86bbcac5adbb6e5812ec4a855;hb=881f47b64723f4d697084533491a489e3e74b10f;hp=216deb579785eb93e27e2ba57a0556471a13daf2;hpb=ce7db282a3830f57f5b05ec48288c23a5c4d66d5;p=linux-2.6-block.git diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 216deb579785..2c87f9b97b6f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -32,6 +32,7 @@ #include "drm.h" #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" #include #include "drm_crtc_helper.h" @@ -61,86 +62,108 @@ extern int intel_agp_enabled; .driver_data = (unsigned long) info } static const struct intel_device_info intel_i830_info = { - .gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_845g_info = { - .gen = 2, .is_i8xx = 1, + .gen = 2, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i85x_info = { - .gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, + .gen = 2, .is_i85x = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i865g_info = { - .gen = 2, .is_i8xx = 1, + .gen = 2, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915g_info = { - .gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1, + .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i915gm_info = { - .gen = 3, .is_i9xx = 1, .is_mobile = 1, + .gen = 3, .is_mobile = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, + .supports_tv = 1, }; static const struct intel_device_info intel_i945g_info = { - .gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1, + .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, }; static const struct intel_device_info intel_i945gm_info = { - .gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, + .gen = 3, .is_i945gm = 1, .is_mobile = 1, .has_hotplug = 1, .cursor_needs_physical = 1, + .has_overlay = 1, .overlay_needs_physical = 1, + .supports_tv = 1, }; static const struct intel_device_info intel_i965g_info = { - .gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, + .gen = 4, .is_broadwater = 1, .has_hotplug = 1, + .has_overlay = 1, }; static const struct intel_device_info intel_i965gm_info = { - .gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1, + .gen = 4, .is_crestline = 1, .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, + .has_overlay = 1, + .supports_tv = 1, }; static const struct intel_device_info intel_g33_info = { - .gen = 3, .is_g33 = 1, .is_i9xx = 1, + .gen = 3, .is_g33 = 1, .need_gfx_hws = 1, .has_hotplug = 1, + .has_overlay = 1, }; static const struct intel_device_info intel_g45_info = { - .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1, + .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_gm45_info = { - .gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, + .gen = 4, .is_g4x = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, + .supports_tv = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_pineview_info = { - .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1, + .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_hotplug = 1, + .has_overlay = 1, }; static const struct intel_device_info intel_ironlake_d_info = { - .gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, + .gen = 5, .is_ironlake = 1, .need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_ironlake_m_info = { - .gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, + .gen = 5, .is_ironlake = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_sandybridge_d_info = { - .gen = 6, .is_i965g = 1, .is_i9xx = 1, + .gen = 6, .need_gfx_hws = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct intel_device_info intel_sandybridge_m_info = { - .gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, + .gen = 6, .is_mobile = 1, .need_gfx_hws = 1, .has_hotplug = 1, + .has_bsd_ring = 1, }; static const struct pci_device_id pciidlist[] = { /* aka */ @@ -170,6 +193,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), /* G45_G */ INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), /* G41_G */ INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), /* B43_G */ + INTEL_VGA_DEVICE(0x2e92, &intel_g45_info), /* B43_G.1 */ INTEL_VGA_DEVICE(0xa001, &intel_pineview_info), INTEL_VGA_DEVICE(0xa011, &intel_pineview_info), INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info), @@ -236,7 +260,7 @@ static int i915_drm_freeze(struct drm_device *dev) i915_save_state(dev); - intel_opregion_free(dev, 1); + intel_opregion_fini(dev); /* Modeset on resume, not lid events */ dev_priv->modeset_on_lid = 0; @@ -276,8 +300,7 @@ static int i915_drm_thaw(struct drm_device *dev) int error = 0; i915_restore_state(dev); - - intel_opregion_init(dev, 1); + intel_opregion_setup(dev); /* KMS EnterVT equivalent */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { @@ -293,6 +316,8 @@ static int i915_drm_thaw(struct drm_device *dev) drm_helper_resume_force_mode(dev); } + intel_opregion_init(dev); + dev_priv->modeset_on_lid = 0; return error; @@ -308,6 +333,31 @@ int i915_resume(struct drm_device *dev) return i915_drm_thaw(dev); } +static int i965_reset_complete(struct drm_device *dev) +{ + u8 gdrst; + pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); + return gdrst & 0x1; +} + +static int i965_do_reset(struct drm_device *dev, u8 flags) +{ + u8 gdrst; + + pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); + pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1); + + return wait_for(i965_reset_complete(dev), 500); +} + +static int ironlake_do_reset(struct drm_device *dev, u8 flags) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1); + return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); +} + /** * i965_reset - reset chip after a hang * @dev: drm device to reset @@ -324,16 +374,15 @@ int i915_resume(struct drm_device *dev) * - re-init interrupt state * - re-init display */ -int i965_reset(struct drm_device *dev, u8 flags) +int i915_reset(struct drm_device *dev, u8 flags) { drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long timeout; - u8 gdrst; /* * We really should only reset the display subsystem if we actually * need to */ bool need_display = true; + int ret; mutex_lock(&dev->struct_mutex); @@ -342,36 +391,35 @@ int i965_reset(struct drm_device *dev, u8 flags) */ i915_gem_retire_requests(dev); - if (need_display) - i915_save_display(dev); - - if (IS_I965G(dev) || IS_G4X(dev)) { - /* - * Set the domains we want to reset, then the reset bit (bit 0). - * Clear the reset bit after a while and wait for hardware status - * bit (bit 1) to be set - */ - pci_read_config_byte(dev->pdev, GDRST, &gdrst); - pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0)); - udelay(50); - pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe); - - /* ...we don't want to loop forever though, 500ms should be plenty */ - timeout = jiffies + msecs_to_jiffies(500); - do { - udelay(100); - pci_read_config_byte(dev->pdev, GDRST, &gdrst); - } while ((gdrst & 0x1) && time_after(timeout, jiffies)); - - if (gdrst & 0x1) { - WARN(true, "i915: Failed to reset chip\n"); - mutex_unlock(&dev->struct_mutex); - return -EIO; - } - } else { - DRM_ERROR("Error occurred. Don't know how to reset this chip.\n"); + /* Remove anything from the flushing lists. The GPU cache is likely + * to be lost on reset along with the data, so simply move the + * lost bo to the inactive list. + */ + i915_gem_reset_flushing_list(dev); + + /* Move everything out of the GPU domains to ensure we do any + * necessary invalidation upon reuse. + */ + i915_gem_reset_inactive_gpu_domains(dev); + + /* + * Set the domains we want to reset (GRDOM/bits 2 and 3) as + * well as the reset bit (GR/bit 0). Setting the GR bit + * triggers the reset; when done, the hardware will clear it. + */ + ret = -ENODEV; + switch (INTEL_INFO(dev)->gen) { + case 5: + ret = ironlake_do_reset(dev, flags); + break; + case 4: + ret = i965_do_reset(dev, flags); + break; + } + if (ret) { + DRM_ERROR("Failed to reset chip.\n"); mutex_unlock(&dev->struct_mutex); - return -ENODEV; + return ret; } /* Ok, now get things going again... */ @@ -399,13 +447,19 @@ int i965_reset(struct drm_device *dev, u8 flags) mutex_lock(&dev->struct_mutex); } + mutex_unlock(&dev->struct_mutex); + /* - * Display needs restore too... + * Perform a full modeset as on later generations, e.g. Ironlake, we may + * need to retrain the display link and cannot just restore the register + * values. */ - if (need_display) - i915_restore_display(dev); + if (need_display) { + mutex_lock(&dev->mode_config.mutex); + drm_helper_resume_force_mode(dev); + mutex_unlock(&dev->mode_config.mutex); + } - mutex_unlock(&dev->struct_mutex); return 0; } @@ -523,8 +577,6 @@ static struct drm_driver driver = { .irq_uninstall = i915_driver_irq_uninstall, .irq_handler = i915_driver_irq_handler, .reclaim_buffers = drm_core_reclaim_buffers, - .get_map_ofs = drm_core_get_map_ofs, - .get_reg_ofs = drm_core_get_reg_ofs, .master_create = i915_master_create, .master_destroy = i915_master_destroy, #if defined(CONFIG_DEBUG_FS)