@@ -1486,6 +1486,7 @@ int i915_gem_evict_everything(struct drm_device *dev);
/* i915_gem_stolen.c */
int i915_gem_init_stolen(struct drm_device *dev);
+int i915_gem_stolen_setup_compression(struct drm_device *dev);
void i915_gem_cleanup_stolen(struct drm_device *dev);
/* i915_gem_tiling.c */
@@ -86,21 +86,13 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
return base;
}
-static void i915_warn_stolen(struct drm_device *dev)
-{
- DRM_INFO("not enough stolen space for compressed buffer, disabling\n");
- DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
-}
-
-static void i915_setup_compression(struct drm_device *dev, int size)
+static int i915_setup_compression(struct drm_device *dev, int size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb);
- unsigned long cfb_base;
- unsigned long ll_base = 0;
- /* Just in case the BIOS is doing something questionable. */
- intel_disable_fbc(dev);
+ DRM_DEBUG_KMS("reserving %d bytes of contiguous stolen space for FBC\n",
+ size);
compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
if (compressed_fb)
@@ -108,11 +100,11 @@ static void i915_setup_compression(struct drm_device *dev, int size)
if (!compressed_fb)
goto err;
- cfb_base = dev_priv->mm.stolen_base + compressed_fb->start;
- if (!cfb_base)
- goto err_fb;
-
- if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) {
+ if (HAS_PCH_SPLIT(dev))
+ I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
+ else if (IS_GM45(dev)) {
+ I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
+ } else {
compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen,
4096, 4096, 0);
if (compressed_llb)
@@ -121,56 +113,82 @@ static void i915_setup_compression(struct drm_device *dev, int size)
if (!compressed_llb)
goto err_fb;
- ll_base = dev_priv->mm.stolen_base + compressed_llb->start;
- if (!ll_base)
- goto err_llb;
- }
+ dev_priv->compressed_llb = compressed_llb;
- dev_priv->cfb_size = size;
+ I915_WRITE(FBC_CFB_BASE,
+ dev_priv->mm.stolen_base + compressed_fb->start);
+ I915_WRITE(FBC_LL_BASE,
+ dev_priv->mm.stolen_base + compressed_llb->start);
+ }
dev_priv->compressed_fb = compressed_fb;
- if (HAS_PCH_SPLIT(dev))
- I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
- else if (IS_GM45(dev)) {
- I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
- } else {
- I915_WRITE(FBC_CFB_BASE, cfb_base);
- I915_WRITE(FBC_LL_BASE, ll_base);
- dev_priv->compressed_llb = compressed_llb;
- }
+ dev_priv->cfb_size = size;
- DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n",
- (long)cfb_base, (long)ll_base, size >> 20);
- return;
+ return size;
-err_llb:
- drm_mm_put_block(compressed_llb);
err_fb:
drm_mm_put_block(compressed_fb);
err:
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
- i915_warn_stolen(dev);
+ DRM_INFO("not enough stolen space for compressed buffer (need %d bytes), disabling\n", size);
+ DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
+ return 0;
+}
+
+int i915_gem_stolen_setup_compression(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_mm_node *entry;
+ unsigned long size;
+
+ if (dev_priv->mm.stolen_base == 0)
+ return 0;
+
+ if (dev_priv->cfb_size)
+ return dev_priv->cfb_size;
+
+ /* Try to set up FBC with a reasonable compressed buffer size */
+ size = 0;
+ list_for_each_entry(entry, &dev_priv->mm.stolen.hole_stack, hole_stack) {
+ unsigned long hole_start = entry->start + entry->size;
+ unsigned long hole_end = list_entry(entry->node_list.next,
+ struct drm_mm_node,
+ node_list)->start;
+ unsigned long hole_size = hole_end - hole_start;
+ if (hole_size > size)
+ size = hole_size;
+ }
+
+ /* Try to get a 32M buffer... */
+ if (size > (36*1024*1024))
+ size = 32*1024*1024;
+ else /* fall back to 3/4 of the stolen space */
+ size = size * 3 / 4;
+
+ return i915_setup_compression(dev, size);
}
static void i915_cleanup_compression(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- drm_mm_put_block(dev_priv->compressed_fb);
+ if (dev_priv->compressed_fb)
+ drm_mm_put_block(dev_priv->compressed_fb);
+
if (dev_priv->compressed_llb)
drm_mm_put_block(dev_priv->compressed_llb);
+
+ dev_priv->cfb_size = 0;
}
void i915_gem_cleanup_stolen(struct drm_device *dev)
{
- if (I915_HAS_FBC(dev) && i915_powersave)
- i915_cleanup_compression(dev);
+ i915_cleanup_compression(dev);
}
int i915_gem_init_stolen(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size;
dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
if (dev_priv->mm.stolen_base == 0)
@@ -180,21 +198,7 @@ int i915_gem_init_stolen(struct drm_device *dev)
dev_priv->mm.gtt->stolen_size, dev_priv->mm.stolen_base);
/* Basic memrange allocator for stolen space */
- drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
-
- /* Try to set up FBC with a reasonable compressed buffer size */
- if (I915_HAS_FBC(dev) && i915_powersave) {
- int cfb_size;
-
- /* Leave 1M for line length buffer & misc. */
-
- /* Try to get a 32M buffer... */
- if (prealloc_size > (36*1024*1024))
- cfb_size = 32*1024*1024;
- else /* fall back to 7/8 of the stolen space */
- cfb_size = prealloc_size * 7 / 8;
- i915_setup_compression(dev, cfb_size);
- }
+ drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->mm.gtt->stolen_size);
return 0;
}
@@ -7173,6 +7173,9 @@ void intel_modeset_init(struct drm_device *dev)
/* Just disable it once at startup */
i915_disable_vga(dev);
intel_setup_outputs(dev);
+
+ /* Just in case the BIOS is doing something questionable. */
+ intel_disable_fbc(dev);
}
void intel_modeset_gem_init(struct drm_device *dev)
@@ -438,12 +438,6 @@ void intel_update_fbc(struct drm_device *dev)
dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
goto out_disable;
}
- if (intel_fb->obj->base.size > dev_priv->cfb_size) {
- DRM_DEBUG_KMS("framebuffer too large, disabling "
- "compression\n");
- dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
- goto out_disable;
- }
if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
(crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
DRM_DEBUG_KMS("mode incompatible with compression, "
@@ -477,6 +471,13 @@ void intel_update_fbc(struct drm_device *dev)
if (in_dbg_master())
goto out_disable;
+ if (intel_fb->obj->base.size > i915_gem_stolen_setup_compression(dev)) {
+ DRM_DEBUG_KMS("framebuffer too large, disabling "
+ "compression\n");
+ dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
+ goto out_disable;
+ }
+
/* If the scanout has not changed, don't modify the FBC settings.
* Note that we make the fundamental assumption that the fb->obj
* cannot be unpinned (and have its GTT offset and fence revoked)
As we may wish to wrap regions preallocated by the BIOS, we need to do that before carving out contiguous chunks of stolen space for FBC. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_stolen.c | 114 +++++++++++++++++--------------- drivers/gpu/drm/i915/intel_display.c | 3 + drivers/gpu/drm/i915/intel_pm.c | 13 ++-- 4 files changed, 70 insertions(+), 61 deletions(-)