diff options
Diffstat (limited to 'drivers/gpu/drm/i915/gem/i915_gem_stolen.c')
| -rw-r--r-- | drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 166 |
1 files changed, 121 insertions, 45 deletions
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 1a766d8e7cce..f859c99f969b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -1,6 +1,5 @@ +// SPDX-License-Identifier: MIT /* - * SPDX-License-Identifier: MIT - * * Copyright © 2008-2012 Intel Corporation */ @@ -8,7 +7,8 @@ #include <linux/mutex.h> #include <drm/drm_mm.h> -#include <drm/i915_drm.h> +#include <drm/drm_print.h> +#include <drm/intel/i915_drm.h> #include "gem/i915_gem_lmem.h" #include "gem/i915_gem_region.h" @@ -25,6 +25,11 @@ #include "intel_mchbar_regs.h" #include "intel_pci_config.h" +struct intel_stolen_node { + struct drm_i915_private *i915; + struct drm_mm_node node; +}; + /* * The BIOS typically reserves some of the system's memory for the exclusive * use of the integrated graphics. This memory is no longer available for @@ -37,9 +42,9 @@ * for is a boon. */ -int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, - struct drm_mm_node *node, u64 size, - unsigned alignment, u64 start, u64 end) +static int __i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, + struct drm_mm_node *node, u64 size, + unsigned int alignment, u64 start, u64 end) { int ret; @@ -59,24 +64,43 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *i915, return ret; } -int i915_gem_stolen_insert_node(struct drm_i915_private *i915, - struct drm_mm_node *node, u64 size, - unsigned alignment) +int i915_gem_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size, + unsigned int alignment, u64 start, u64 end) +{ + return __i915_gem_stolen_insert_node_in_range(node->i915, &node->node, + size, alignment, + start, end); +} + +static int __i915_gem_stolen_insert_node(struct drm_i915_private *i915, + struct drm_mm_node *node, u64 size, + unsigned int alignment) { - return i915_gem_stolen_insert_node_in_range(i915, node, - size, alignment, - I915_GEM_STOLEN_BIAS, - U64_MAX); + return __i915_gem_stolen_insert_node_in_range(i915, node, + size, alignment, + I915_GEM_STOLEN_BIAS, + U64_MAX); } -void i915_gem_stolen_remove_node(struct drm_i915_private *i915, - struct drm_mm_node *node) +int i915_gem_stolen_insert_node(struct intel_stolen_node *node, u64 size, + unsigned int alignment) +{ + return __i915_gem_stolen_insert_node(node->i915, &node->node, size, alignment); +} + +static void __i915_gem_stolen_remove_node(struct drm_i915_private *i915, + struct drm_mm_node *node) { mutex_lock(&i915->mm.stolen_lock); drm_mm_remove_node(node); mutex_unlock(&i915->mm.stolen_lock); } +void i915_gem_stolen_remove_node(struct intel_stolen_node *node) +{ + __i915_gem_stolen_remove_node(node->i915, &node->node); +} + static bool valid_stolen_size(struct drm_i915_private *i915, struct resource *dsm) { return (dsm->start != 0 || HAS_LMEMBAR_SMEM_STOLEN(i915)) && dsm->end > dsm->start; @@ -386,6 +410,27 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915, drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val); + /* Wa_14019821291 */ + if (MEDIA_VER_FULL(i915) == IP_VER(13, 0)) { + /* + * This workaround is primarily implemented by the BIOS. We + * just need to figure out whether the BIOS has applied the + * workaround (meaning the programmed address falls within + * the DSM) and, if so, reserve that part of the DSM to + * prevent accidental reuse. The DSM location should be just + * below the WOPCM. + */ + u64 gscpsmi_base = intel_uncore_read64_2x32(uncore, + MTL_GSCPSMI_BASEADDR_LSB, + MTL_GSCPSMI_BASEADDR_MSB); + if (gscpsmi_base >= i915->dsm.stolen.start && + gscpsmi_base < i915->dsm.stolen.end) { + *base = gscpsmi_base; + *size = i915->dsm.stolen.end - gscpsmi_base; + return; + } + } + switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) { case GEN8_STOLEN_RESERVED_1M: *size = 1024 * 1024; @@ -436,7 +481,7 @@ static int init_reserved_stolen(struct drm_i915_private *i915) icl_get_stolen_reserved(i915, uncore, &reserved_base, &reserved_size); } else if (GRAPHICS_VER(i915) >= 8) { - if (IS_LP(i915)) + if (IS_CHERRYVIEW(i915) || IS_BROXTON(i915) || IS_GEMINILAKE(i915)) chv_get_stolen_reserved(i915, uncore, &reserved_base, &reserved_size); else @@ -520,7 +565,9 @@ static int i915_gem_init_stolen(struct intel_memory_region *mem) /* Exclude the reserved region from driver use */ mem->region.end = i915->dsm.reserved.start - 1; - mem->io_size = min(mem->io_size, resource_size(&mem->region)); + mem->io = DEFINE_RES_MEM(mem->io.start, + min(resource_size(&mem->io), + resource_size(&mem->region))); i915->dsm.usable_size = resource_size(&mem->region); @@ -661,7 +708,7 @@ i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) struct drm_mm_node *stolen = fetch_and_zero(&obj->stolen); GEM_BUG_ON(!stolen); - i915_gem_stolen_remove_node(i915, stolen); + __i915_gem_stolen_remove_node(i915, stolen); kfree(stolen); i915_gem_object_release_memory_region(obj); @@ -731,7 +778,7 @@ static int _i915_gem_object_stolen_init(struct intel_memory_region *mem, * With discrete devices, where we lack a mappable aperture there is no * possible way to ever access this memory on the CPU side. */ - if (mem->type == INTEL_MEMORY_STOLEN_LOCAL && !mem->io_size && + if (mem->type == INTEL_MEMORY_STOLEN_LOCAL && !resource_size(&mem->io) && !(flags & I915_BO_ALLOC_GPU_ONLY)) return -ENOSPC; @@ -750,8 +797,8 @@ static int _i915_gem_object_stolen_init(struct intel_memory_region *mem, ret = drm_mm_reserve_node(&i915->mm.stolen, stolen); mutex_unlock(&i915->mm.stolen_lock); } else { - ret = i915_gem_stolen_insert_node(i915, stolen, size, - mem->min_page_size); + ret = __i915_gem_stolen_insert_node(i915, stolen, size, + mem->min_page_size); } if (ret) goto err_free; @@ -763,7 +810,7 @@ static int _i915_gem_object_stolen_init(struct intel_memory_region *mem, return 0; err_remove: - i915_gem_stolen_remove_node(i915, stolen); + __i915_gem_stolen_remove_node(i915, stolen); err_free: kfree(stolen); return ret; @@ -805,7 +852,6 @@ static const struct intel_memory_region_ops i915_region_stolen_smem_ops = { static int init_stolen_lmem(struct intel_memory_region *mem) { - struct drm_i915_private *i915 = mem->i915; int err; if (GEM_WARN_ON(resource_size(&mem->region) == 0)) @@ -817,14 +863,10 @@ static int init_stolen_lmem(struct intel_memory_region *mem) return 0; } - if (mem->io_size && - !io_mapping_init_wc(&mem->iomap, mem->io_start, mem->io_size)) + if (resource_size(&mem->io) && + !io_mapping_init_wc(&mem->iomap, mem->io.start, resource_size(&mem->io))) goto err_cleanup; - drm_dbg(&i915->drm, "Stolen Local memory IO start: %pa\n", - &mem->io_start); - drm_dbg(&i915->drm, "Stolen Local DSM base: %pa\n", &mem->region.start); - return 0; err_cleanup: @@ -834,7 +876,7 @@ err_cleanup: static int release_stolen_lmem(struct intel_memory_region *mem) { - if (mem->io_size) + if (resource_size(&mem->io)) io_mapping_fini(&mem->iomap); i915_gem_cleanup_stolen(mem->i915); return 0; @@ -917,13 +959,21 @@ i915_gem_stolen_lmem_setup(struct drm_i915_private *i915, u16 type, GEM_BUG_ON((dsm_base + dsm_size) > lmem_size); } else { /* Use DSM base address instead for stolen memory */ - dsm_base = intel_uncore_read64(uncore, GEN12_DSMBASE) & GEN12_BDSM_MASK; - if (WARN_ON(lmem_size < dsm_base)) - return ERR_PTR(-ENODEV); + dsm_base = intel_uncore_read64(uncore, GEN6_DSMBASE) & GEN11_BDSM_MASK; + if (lmem_size < dsm_base) { + drm_dbg(&i915->drm, + "Disabling stolen memory support due to OOB placement: lmem_size = %pa vs dsm_base = %pa\n", + &lmem_size, &dsm_base); + return NULL; + } dsm_size = ALIGN_DOWN(lmem_size - dsm_base, SZ_1M); } - if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) { + if (i915_direct_stolen_access(i915)) { + drm_dbg(&i915->drm, "Using direct DSM access\n"); + io_start = intel_uncore_read64(uncore, GEN6_DSMBASE) & GEN11_BDSM_MASK; + io_size = dsm_size; + } else if (pci_resource_len(pdev, GEN12_LMEM_BAR) < lmem_size) { io_start = 0; io_size = 0; } else { @@ -975,38 +1025,64 @@ bool i915_gem_object_is_stolen(const struct drm_i915_gem_object *obj) return obj->ops == &i915_gem_object_stolen_ops; } -bool i915_gem_stolen_initialized(const struct drm_i915_private *i915) +bool i915_gem_stolen_initialized(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); + return drm_mm_initialized(&i915->mm.stolen); } -u64 i915_gem_stolen_area_address(const struct drm_i915_private *i915) +u64 i915_gem_stolen_area_address(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); + return i915->dsm.stolen.start; } -u64 i915_gem_stolen_area_size(const struct drm_i915_private *i915) +u64 i915_gem_stolen_area_size(struct drm_device *drm) { + struct drm_i915_private *i915 = to_i915(drm); + return resource_size(&i915->dsm.stolen); } -u64 i915_gem_stolen_node_address(const struct drm_i915_private *i915, - const struct drm_mm_node *node) +u64 i915_gem_stolen_node_address(const struct intel_stolen_node *node) { + struct drm_i915_private *i915 = node->i915; + return i915->dsm.stolen.start + i915_gem_stolen_node_offset(node); } -bool i915_gem_stolen_node_allocated(const struct drm_mm_node *node) +bool i915_gem_stolen_node_allocated(const struct intel_stolen_node *node) { - return drm_mm_node_allocated(node); + return drm_mm_node_allocated(&node->node); } -u64 i915_gem_stolen_node_offset(const struct drm_mm_node *node) +u64 i915_gem_stolen_node_offset(const struct intel_stolen_node *node) { - return node->start; + return node->node.start; +} + +u64 i915_gem_stolen_node_size(const struct intel_stolen_node *node) +{ + return node->node.size; +} + +struct intel_stolen_node *i915_gem_stolen_node_alloc(struct drm_device *drm) +{ + struct drm_i915_private *i915 = to_i915(drm); + struct intel_stolen_node *node; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return NULL; + + node->i915 = i915; + + return node; } -u64 i915_gem_stolen_node_size(const struct drm_mm_node *node) +void i915_gem_stolen_node_free(const struct intel_stolen_node *node) { - return node->size; + kfree(node); } |
