From ae15f047264a9c6b791c191f4d9dae6caf82e1bc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 26 Feb 2014 18:01:42 +0000 Subject: [PATCH] drm/i915: Trim stolen region for reserved pages and conflicting BIOS setups On a few systems we have to reserve regions inside the stolen portion for use by the BIOS - we have to trim that out of our own allocation. In some cases, the BIOS will have reduced the reserved region in the e820 map and so we have to adjust our own region request to suit. Either way, we need to only use the resource that we successfully reserve for ourselves - rather than claim one region and use another. v2: Fix resource request bounds to be inclusive. (Jani) Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_stolen.c | 75 +++++++++++++++++--------------- drivers/gpu/drm/i915/intel_pm.c | 8 +++- 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4a4dfc0..b0ab633 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1099,7 +1099,7 @@ struct i915_gem_mm { struct list_head unbound_list; /** Usable portion of the GTT for GEM */ - unsigned long stolen_base; /* limited to low memory (32-bit) */ + struct resource *stolen_region; /* limited to low memory (32-bit) */ /** PPGTT used for aliasing the PPGTT with the GTT */ struct i915_hw_ppgtt *aliasing_ppgtt; diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 3214124..984ada1 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -45,10 +45,11 @@ * for is a boon. */ -static unsigned long i915_stolen_to_physical(struct drm_device *dev) +static struct resource *i915_stolen_to_physical(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct resource *r; + unsigned long start, end; u32 base; /* Almost universally we can find the Graphics Base of Stolen Memory @@ -184,28 +185,38 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) * kernel. So if the region is already marked as busy, something * is seriously wrong. */ - r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size, + start = base + PAGE_SIZE; /* leave the first page alone! */ + + end = base + dev_priv->gtt.stolen_size - 1; + if (IS_VALLEYVIEW(dev)) + end -= 1024*1024; /* top 1M on VLV/BYT is reserved */ + + r = devm_request_mem_region(dev->dev, start, end-start, "Graphics Stolen Memory"); if (r == NULL) { - /* - * One more attempt but this time requesting region from - * base + 1, as we have seen that this resolves the region - * conflict with the PCI Bus. - * This is a BIOS w/a: Some BIOS wrap stolen in the root - * PCI bus, but have an off-by-one error. Hence retry the - * reservation starting from 1 instead of 0. + /* Weird. BIOS has not reserved the whole region for us, + * try something smaller. */ - r = devm_request_mem_region(dev->dev, base + 1, - dev_priv->gtt.stolen_size - 1, - "Graphics Stolen Memory"); - if (r == NULL) { - DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n", - base, base + (uint32_t)dev_priv->gtt.stolen_size); - base = 0; - } + do { + start += PAGE_SIZE; + end -= PAGE_SIZE; + if (start < end) + break; + + r = devm_request_mem_region(dev->dev, start, end-start, + "Graphics Stolen Memory"); + } while (r == NULL); + + if (r == NULL) + DRM_ERROR("conflicting resource reservations detected with stolen region: [0x%08x - 0x%08x]\n", + base, base + (uint32_t)dev_priv->gtt.stolen_size - 1); + else + DRM_INFO("conflict detected with stolen region [0x%08x - 0x%08x], reducing to [0x%08lx - 0x%08lx]\n", + base, base + (uint32_t)dev_priv->gtt.stolen_size - 1, + start, end); } - return base; + return r; } static int i915_setup_compression(struct drm_device *dev, int size) @@ -245,9 +256,9 @@ static int i915_setup_compression(struct drm_device *dev, int size) dev_priv->fbc.compressed_llb = compressed_llb; I915_WRITE(FBC_CFB_BASE, - dev_priv->mm.stolen_base + compressed_fb->start); + dev_priv->mm.stolen_region->start + compressed_fb->start); I915_WRITE(FBC_LL_BASE, - dev_priv->mm.stolen_base + compressed_llb->start); + dev_priv->mm.stolen_region->start + compressed_llb->start); } dev_priv->fbc.compressed_fb = compressed_fb; @@ -317,28 +328,22 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) int i915_gem_init_stolen(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int bios_reserved = 0; + struct resource *r; if (dev_priv->gtt.stolen_size == 0) return 0; - dev_priv->mm.stolen_base = i915_stolen_to_physical(dev); - if (dev_priv->mm.stolen_base == 0) + r = i915_stolen_to_physical(dev); + if (r == NULL) return 0; - DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n", - dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base); - - if (IS_VALLEYVIEW(dev)) - bios_reserved = 1024*1024; /* top 1M on VLV/BYT */ - - if (WARN_ON(bios_reserved > dev_priv->gtt.stolen_size)) - return 0; + DRM_DEBUG_KMS("found %ld bytes of stolen memory at %08lx\n", + (long)resource_size(r), (long)r->start); /* Basic memrange allocator for stolen space */ - drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size - - bios_reserved); + drm_mm_init(&dev_priv->mm.stolen, 0, resource_size(r)); + dev_priv->mm.stolen_region = r; return 0; } @@ -351,7 +356,7 @@ i915_pages_create_for_stolen(struct drm_device *dev, struct scatterlist *sg; DRM_DEBUG_DRIVER("offset=0x%x, size=%d\n", offset, size); - BUG_ON(offset > dev_priv->gtt.stolen_size - size); + BUG_ON(offset > resource_size(dev_priv->mm.stolen_region) - size); /* We hide that we have no struct page backing our stolen object * by wrapping the contiguous physical allocation with a fake @@ -371,7 +376,7 @@ i915_pages_create_for_stolen(struct drm_device *dev, sg->offset = 0; sg->length = size; - sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset; + sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_region->start + offset; sg_dma_len(sg) = size; return st; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0c78e01..0b1e05d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3565,13 +3565,17 @@ static void valleyview_setup_pctx(struct drm_device *dev) int pctx_size = 24*1024; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + if (dev_priv->mm.stolen_region == NULL) { + DRM_DEBUG("stolen space not reserved, unable to setup power saving context"); + return; + } pcbr = I915_READ(VLV_PCBR); if (pcbr) { /* BIOS set it up already, grab the pre-alloc'd space */ int pcbr_offset; - pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_base; + pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_region->start; pctx = i915_gem_object_create_stolen_for_preallocated(dev_priv->dev, pcbr_offset, I915_GTT_OFFSET_NONE, @@ -3593,7 +3597,7 @@ static void valleyview_setup_pctx(struct drm_device *dev) return; } - pctx_paddr = dev_priv->mm.stolen_base + pctx->stolen->start; + pctx_paddr = dev_priv->mm.stolen_region->start + pctx->stolen->start; I915_WRITE(VLV_PCBR, pctx_paddr); out: -- 1.7.9.5