From owner-svn-src-all@freebsd.org Tue Oct 27 21:23:20 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id E15D7A1CCD4; Tue, 27 Oct 2015 21:23:20 +0000 (UTC) (envelope-from dumbbell@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A727F11C1; Tue, 27 Oct 2015 21:23:20 +0000 (UTC) (envelope-from dumbbell@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t9RLNJrU070297; Tue, 27 Oct 2015 21:23:19 GMT (envelope-from dumbbell@FreeBSD.org) Received: (from dumbbell@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t9RLNJPU070296; Tue, 27 Oct 2015 21:23:19 GMT (envelope-from dumbbell@FreeBSD.org) Message-Id: <201510272123.t9RLNJPU070296@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: dumbbell set sender to dumbbell@FreeBSD.org using -f From: =?UTF-8?Q?Jean-S=c3=a9bastien_P=c3=a9dron?= Date: Tue, 27 Oct 2015 21:23:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r290070 - head/sys/dev/drm2/i915 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Oct 2015 21:23:21 -0000 Author: dumbbell Date: Tue Oct 27 21:23:19 2015 New Revision: 290070 URL: https://svnweb.freebsd.org/changeset/base/290070 Log: drm/i915: Reduce diff with Linux 3.8 There is no functional change. The goal is to ease the future update to Linux 3.8's i915 driver. MFC after: 2 months Modified: head/sys/dev/drm2/i915/i915_drv.c Modified: head/sys/dev/drm2/i915/i915_drv.c ============================================================================== --- head/sys/dev/drm2/i915/i915_drv.c Tue Oct 27 21:20:00 2015 (r290069) +++ head/sys/dev/drm2/i915/i915_drv.c Tue Oct 27 21:23:19 2015 (r290070) @@ -42,6 +42,44 @@ __FBSDID("$FreeBSD$"); #include "fb_if.h" +int intel_iommu_enabled = 0; +TUNABLE_INT("drm.i915.intel_iommu_enabled", &intel_iommu_enabled); +int intel_iommu_gfx_mapped = 0; +TUNABLE_INT("drm.i915.intel_iommu_gfx_mapped", &intel_iommu_gfx_mapped); + +int i915_prefault_disable; +TUNABLE_INT("drm.i915.prefault_disable", &i915_prefault_disable); +int i915_semaphores = -1; +TUNABLE_INT("drm.i915.semaphores", &i915_semaphores); +static int i915_try_reset = 1; +TUNABLE_INT("drm.i915.try_reset", &i915_try_reset); +unsigned int i915_lvds_downclock = 0; +TUNABLE_INT("drm.i915.lvds_downclock", &i915_lvds_downclock); +int i915_vbt_sdvo_panel_type = -1; +TUNABLE_INT("drm.i915.vbt_sdvo_panel_type", &i915_vbt_sdvo_panel_type); +unsigned int i915_powersave = 1; +TUNABLE_INT("drm.i915.powersave", &i915_powersave); +int i915_enable_fbc = 0; +TUNABLE_INT("drm.i915.enable_fbc", &i915_enable_fbc); +int i915_enable_rc6 = 0; +TUNABLE_INT("drm.i915.enable_rc6", &i915_enable_rc6); +int i915_lvds_channel_mode; +TUNABLE_INT("drm.i915.lvds_channel_mode", &i915_lvds_channel_mode); +int i915_panel_use_ssc = -1; +TUNABLE_INT("drm.i915.panel_use_ssc", &i915_panel_use_ssc); +int i915_panel_ignore_lid = 0; +TUNABLE_INT("drm.i915.panel_ignore_lid", &i915_panel_ignore_lid); +int i915_panel_invert_brightness; +TUNABLE_INT("drm.i915.panel_invert_brightness", &i915_panel_invert_brightness); +int i915_modeset = 1; +TUNABLE_INT("drm.i915.modeset", &i915_modeset); +int i915_enable_ppgtt = -1; +TUNABLE_INT("drm.i915.enable_ppgtt", &i915_enable_ppgtt); +int i915_enable_hangcheck = 1; +TUNABLE_INT("drm.i915.enable_hangcheck", &i915_enable_hangcheck); +static int i915_enable_unsupported = 0; +TUNABLE_INT("drm.i915.enable_unsupported", &i915_enable_unsupported); + /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t i915_pciidlist[] = { i915_PCI_IDS @@ -229,7 +267,7 @@ static const struct intel_device_info in static const struct intel_gfx_device_id { int device; const struct intel_device_info *info; -} pciidlist[] = { /* aka */ +} i915_infolist[] = { /* aka */ INTEL_VGA_DEVICE(0x3577, &intel_i830_info), /* I830_M */ INTEL_VGA_DEVICE(0x2562, &intel_845g_info), /* 845_G */ INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), /* I855_GM */ @@ -316,7 +354,61 @@ static const struct intel_gfx_device_id {0, 0} }; -static int i915_enable_unsupported; +#define PCI_VENDOR_INTEL 0x8086 +#define INTEL_PCH_DEVICE_ID_MASK 0xff00 +#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 +#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 +#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00 +#define INTEL_PCH_LPT_DEVICE_ID_TYPE 0x8c00 + +void intel_detect_pch(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + device_t pch; + uint32_t id; + + pch = pci_find_class(PCIC_BRIDGE, PCIS_BRIDGE_ISA); + if (pch != NULL && pci_get_vendor(pch) == PCI_VENDOR_INTEL) { + id = pci_get_device(pch) & INTEL_PCH_DEVICE_ID_MASK; + if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_IBX; + dev_priv->num_pch_pll = 2; + DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); + } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_CPT; + dev_priv->num_pch_pll = 2; + DRM_DEBUG_KMS("Found CougarPoint PCH\n"); + } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { + /* PantherPoint is CPT compatible */ + dev_priv->pch_type = PCH_CPT; + dev_priv->num_pch_pll = 2; + DRM_DEBUG_KMS("Found PatherPoint PCH\n"); + } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_LPT; + dev_priv->num_pch_pll = 0; + DRM_DEBUG_KMS("Found LynxPoint PCH\n"); + } else + DRM_DEBUG_KMS("No PCH detected\n"); + KASSERT(dev_priv->num_pch_pll <= I915_NUM_PLLS, + ("num_pch_pll %d\n", dev_priv->num_pch_pll)); + } else + DRM_DEBUG_KMS("No Intel PCI-ISA bridge found\n"); +} + +bool i915_semaphore_is_enabled(struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen < 6) + return 0; + + if (i915_semaphores >= 0) + return i915_semaphores; + + /* Enable semaphores on SNB when IO remapping is off */ + if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) + return false; + + return 1; +} static int i915_drm_freeze(struct drm_device *dev) { @@ -355,7 +447,7 @@ static int i915_suspend(device_t kdev) int error; dev = device_get_softc(kdev); - if (dev == NULL || dev->dev_private == NULL) { + if (!dev || !dev->dev_private) { DRM_ERROR("DRM not initialized, aborting suspend.\n"); return ENODEV; } @@ -363,7 +455,7 @@ static int i915_suspend(device_t kdev) DRM_DEBUG_KMS("starting suspend\n"); error = i915_drm_freeze(dev); if (error) - return (-error); + return -error; error = bus_generic_suspend(kdev); DRM_DEBUG_KMS("finished suspend %d\n", error); @@ -429,8 +521,8 @@ static int i915_resume(device_t kdev) #endif ret = i915_drm_thaw(dev); - if (ret != 0) - return (-ret); + if (ret) + return -ret; drm_kms_helper_poll_enable(dev); ret = bus_generic_resume(kdev); @@ -438,189 +530,348 @@ static int i915_resume(device_t kdev) return (ret); } -static int -i915_probe(device_t kdev) +static int i8xx_do_reset(struct drm_device *dev) { - const struct intel_device_info *info; - int error; + struct drm_i915_private *dev_priv = dev->dev_private; + int onems; - error = drm_probe_helper(kdev, i915_pciidlist); - if (error != 0) - return (-error); - info = i915_get_device_id(pci_get_device(kdev)); - if (info == NULL) - return (ENXIO); - return (0); -} + if (IS_I85X(dev)) + return -ENODEV; + + onems = hz / 1000; + if (onems == 0) + onems = 1; + + I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830); + POSTING_READ(D_STATE); + + if (IS_I830(dev) || IS_845G(dev)) { + I915_WRITE(DEBUG_RESET_I830, + DEBUG_RESET_DISPLAY | + DEBUG_RESET_RENDER | + DEBUG_RESET_FULL); + POSTING_READ(DEBUG_RESET_I830); + pause("i8xxrst1", onems); + + I915_WRITE(DEBUG_RESET_I830, 0); + POSTING_READ(DEBUG_RESET_I830); + } + + pause("i8xxrst2", onems); + + I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830); + POSTING_READ(D_STATE); -int i915_modeset; + return 0; +} -static int -i915_attach(device_t kdev) +static int i965_reset_complete(struct drm_device *dev) { + u8 gdrst; - if (i915_modeset == 1) - i915_driver_info.driver_features |= DRIVER_MODESET; - return (-drm_attach_helper(kdev, i915_pciidlist, &i915_driver_info)); + gdrst = pci_read_config(dev->dev, I965_GDRST, 1); + return (gdrst & GRDOM_RESET_ENABLE) == 0; } -static struct fb_info * -i915_fb_helper_getinfo(device_t kdev) +static int i965_do_reset(struct drm_device *dev) { - struct intel_fbdev *ifbdev; - drm_i915_private_t *dev_priv; - struct drm_device *dev; - struct fb_info *info; + int ret; + u8 gdrst; - dev = device_get_softc(kdev); - dev_priv = dev->dev_private; - ifbdev = dev_priv->fbdev; - if (ifbdev == NULL) - return (NULL); + /* + * 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. + */ + gdrst = pci_read_config(dev->dev, I965_GDRST, 1); + pci_write_config(dev->dev, I965_GDRST, + gdrst | GRDOM_RENDER | + GRDOM_RESET_ENABLE, 1); + ret = wait_for(i965_reset_complete(dev), 500); + if (ret) + return ret; - info = ifbdev->helper.fbdev; + /* We can't reset render&media without also resetting display ... */ + gdrst = pci_read_config(dev->dev, I965_GDRST, 1); + pci_write_config(dev->dev, I965_GDRST, + gdrst | GRDOM_MEDIA | + GRDOM_RESET_ENABLE, 1); - return (info); + return wait_for(i965_reset_complete(dev), 500); } -const struct intel_device_info * -i915_get_device_id(int device) +static int ironlake_do_reset(struct drm_device *dev) { - const struct intel_gfx_device_id *did; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 gdrst; + int ret; - for (did = &pciidlist[0]; did->device != 0; did++) { - if (did->device != device) - continue; - if (did->info->not_supported && !i915_enable_unsupported) - return (NULL); - return (did->info); - } - return (NULL); + gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, + gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); + ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); + if (ret) + return ret; + + /* We can't reset render&media without also resetting display ... */ + gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, + gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); + return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); } -static device_method_t i915_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, i915_probe), - DEVMETHOD(device_attach, i915_attach), - DEVMETHOD(device_suspend, i915_suspend), - DEVMETHOD(device_resume, i915_resume), - DEVMETHOD(device_detach, drm_generic_detach), +static int gen6_do_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; - /* Framebuffer service methods */ - DEVMETHOD(fb_getinfo, i915_fb_helper_getinfo), + /* Hold gt_lock across reset to prevent any register access + * with forcewake not set correctly + */ + mtx_lock(&dev_priv->gt_lock); - DEVMETHOD_END -}; + /* Reset the chip */ -static driver_t i915_driver = { - "drmn", - i915_methods, - sizeof(struct drm_device) -}; + /* GEN6_GDRST is not in the gt power well, no need to check + * for fifo space for the write or forcewake the chip for + * the read + */ + I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL); -extern devclass_t drm_devclass; -DRIVER_MODULE_ORDERED(i915kms, vgapci, i915_driver, drm_devclass, 0, 0, - SI_ORDER_ANY); -MODULE_DEPEND(i915kms, drmn, 1, 1, 1); -MODULE_DEPEND(i915kms, agp, 1, 1, 1); -MODULE_DEPEND(i915kms, iicbus, 1, 1, 1); -MODULE_DEPEND(i915kms, iic, 1, 1, 1); -MODULE_DEPEND(i915kms, iicbb, 1, 1, 1); + /* Spin waiting for the device to ack the reset request */ + ret = _intel_wait_for(dev, + (I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, + 500, 0, "915rst"); -int intel_iommu_enabled = 0; -TUNABLE_INT("drm.i915.intel_iommu_enabled", &intel_iommu_enabled); -int intel_iommu_gfx_mapped = 0; -TUNABLE_INT("drm.i915.intel_iommu_gfx_mapped", &intel_iommu_gfx_mapped); + /* If reset with a user forcewake, try to restore, otherwise turn it off */ + if (dev_priv->forcewake_count) + dev_priv->display.force_wake_get(dev_priv); + else + dev_priv->display.force_wake_put(dev_priv); -int i915_prefault_disable; -TUNABLE_INT("drm.i915.prefault_disable", &i915_prefault_disable); -int i915_semaphores = -1; -TUNABLE_INT("drm.i915.semaphores", &i915_semaphores); -static int i915_try_reset = 1; -TUNABLE_INT("drm.i915.try_reset", &i915_try_reset); -unsigned int i915_lvds_downclock = 0; -TUNABLE_INT("drm.i915.lvds_downclock", &i915_lvds_downclock); -int i915_vbt_sdvo_panel_type = -1; -TUNABLE_INT("drm.i915.vbt_sdvo_panel_type", &i915_vbt_sdvo_panel_type); -unsigned int i915_powersave = 1; -TUNABLE_INT("drm.i915.powersave", &i915_powersave); -int i915_enable_fbc = 0; -TUNABLE_INT("drm.i915.enable_fbc", &i915_enable_fbc); -int i915_enable_rc6 = 0; -TUNABLE_INT("drm.i915.enable_rc6", &i915_enable_rc6); -int i915_lvds_channel_mode; -TUNABLE_INT("drm.i915.lvds_channel_mode", &i915_lvds_channel_mode); -int i915_panel_use_ssc = -1; -TUNABLE_INT("drm.i915.panel_use_ssc", &i915_panel_use_ssc); -int i915_panel_ignore_lid = 0; -TUNABLE_INT("drm.i915.panel_ignore_lid", &i915_panel_ignore_lid); -int i915_panel_invert_brightness; -TUNABLE_INT("drm.i915.panel_invert_brightness", &i915_panel_invert_brightness); -int i915_modeset = 1; -TUNABLE_INT("drm.i915.modeset", &i915_modeset); -int i915_enable_ppgtt = -1; -TUNABLE_INT("drm.i915.enable_ppgtt", &i915_enable_ppgtt); -int i915_enable_hangcheck = 1; -TUNABLE_INT("drm.i915.enable_hangcheck", &i915_enable_hangcheck); -TUNABLE_INT("drm.i915.enable_unsupported", &i915_enable_unsupported); + /* Restore fifo count */ + dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); -#define PCI_VENDOR_INTEL 0x8086 -#define INTEL_PCH_DEVICE_ID_MASK 0xff00 -#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 -#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 -#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00 -#define INTEL_PCH_LPT_DEVICE_ID_TYPE 0x8c00 + mtx_unlock(&dev_priv->gt_lock); + return ret; +} -void intel_detect_pch(struct drm_device *dev) +int intel_gpu_reset(struct drm_device *dev) { - struct drm_i915_private *dev_priv; - device_t pch; - uint32_t id; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret = -ENODEV; - dev_priv = dev->dev_private; - pch = pci_find_class(PCIC_BRIDGE, PCIS_BRIDGE_ISA); - if (pch != NULL && pci_get_vendor(pch) == PCI_VENDOR_INTEL) { - id = pci_get_device(pch) & INTEL_PCH_DEVICE_ID_MASK; - if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_IBX; - dev_priv->num_pch_pll = 2; - DRM_DEBUG_KMS("Found Ibex Peak PCH\n"); - } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_CPT; - dev_priv->num_pch_pll = 2; - DRM_DEBUG_KMS("Found CougarPoint PCH\n"); - } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) { - /* PantherPoint is CPT compatible */ - dev_priv->pch_type = PCH_CPT; - dev_priv->num_pch_pll = 2; - DRM_DEBUG_KMS("Found PatherPoint PCH\n"); - } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { - dev_priv->pch_type = PCH_LPT; - dev_priv->num_pch_pll = 0; - DRM_DEBUG_KMS("Found LynxPoint PCH\n"); - } else - DRM_DEBUG_KMS("No PCH detected\n"); - KASSERT(dev_priv->num_pch_pll <= I915_NUM_PLLS, - ("num_pch_pll %d\n", dev_priv->num_pch_pll)); - } else - DRM_DEBUG_KMS("No Intel PCI-ISA bridge found\n"); + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: + ret = gen6_do_reset(dev); + break; + case 5: + ret = ironlake_do_reset(dev); + break; + case 4: + ret = i965_do_reset(dev); + break; + case 2: + ret = i8xx_do_reset(dev); + break; + } + + /* Also reset the gpu hangman. */ + if (dev_priv->stop_rings) { + DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n"); + dev_priv->stop_rings = 0; + if (ret == -ENODEV) { + DRM_ERROR("Reset not implemented, but ignoring " + "error for simulated gpu hangs\n"); + ret = 0; + } + } + + return ret; } -bool i915_semaphore_is_enabled(struct drm_device *dev) +/** + * i915_reset - reset chip after a hang + * @dev: drm device to reset + * + * Reset the chip. Useful if a hang is detected. Returns zero on successful + * reset or otherwise an error code. + * + * Procedure is fairly simple: + * - reset the chip using the reset reg + * - re-init context state + * - re-init hardware status page + * - re-init ring buffer + * - re-init interrupt state + * - re-init display + */ +int i915_reset(struct drm_device *dev) { - if (INTEL_INFO(dev)->gen < 6) + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + + if (!i915_try_reset) return 0; - if (i915_semaphores >= 0) - return i915_semaphores; + if (!sx_try_xlock(&dev->dev_struct_lock)) + return (-EBUSY); - /* Enable semaphores on SNB when IO remapping is off */ - if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) - return false; + dev_priv->stop_rings = 0; - return 1; + i915_gem_reset(dev); + + ret = -ENODEV; + if (time_second - dev_priv->last_gpu_reset < 5) + DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); + else + ret = intel_gpu_reset(dev); + + dev_priv->last_gpu_reset = time_second; + if (ret) { + DRM_ERROR("Failed to reset chip.\n"); + DRM_UNLOCK(dev); + return ret; + } + + /* Ok, now get things going again... */ + + /* + * Everything depends on having the GTT running, so we need to start + * there. Fortunately we don't need to do this unless we reset the + * chip at a PCI level. + * + * Next we need to restore the context, but we don't use those + * yet either... + * + * Ring buffer needs to be re-initialized in the KMS case, or if X + * was running at the time of the reset (i.e. we weren't VT + * switched away). + */ + if (drm_core_check_feature(dev, DRIVER_MODESET) || + !dev_priv->mm.suspended) { + struct intel_ring_buffer *ring; + int i; + + dev_priv->mm.suspended = 0; + + i915_gem_init_swizzling(dev); + + for_each_ring(ring, dev_priv, i) + ring->init(ring); + + i915_gem_context_init(dev); + i915_gem_init_ppgtt(dev); + + /* + * It would make sense to re-init all the other hw state, at + * least the rps/rc6/emon init done within modeset_init_hw. For + * some unknown reason, this blows up my ilk, so don't. + */ + + DRM_UNLOCK(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + intel_modeset_init_hw(dev); + + drm_irq_uninstall(dev); + drm_irq_install(dev); + } else { + DRM_UNLOCK(dev); + } + + return 0; } +const struct intel_device_info * +i915_get_device_id(int device) +{ + const struct intel_gfx_device_id *did; + + for (did = &i915_infolist[0]; did->device != 0; did++) { + if (did->device != device) + continue; + if (did->info->not_supported && !i915_enable_unsupported) + return (NULL); + return (did->info); + } + return (NULL); +} + +static int i915_probe(device_t kdev) +{ + const struct intel_device_info *intel_info = + i915_get_device_id(pci_get_device(kdev)); + + if (intel_info == NULL) + return (ENXIO); + + return -drm_probe_helper(kdev, i915_pciidlist); +} + +static int i915_attach(device_t kdev) +{ + + if (i915_modeset == 1) + i915_driver_info.driver_features |= DRIVER_MODESET; + return (-drm_attach_helper(kdev, i915_pciidlist, &i915_driver_info)); +} + +static struct fb_info * +i915_fb_helper_getinfo(device_t kdev) +{ + struct intel_fbdev *ifbdev; + drm_i915_private_t *dev_priv; + struct drm_device *dev; + struct fb_info *info; + + dev = device_get_softc(kdev); + dev_priv = dev->dev_private; + ifbdev = dev_priv->fbdev; + if (ifbdev == NULL) + return (NULL); + + info = ifbdev->helper.fbdev; + + return (info); +} + +static device_method_t i915_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, i915_probe), + DEVMETHOD(device_attach, i915_attach), + DEVMETHOD(device_suspend, i915_suspend), + DEVMETHOD(device_resume, i915_resume), + DEVMETHOD(device_detach, drm_generic_detach), + + /* Framebuffer service methods */ + DEVMETHOD(fb_getinfo, i915_fb_helper_getinfo), + + DEVMETHOD_END +}; + +static driver_t i915_driver = { + "drmn", + i915_methods, + sizeof(struct drm_device) +}; + +extern devclass_t drm_devclass; +DRIVER_MODULE_ORDERED(i915kms, vgapci, i915_driver, drm_devclass, 0, 0, + SI_ORDER_ANY); +MODULE_DEPEND(i915kms, drmn, 1, 1, 1); +MODULE_DEPEND(i915kms, agp, 1, 1, 1); +MODULE_DEPEND(i915kms, iicbus, 1, 1, 1); +MODULE_DEPEND(i915kms, iic, 1, 1, 1); +MODULE_DEPEND(i915kms, iicbb, 1, 1, 1); + +/* We give fast paths for the really cool registers */ +#define NEEDS_FORCE_WAKE(dev_priv, reg) \ + (((dev_priv)->info->gen >= 6) && \ + ((reg) < 0x40000) && \ + ((reg) != FORCEWAKE)) && \ + (!IS_VALLEYVIEW((dev_priv)->dev)) + void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { @@ -753,264 +1004,6 @@ void vlv_force_wake_put(struct drm_i915_ POSTING_READ(FORCEWAKE_VLV); } -static int i8xx_do_reset(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int onems; - - if (IS_I85X(dev)) - return -ENODEV; - - onems = hz / 1000; - if (onems == 0) - onems = 1; - - I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830); - POSTING_READ(D_STATE); - - if (IS_I830(dev) || IS_845G(dev)) { - I915_WRITE(DEBUG_RESET_I830, - DEBUG_RESET_DISPLAY | - DEBUG_RESET_RENDER | - DEBUG_RESET_FULL); - POSTING_READ(DEBUG_RESET_I830); - pause("i8xxrst1", onems); - - I915_WRITE(DEBUG_RESET_I830, 0); - POSTING_READ(DEBUG_RESET_I830); - } - - pause("i8xxrst2", onems); - - I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830); - POSTING_READ(D_STATE); - - return 0; -} - -static int i965_reset_complete(struct drm_device *dev) -{ - u8 gdrst; - - gdrst = pci_read_config(dev->dev, I965_GDRST, 1); - return (gdrst & GRDOM_RESET_ENABLE) == 0; -} - -static int i965_do_reset(struct drm_device *dev) -{ - int ret; - u8 gdrst; - - /* - * 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. - */ - gdrst = pci_read_config(dev->dev, I965_GDRST, 1); - pci_write_config(dev->dev, I965_GDRST, - gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE, 1); - - ret = wait_for(i965_reset_complete(dev), 500); - if (ret) - return ret; - - /* We can't reset render&media without also resetting display ... */ - gdrst = pci_read_config(dev->dev, I965_GDRST, 1); - pci_write_config(dev->dev, I965_GDRST, - gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE, 1); - - return wait_for(i965_reset_complete(dev), 500); -} - -static int ironlake_do_reset(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 gdrst; - int ret; - - gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, - gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); - ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); - if (ret) - return ret; - - /* We can't reset render&media without also resetting display ... */ - gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, - gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); - return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); -} - -static int gen6_do_reset(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - - /* Hold gt_lock across reset to prevent any register access - * with forcewake not set correctly - */ - mtx_lock(&dev_priv->gt_lock); - - /* Reset the chip */ - - /* GEN6_GDRST is not in the gt power well, no need to check - * for fifo space for the write or forcewake the chip for - * the read - */ - I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL); - - /* Spin waiting for the device to ack the reset request */ - ret = _intel_wait_for(dev, - (I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, - 500, 0, "915rst"); - - /* If reset with a user forcewake, try to restore, otherwise turn it off */ - if (dev_priv->forcewake_count) - dev_priv->display.force_wake_get(dev_priv); - else - dev_priv->display.force_wake_put(dev_priv); - - /* Restore fifo count */ - dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); - - mtx_unlock(&dev_priv->gt_lock); - return (ret); -} - -int intel_gpu_reset(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int ret = -ENODEV; - - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - ret = gen6_do_reset(dev); - break; - case 5: - ret = ironlake_do_reset(dev); - break; - case 4: - ret = i965_do_reset(dev); - break; - case 2: - ret = i8xx_do_reset(dev); - break; - } - - /* Also reset the gpu hangman. */ - if (dev_priv->stop_rings) { - DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n"); - dev_priv->stop_rings = 0; - if (ret == -ENODEV) { - DRM_ERROR("Reset not implemented, but ignoring " - "error for simulated gpu hangs\n"); - ret = 0; - } - } - - return ret; -} - -/** - * i915_reset - reset chip after a hang - * @dev: drm device to reset - * - * Reset the chip. Useful if a hang is detected. Returns zero on successful - * reset or otherwise an error code. - * - * Procedure is fairly simple: - * - reset the chip using the reset reg - * - re-init context state - * - re-init hardware status page - * - re-init ring buffer - * - re-init interrupt state - * - re-init display - */ -int i915_reset(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret; - - if (!i915_try_reset) - return 0; - - if (!sx_try_xlock(&dev->dev_struct_lock)) - return (-EBUSY); - - dev_priv->stop_rings = 0; - - i915_gem_reset(dev); - - ret = -ENODEV; - if (time_second - dev_priv->last_gpu_reset < 5) - DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); - else - ret = intel_gpu_reset(dev); - - dev_priv->last_gpu_reset = time_second; - if (ret) { - DRM_ERROR("Failed to reset chip.\n"); - DRM_UNLOCK(dev); - return ret; - } - - /* Ok, now get things going again... */ - - /* - * Everything depends on having the GTT running, so we need to start - * there. Fortunately we don't need to do this unless we reset the - * chip at a PCI level. - * - * Next we need to restore the context, but we don't use those - * yet either... - * - * Ring buffer needs to be re-initialized in the KMS case, or if X - * was running at the time of the reset (i.e. we weren't VT - * switched away). - */ - if (drm_core_check_feature(dev, DRIVER_MODESET) || - !dev_priv->mm.suspended) { - struct intel_ring_buffer *ring; - int i; - - dev_priv->mm.suspended = 0; - - i915_gem_init_swizzling(dev); - - for_each_ring(ring, dev_priv, i) - ring->init(ring); - - i915_gem_context_init(dev); - i915_gem_init_ppgtt(dev); - - /* - * It would make sense to re-init all the other hw state, at - * least the rps/rc6/emon init done within modeset_init_hw. For - * some unknown reason, this blows up my ilk, so don't. - */ - DRM_UNLOCK(dev); - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - intel_modeset_init_hw(dev); - - drm_irq_uninstall(dev); - drm_irq_install(dev); - } else { - DRM_UNLOCK(dev); - } - - return 0; -} - -/* We give fast paths for the really cool registers */ -#define NEEDS_FORCE_WAKE(dev_priv, reg) \ - (((dev_priv)->info->gen >= 6) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE)) && \ - (!IS_VALLEYVIEW((dev_priv)->dev)) - #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = 0; \ @@ -1018,12 +1011,12 @@ u##x i915_read##x(struct drm_i915_privat mtx_lock(&dev_priv->gt_lock); \ if (dev_priv->forcewake_count == 0) \ dev_priv->display.force_wake_get(dev_priv); \ - val = DRM_READ##y(dev_priv->mmio_map, reg); \ + val = DRM_READ##x(dev_priv->mmio_map, reg); \ if (dev_priv->forcewake_count == 0) \ dev_priv->display.force_wake_put(dev_priv); \ mtx_unlock(&dev_priv->gt_lock); \ } else { \ - val = DRM_READ##y(dev_priv->mmio_map, reg); \ + val = DRM_READ##x(dev_priv->mmio_map, reg); \ } \ trace_i915_reg_rw(false, reg, val, sizeof(val)); \ return val; \ @@ -1042,7 +1035,7 @@ void i915_write##x(struct drm_i915_priva if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ - DRM_WRITE##y(dev_priv->mmio_map, reg, val); \ + DRM_WRITE##x(dev_priv->mmio_map, reg, val); \ if (__predict_false(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \