Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 77894226 authored by Matthew Auld's avatar Matthew Auld Committed by Joonas Lahtinen
Browse files

drm/i915: make dsm struct resource centric



Now that we are using struct resource to track the stolen region, it is
more convenient if we track dsm in a resource as well.

v2: check range_overflow when writing to 32b registers (Chris)
    pepper in some comments (Chris)
v3: refit i915_stolen_to_dma()
v4: kill ggtt->stolen_size
v5: some more polish

Signed-off-by: default avatarMatthew Auld <matthew.auld@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171211151822.20953-6-matthew.auld@intel.com
parent f773568b
Loading
Loading
Loading
Loading
+0 −2
Original line number Original line Diff line number Diff line
@@ -1424,12 +1424,10 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,
EXPORT_SYMBOL(intel_gmch_probe);
EXPORT_SYMBOL(intel_gmch_probe);


void intel_gtt_get(u64 *gtt_total,
void intel_gtt_get(u64 *gtt_total,
		   u32 *stolen_size,
		   phys_addr_t *mappable_base,
		   phys_addr_t *mappable_base,
		   u64 *mappable_end)
		   u64 *mappable_end)
{
{
	*gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT;
	*gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT;
	*stolen_size = intel_private.stolen_size;
	*mappable_base = intel_private.gma_bus_addr;
	*mappable_base = intel_private.gma_bus_addr;
	*mappable_end = intel_private.gtt_mappable_entries << PAGE_SHIFT;
	*mappable_end = intel_private.gtt_mappable_entries << PAGE_SHIFT;
}
}
+9 −3
Original line number Original line Diff line number Diff line
@@ -1538,9 +1538,6 @@ struct i915_gem_mm {
	 */
	 */
	struct pagevec wc_stash;
	struct pagevec wc_stash;


	/** Usable portion of the GTT for GEM */
	dma_addr_t stolen_base; /* limited to low memory (32-bit) */

	/**
	/**
	 * tmpfs instance used for shmem backed objects
	 * tmpfs instance used for shmem backed objects
	 */
	 */
@@ -2254,6 +2251,15 @@ struct drm_i915_private {


	const struct intel_device_info info;
	const struct intel_device_info info;


	/**
	 * Data Stolen Memory - aka "i915 stolen memory" gives us the start and
	 * end of stolen which we can optionally use to create GEM objects
	 * backed by stolen memory. Note that ggtt->stolen_usable_size tells us
	 * exactly how much of this we are actually allowed to use, given that
	 * some portion of it is in fact reserved for use by hardware functions.
	 */
	struct resource dsm;

	void __iomem *regs;
	void __iomem *regs;


	struct intel_uncore uncore;
	struct intel_uncore uncore;
+2 −6
Original line number Original line Diff line number Diff line
@@ -3299,8 +3299,6 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)


	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);


	ggtt->stolen_size = resource_size(&intel_graphics_stolen_res);

	if (INTEL_GEN(dev_priv) >= 9) {
	if (INTEL_GEN(dev_priv) >= 9) {
		size = gen8_get_total_gtt_size(snb_gmch_ctl);
		size = gen8_get_total_gtt_size(snb_gmch_ctl);
	} else if (IS_CHERRYVIEW(dev_priv)) {
	} else if (IS_CHERRYVIEW(dev_priv)) {
@@ -3363,8 +3361,6 @@ static int gen6_gmch_probe(struct i915_ggtt *ggtt)
		DRM_ERROR("Can't set DMA mask/consistent mask (%d)\n", err);
		DRM_ERROR("Can't set DMA mask/consistent mask (%d)\n", err);
	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
	pci_read_config_word(pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);


	ggtt->stolen_size = resource_size(&intel_graphics_stolen_res);

	size = gen6_get_total_gtt_size(snb_gmch_ctl);
	size = gen6_get_total_gtt_size(snb_gmch_ctl);
	ggtt->base.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT;
	ggtt->base.total = (size / sizeof(gen6_pte_t)) << PAGE_SHIFT;


@@ -3410,7 +3406,6 @@ static int i915_gmch_probe(struct i915_ggtt *ggtt)
	}
	}


	intel_gtt_get(&ggtt->base.total,
	intel_gtt_get(&ggtt->base.total,
		      &ggtt->stolen_size,
		      &ggtt->mappable_base,
		      &ggtt->mappable_base,
		      &ggtt->mappable_end);
		      &ggtt->mappable_end);


@@ -3482,7 +3477,8 @@ int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv)
	DRM_INFO("Memory usable by graphics device = %lluM\n",
	DRM_INFO("Memory usable by graphics device = %lluM\n",
		 ggtt->base.total >> 20);
		 ggtt->base.total >> 20);
	DRM_DEBUG_DRIVER("GMADR size = %lldM\n", ggtt->mappable_end >> 20);
	DRM_DEBUG_DRIVER("GMADR size = %lldM\n", ggtt->mappable_end >> 20);
	DRM_DEBUG_DRIVER("GTT stolen size = %uM\n", ggtt->stolen_size >> 20);
	DRM_DEBUG_DRIVER("GTT stolen size = %lluM\n",
			 (u64)resource_size(&intel_graphics_stolen_res) >> 20);
	if (intel_vtd_active())
	if (intel_vtd_active())
		DRM_INFO("VT-d active for gfx access\n");
		DRM_INFO("VT-d active for gfx access\n");


+0 −1
Original line number Original line Diff line number Diff line
@@ -381,7 +381,6 @@ struct i915_ggtt {
	 * avoid the first page! The upper end of stolen memory is reserved for
	 * avoid the first page! The upper end of stolen memory is reserved for
	 * hardware functions and similarly removed from the accessible range.
	 * hardware functions and similarly removed from the accessible range.
	 */
	 */
	u32 stolen_size;		/* Total size of stolen memory */
	u32 stolen_usable_size;	/* Total size minus reserved ranges */
	u32 stolen_usable_size;	/* Total size minus reserved ranges */
	u32 stolen_reserved_base;
	u32 stolen_reserved_base;
	u32 stolen_reserved_size;
	u32 stolen_reserved_size;
+60 −65
Original line number Original line Diff line number Diff line
@@ -76,27 +76,26 @@ void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
	mutex_unlock(&dev_priv->mm.stolen_lock);
	mutex_unlock(&dev_priv->mm.stolen_lock);
}
}


static dma_addr_t i915_stolen_to_dma(struct drm_i915_private *dev_priv)
static int i915_adjust_stolen(struct drm_i915_private *dev_priv,
			      struct resource *dsm)
{
{
	struct i915_ggtt *ggtt = &dev_priv->ggtt;
	struct i915_ggtt *ggtt = &dev_priv->ggtt;
	dma_addr_t base = intel_graphics_stolen_res.start;
	struct resource *r;
	struct resource *r;


	GEM_BUG_ON(overflows_type(intel_graphics_stolen_res.start, base));
	if (dsm->start == 0 || dsm->end <= dsm->start)
		return -EINVAL;


	if (base == 0 || add_overflows(base, ggtt->stolen_size))
	/*
		return 0;
	 * TODO: We have yet too encounter the case where the GTT wasn't at the
	 * end of stolen. With that assumption we could simplify this.
	 */


	/* make sure we don't clobber the GTT if it's within stolen memory */
	/* Make sure we don't clobber the GTT if it's within stolen memory */
	if (INTEL_GEN(dev_priv) <= 4 &&
	if (INTEL_GEN(dev_priv) <= 4 &&
	    !IS_G33(dev_priv) && !IS_PINEVIEW(dev_priv) && !IS_G4X(dev_priv)) {
	    !IS_G33(dev_priv) && !IS_PINEVIEW(dev_priv) && !IS_G4X(dev_priv)) {
		struct {
		struct resource stolen[2] = {*dsm, *dsm};
			dma_addr_t start, end;
		struct resource ggtt_res;
		} stolen[2] = {
		u64 ggtt_start;
			{ .start = base, .end = base + ggtt->stolen_size, },
			{ .start = base, .end = base + ggtt->stolen_size, },
		};
		u64 ggtt_start, ggtt_end;


		ggtt_start = I915_READ(PGTBL_CTL);
		ggtt_start = I915_READ(PGTBL_CTL);
		if (IS_GEN4(dev_priv))
		if (IS_GEN4(dev_priv))
@@ -104,70 +103,64 @@ static dma_addr_t i915_stolen_to_dma(struct drm_i915_private *dev_priv)
				     (ggtt_start & PGTBL_ADDRESS_HI_MASK) << 28;
				     (ggtt_start & PGTBL_ADDRESS_HI_MASK) << 28;
		else
		else
			ggtt_start &= PGTBL_ADDRESS_LO_MASK;
			ggtt_start &= PGTBL_ADDRESS_LO_MASK;
		ggtt_end = ggtt_start + ggtt_total_entries(ggtt) * 4;


		if (ggtt_start >= stolen[0].start && ggtt_start < stolen[0].end)
		ggtt_res =
			stolen[0].end = ggtt_start;
			(struct resource) DEFINE_RES_MEM(ggtt_start,
		if (ggtt_end > stolen[1].start && ggtt_end <= stolen[1].end)
							 ggtt_total_entries(ggtt) * 4);
			stolen[1].start = ggtt_end;


		/* pick the larger of the two chunks */
		if (ggtt_res.start >= stolen[0].start && ggtt_res.start < stolen[0].end)
		if (stolen[0].end - stolen[0].start >
			stolen[0].end = ggtt_res.start;
		    stolen[1].end - stolen[1].start) {
		if (ggtt_res.end > stolen[1].start && ggtt_res.end <= stolen[1].end)
			base = stolen[0].start;
			stolen[1].start = ggtt_res.end;
			ggtt->stolen_size = stolen[0].end - stolen[0].start;

		} else {
		/* Pick the larger of the two chunks */
			base = stolen[1].start;
		if (resource_size(&stolen[0]) > resource_size(&stolen[1]))
			ggtt->stolen_size = stolen[1].end - stolen[1].start;
			*dsm = stolen[0];
		}
		else
			*dsm = stolen[1];


		if (stolen[0].start != stolen[1].start ||
		if (stolen[0].start != stolen[1].start ||
		    stolen[0].end != stolen[1].end) {
		    stolen[0].end != stolen[1].end) {
			dma_addr_t end = base + ggtt->stolen_size - 1;
			DRM_DEBUG_KMS("GTT within stolen memory at %pR\n", &ggtt_res);

			DRM_DEBUG_KMS("Stolen memory adjusted to %pR\n", dsm);
			DRM_DEBUG_KMS("GTT within stolen memory at 0x%llx-0x%llx\n",
				      (unsigned long long)ggtt_start,
				      (unsigned long long)ggtt_end - 1);
			DRM_DEBUG_KMS("Stolen memory adjusted to %pad - %pad\n",
				      &base, &end);
		}
		}
	}
	}



	/*
	/* Verify that nothing else uses this physical address. Stolen
	 * Verify that nothing else uses this physical address. Stolen
	 * memory should be reserved by the BIOS and hidden from the
	 * memory should be reserved by the BIOS and hidden from the
	 * kernel. So if the region is already marked as busy, something
	 * kernel. So if the region is already marked as busy, something
	 * is seriously wrong.
	 * is seriously wrong.
	 */
	 */
	r = devm_request_mem_region(dev_priv->drm.dev, base, ggtt->stolen_size,
	r = devm_request_mem_region(dev_priv->drm.dev, dsm->start,
				    resource_size(dsm),
				    "Graphics Stolen Memory");
				    "Graphics Stolen Memory");
	if (r == NULL) {
	if (r == NULL) {
		/*
		/*
		 * One more attempt but this time requesting region from
		 * One more attempt but this time requesting region from
		 * base + 1, as we have seen that this resolves the region
		 * start + 1, as we have seen that this resolves the region
		 * conflict with the PCI Bus.
		 * conflict with the PCI Bus.
		 * This is a BIOS w/a: Some BIOS wrap stolen in the root
		 * 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
		 * PCI bus, but have an off-by-one error. Hence retry the
		 * reservation starting from 1 instead of 0.
		 * reservation starting from 1 instead of 0.
		 * There's also BIOS with off-by-one on the other end.
		 * There's also BIOS with off-by-one on the other end.
		 */
		 */
		r = devm_request_mem_region(dev_priv->drm.dev, base + 1,
		r = devm_request_mem_region(dev_priv->drm.dev, dsm->start + 1,
					    ggtt->stolen_size - 2,
					    resource_size(dsm) - 2,
					    "Graphics Stolen Memory");
					    "Graphics Stolen Memory");
		/*
		/*
		 * GEN3 firmware likes to smash pci bridges into the stolen
		 * GEN3 firmware likes to smash pci bridges into the stolen
		 * range. Apparently this works.
		 * range. Apparently this works.
		 */
		 */
		if (r == NULL && !IS_GEN3(dev_priv)) {
		if (r == NULL && !IS_GEN3(dev_priv)) {
			dma_addr_t end = base + ggtt->stolen_size;
			DRM_ERROR("conflict detected with stolen region: %pR\n",
				  dsm);


			DRM_ERROR("conflict detected with stolen region: [%pad - %pad]\n",
			return -EBUSY;
				  &base, &end);
			base = 0;
		}
		}
	}
	}


	return base;
	return 0;
}
}


void i915_gem_cleanup_stolen(struct drm_device *dev)
void i915_gem_cleanup_stolen(struct drm_device *dev)
@@ -183,11 +176,10 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv,
static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv,
				    dma_addr_t *base, u32 *size)
				    dma_addr_t *base, u32 *size)
{
{
	struct i915_ggtt *ggtt = &dev_priv->ggtt;
	uint32_t reg_val = I915_READ(IS_GM45(dev_priv) ?
	uint32_t reg_val = I915_READ(IS_GM45(dev_priv) ?
				     CTG_STOLEN_RESERVED :
				     CTG_STOLEN_RESERVED :
				     ELK_STOLEN_RESERVED);
				     ELK_STOLEN_RESERVED);
	dma_addr_t stolen_top = dev_priv->mm.stolen_base + ggtt->stolen_size;
	dma_addr_t stolen_top = dev_priv->dsm.end + 1;


	if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0) {
	if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0) {
		*base = 0;
		*base = 0;
@@ -308,7 +300,6 @@ static void chv_get_stolen_reserved(struct drm_i915_private *dev_priv,
static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv,
static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv,
				    dma_addr_t *base, u32 *size)
				    dma_addr_t *base, u32 *size)
{
{
	struct i915_ggtt *ggtt = &dev_priv->ggtt;
	uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
	uint32_t reg_val = I915_READ(GEN6_STOLEN_RESERVED);
	dma_addr_t stolen_top;
	dma_addr_t stolen_top;


@@ -318,7 +309,7 @@ static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv,
		return;
		return;
	}
	}


	stolen_top = dev_priv->mm.stolen_base + ggtt->stolen_size;
	stolen_top = dev_priv->dsm.end + 1;


	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;
	*base = reg_val & GEN6_STOLEN_RESERVED_ADDR_MASK;


@@ -351,14 +342,18 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv)
		return 0;
		return 0;
	}
	}


	if (ggtt->stolen_size == 0)
	if (resource_size(&intel_graphics_stolen_res) == 0)
		return 0;
		return 0;


	dev_priv->mm.stolen_base = i915_stolen_to_dma(dev_priv);
	dev_priv->dsm = intel_graphics_stolen_res;
	if (dev_priv->mm.stolen_base == 0)

	if (i915_adjust_stolen(dev_priv, &dev_priv->dsm))
		return 0;
		return 0;


	stolen_top = dev_priv->mm.stolen_base + ggtt->stolen_size;
	GEM_BUG_ON(dev_priv->dsm.start == 0);
	GEM_BUG_ON(dev_priv->dsm.end <= dev_priv->dsm.start);

	stolen_top = dev_priv->dsm.end + 1;
	reserved_base = 0;
	reserved_base = 0;
	reserved_size = 0;
	reserved_size = 0;


@@ -399,12 +394,11 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv)
		reserved_base = stolen_top;
		reserved_base = stolen_top;
	}
	}


	if (reserved_base < dev_priv->mm.stolen_base ||
	if (reserved_base < dev_priv->dsm.start ||
	    reserved_base + reserved_size > stolen_top) {
	    reserved_base + reserved_size > stolen_top) {
		dma_addr_t reserved_top = reserved_base + reserved_size;
		dma_addr_t reserved_top = reserved_base + reserved_size;
		DRM_ERROR("Stolen reserved area [%pad - %pad] outside stolen memory [%pad - %pad]\n",
		DRM_ERROR("Stolen reserved area [%pad - %pad] outside stolen memory %pR\n",
			  &reserved_base, &reserved_top,
			  &reserved_base, &reserved_top, &dev_priv->dsm);
			  &dev_priv->mm.stolen_base, &stolen_top);
		return 0;
		return 0;
	}
	}


@@ -415,9 +409,9 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv)
	 * memory, so just consider the start. */
	 * memory, so just consider the start. */
	reserved_total = stolen_top - reserved_base;
	reserved_total = stolen_top - reserved_base;


	DRM_DEBUG_KMS("Memory reserved for graphics device: %uK, usable: %uK\n",
	DRM_DEBUG_KMS("Memory reserved for graphics device: %lluK, usable: %lluK\n",
		      ggtt->stolen_size >> 10,
		      (u64)resource_size(&dev_priv->dsm) >> 10,
		      (ggtt->stolen_size - reserved_total) >> 10);
		      ((u64)resource_size(&dev_priv->dsm) - reserved_total) >> 10);


	stolen_usable_start = 0;
	stolen_usable_start = 0;
	/* WaSkipStolenMemoryFirstPage:bdw+ */
	/* WaSkipStolenMemoryFirstPage:bdw+ */
@@ -425,7 +419,7 @@ int i915_gem_init_stolen(struct drm_i915_private *dev_priv)
		stolen_usable_start = 4096;
		stolen_usable_start = 4096;


	ggtt->stolen_usable_size =
	ggtt->stolen_usable_size =
		ggtt->stolen_size - reserved_total - stolen_usable_start;
		resource_size(&dev_priv->dsm) - reserved_total - stolen_usable_start;


	/* Basic memrange allocator for stolen space. */
	/* Basic memrange allocator for stolen space. */
	drm_mm_init(&dev_priv->mm.stolen, stolen_usable_start,
	drm_mm_init(&dev_priv->mm.stolen, stolen_usable_start,
@@ -442,7 +436,8 @@ i915_pages_create_for_stolen(struct drm_device *dev,
	struct sg_table *st;
	struct sg_table *st;
	struct scatterlist *sg;
	struct scatterlist *sg;


	GEM_BUG_ON(range_overflows(offset, size, dev_priv->ggtt.stolen_size));
	GEM_BUG_ON(range_overflows_t(resource_size_t, offset, size,
				     resource_size(&dev_priv->dsm)));


	/* We hide that we have no struct page backing our stolen object
	/* We hide that we have no struct page backing our stolen object
	 * by wrapping the contiguous physical allocation with a fake
	 * by wrapping the contiguous physical allocation with a fake
@@ -462,7 +457,7 @@ i915_pages_create_for_stolen(struct drm_device *dev,
	sg->offset = 0;
	sg->offset = 0;
	sg->length = size;
	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->dsm.start + offset;
	sg_dma_len(sg) = size;
	sg_dma_len(sg) = size;


	return st;
	return st;
Loading