/* * 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 * use by the OS and so the user finds that his system has less memory * available than he put in. We refer to this memory as stolen. * * The BIOS will allocate its framebuffer from the stolen memory. Our * goal is try to reuse that object for our own fbcon which must always * be available for panics. Anything else we can reuse the stolen memory * 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)
{ int ret;
if (!drm_mm_initialized(&i915->mm.stolen)) return -ENODEV;
if (!valid_stolen_size(i915, dsm)) return -EINVAL;
/* * Make sure we don't clobber the GTT if it's within stolen memory * * 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.
*/ if (GRAPHICS_VER(i915) <= 4 &&
!IS_G33(i915) && !IS_PINEVIEW(i915) && !IS_G4X(i915)) { struct resource stolen[2] = {*dsm, *dsm}; struct resource ggtt_res;
resource_size_t ggtt_start;
/* * With stolen lmem, we don't need to request system memory for the * address range since it's local to the gpu. * * Starting MTL, in IGFX devices the stolen memory is exposed via * LMEMBAR and shall be considered similar to stolen lmem.
*/ if (HAS_LMEM(i915) || HAS_LMEMBAR_SMEM_STOLEN(i915)) return 0;
/* * Verify that nothing else uses this physical address. Stolen * memory should be reserved by the BIOS and hidden from the * kernel. So if the region is already marked as busy, something * is seriously wrong.
*/
r = devm_request_mem_region(i915->drm.dev, dsm->start,
resource_size(dsm), "Graphics Stolen Memory"); if (r == NULL) { /* * One more attempt but this time requesting region from * start + 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. * There's also BIOS with off-by-one on the other end.
*/
r = devm_request_mem_region(i915->drm.dev, dsm->start + 1,
resource_size(dsm) - 2, "Graphics Stolen Memory"); /* * GEN3 firmware likes to smash pci bridges into the stolen * range. Apparently this works.
*/ if (!r && GRAPHICS_VER(i915) != 3) {
drm_err(&i915->drm, "conflict detected with stolen region: %pR\n",
dsm);
return -EBUSY;
}
}
return 0;
}
staticvoid i915_gem_cleanup_stolen(struct drm_i915_private *i915)
{ if (!drm_mm_initialized(&i915->mm.stolen)) return;
if ((reg_val & G4X_STOLEN_RESERVED_ENABLE) == 0) return;
/* * Whether ILK really reuses the ELK register for this is unclear. * Let's see if we catch anyone with this supposedly enabled on ILK.
*/
drm_WARN(&i915->drm, GRAPHICS_VER(i915) == 5, "ILK stolen reserved found? 0x%08x\n",
reg_val);
if (!(reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK)) return;
/* 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;
}
}
if (HAS_LMEMBAR_SMEM_STOLEN(i915)) /* the base is initialized to stolen top so subtract size to get base */
*base -= *size; else
*base = reg_val & GEN11_STOLEN_RESERVED_ADDR_MASK;
}
/* * Initialize i915->dsm.reserved to contain the reserved space within the Data * Stolen Memory. This is a range on the top of DSM that is reserved, not to * be used by driver, so must be excluded from the region passed to the * allocator later. In the spec this is also called as WOPCM. * * Our expectation is that the reserved space is at the top of the stolen * region, as it has been the case for every platform, and *never* at the * bottom, so the calculation here can be simplified.
*/ staticint init_reserved_stolen(struct drm_i915_private *i915)
{ struct intel_uncore *uncore = &i915->uncore;
resource_size_t reserved_base, stolen_top;
resource_size_t reserved_size; int ret = 0;
if (intel_vgpu_active(i915)) {
drm_notice(&i915->drm, "%s, disabling use of stolen memory\n", "iGVT-g active"); return -ENOSPC;
}
if (i915_vtd_active(i915) && GRAPHICS_VER(i915) < 8) {
drm_notice(&i915->drm, "%s, disabling use of stolen memory\n", "DMAR active"); return -ENOSPC;
}
if (adjust_stolen(i915, &mem->region)) return -ENOSPC;
if (request_smem_stolen(i915, &mem->region)) return -ENOSPC;
i915->dsm.stolen = mem->region;
if (init_reserved_stolen(i915)) return -ENOSPC;
/* Exclude the reserved region from driver use */
mem->region.end = i915->dsm.reserved.start - 1;
mem->io = DEFINE_RES_MEM(mem->io.start,
min(resource_size(&mem->io),
resource_size(&mem->region)));
/* * Access to stolen lmem beyond certain size for MTL A0 stepping * would crash the machine. Disable stolen lmem for userspace access * by setting usable_size to zero.
*/ if (IS_METEORLAKE(i915) && INTEL_REVID(i915) == 0x0)
i915->dsm.usable_size = 0;
/* We hide that we have no struct page backing our stolen object * by wrapping the contiguous physical allocation with a fake * dma mapping in a single scatterlist.
*/
st = kmalloc(sizeof(*st), GFP_KERNEL); if (st == NULL) return ERR_PTR(-ENOMEM);
if (sg_alloc_table(st, 1, GFP_KERNEL)) {
kfree(st); return ERR_PTR(-ENOMEM);
}
staticvoid i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj, struct sg_table *pages)
{ struct drm_i915_private *i915 = to_i915(obj->base.dev); /* Should only be called from i915_gem_object_release_stolen() */
/* * Stolen objects are always physically contiguous since we just * allocate one big block underneath using the drm_mm range allocator.
*/
flags = I915_BO_ALLOC_CONTIGUOUS;
if (!drm_mm_initialized(&i915->mm.stolen)) return -ENODEV;
if (size == 0) return -EINVAL;
/* * 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 && !resource_size(&mem->io) &&
!(flags & I915_BO_ALLOC_GPU_ONLY)) return -ENOSPC;
stolen = kzalloc(sizeof(*stolen), GFP_KERNEL); if (!stolen) return -ENOMEM;
staticint init_stolen_smem(struct intel_memory_region *mem)
{ int err;
/* * Initialise stolen early so that we may reserve preallocated * objects for the BIOS to KMS transition.
*/
err = i915_gem_init_stolen(mem); if (err)
drm_dbg(&mem->i915->drm, "Skip stolen region: failed to setup\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.