18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright © 2019 Intel Corporation
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include "i915_drv.h"
78c2ecf20Sopenharmony_ci#include "intel_memory_region.h"
88c2ecf20Sopenharmony_ci#include "gem/i915_gem_lmem.h"
98c2ecf20Sopenharmony_ci#include "gem/i915_gem_region.h"
108c2ecf20Sopenharmony_ci#include "intel_region_lmem.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic int init_fake_lmem_bar(struct intel_memory_region *mem)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = mem->i915;
158c2ecf20Sopenharmony_ci	struct i915_ggtt *ggtt = &i915->ggtt;
168c2ecf20Sopenharmony_ci	unsigned long n;
178c2ecf20Sopenharmony_ci	int ret;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	/* We want to 1:1 map the mappable aperture to our reserved region */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	mem->fake_mappable.start = 0;
228c2ecf20Sopenharmony_ci	mem->fake_mappable.size = resource_size(&mem->region);
238c2ecf20Sopenharmony_ci	mem->fake_mappable.color = I915_COLOR_UNEVICTABLE;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	ret = drm_mm_reserve_node(&ggtt->vm.mm, &mem->fake_mappable);
268c2ecf20Sopenharmony_ci	if (ret)
278c2ecf20Sopenharmony_ci		return ret;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	mem->remap_addr = dma_map_resource(&i915->drm.pdev->dev,
308c2ecf20Sopenharmony_ci					   mem->region.start,
318c2ecf20Sopenharmony_ci					   mem->fake_mappable.size,
328c2ecf20Sopenharmony_ci					   PCI_DMA_BIDIRECTIONAL,
338c2ecf20Sopenharmony_ci					   DMA_ATTR_FORCE_CONTIGUOUS);
348c2ecf20Sopenharmony_ci	if (dma_mapping_error(&i915->drm.pdev->dev, mem->remap_addr)) {
358c2ecf20Sopenharmony_ci		drm_mm_remove_node(&mem->fake_mappable);
368c2ecf20Sopenharmony_ci		return -EINVAL;
378c2ecf20Sopenharmony_ci	}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	for (n = 0; n < mem->fake_mappable.size >> PAGE_SHIFT; ++n) {
408c2ecf20Sopenharmony_ci		ggtt->vm.insert_page(&ggtt->vm,
418c2ecf20Sopenharmony_ci				     mem->remap_addr + (n << PAGE_SHIFT),
428c2ecf20Sopenharmony_ci				     n << PAGE_SHIFT,
438c2ecf20Sopenharmony_ci				     I915_CACHE_NONE, 0);
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	mem->region = (struct resource)DEFINE_RES_MEM(mem->remap_addr,
478c2ecf20Sopenharmony_ci						      mem->fake_mappable.size);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	return 0;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic void release_fake_lmem_bar(struct intel_memory_region *mem)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	if (!drm_mm_node_allocated(&mem->fake_mappable))
558c2ecf20Sopenharmony_ci		return;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	drm_mm_remove_node(&mem->fake_mappable);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	dma_unmap_resource(&mem->i915->drm.pdev->dev,
608c2ecf20Sopenharmony_ci			   mem->remap_addr,
618c2ecf20Sopenharmony_ci			   mem->fake_mappable.size,
628c2ecf20Sopenharmony_ci			   PCI_DMA_BIDIRECTIONAL,
638c2ecf20Sopenharmony_ci			   DMA_ATTR_FORCE_CONTIGUOUS);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic void
678c2ecf20Sopenharmony_ciregion_lmem_release(struct intel_memory_region *mem)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	release_fake_lmem_bar(mem);
708c2ecf20Sopenharmony_ci	io_mapping_fini(&mem->iomap);
718c2ecf20Sopenharmony_ci	intel_memory_region_release_buddy(mem);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic int
758c2ecf20Sopenharmony_ciregion_lmem_init(struct intel_memory_region *mem)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	int ret;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (mem->i915->params.fake_lmem_start) {
808c2ecf20Sopenharmony_ci		ret = init_fake_lmem_bar(mem);
818c2ecf20Sopenharmony_ci		GEM_BUG_ON(ret);
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (!io_mapping_init_wc(&mem->iomap,
858c2ecf20Sopenharmony_ci				mem->io_start,
868c2ecf20Sopenharmony_ci				resource_size(&mem->region)))
878c2ecf20Sopenharmony_ci		return -EIO;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	ret = intel_memory_region_init_buddy(mem);
908c2ecf20Sopenharmony_ci	if (ret)
918c2ecf20Sopenharmony_ci		io_mapping_fini(&mem->iomap);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	intel_memory_region_set_name(mem, "local");
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return ret;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciconst struct intel_memory_region_ops intel_region_lmem_ops = {
998c2ecf20Sopenharmony_ci	.init = region_lmem_init,
1008c2ecf20Sopenharmony_ci	.release = region_lmem_release,
1018c2ecf20Sopenharmony_ci	.create_object = __i915_gem_lmem_object_create,
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistruct intel_memory_region *
1058c2ecf20Sopenharmony_ciintel_setup_fake_lmem(struct drm_i915_private *i915)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct pci_dev *pdev = i915->drm.pdev;
1088c2ecf20Sopenharmony_ci	struct intel_memory_region *mem;
1098c2ecf20Sopenharmony_ci	resource_size_t mappable_end;
1108c2ecf20Sopenharmony_ci	resource_size_t io_start;
1118c2ecf20Sopenharmony_ci	resource_size_t start;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	GEM_BUG_ON(i915_ggtt_has_aperture(&i915->ggtt));
1148c2ecf20Sopenharmony_ci	GEM_BUG_ON(!i915->params.fake_lmem_start);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* Your mappable aperture belongs to me now! */
1178c2ecf20Sopenharmony_ci	mappable_end = pci_resource_len(pdev, 2);
1188c2ecf20Sopenharmony_ci	io_start = pci_resource_start(pdev, 2),
1198c2ecf20Sopenharmony_ci	start = i915->params.fake_lmem_start;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	mem = intel_memory_region_create(i915,
1228c2ecf20Sopenharmony_ci					 start,
1238c2ecf20Sopenharmony_ci					 mappable_end,
1248c2ecf20Sopenharmony_ci					 PAGE_SIZE,
1258c2ecf20Sopenharmony_ci					 io_start,
1268c2ecf20Sopenharmony_ci					 &intel_region_lmem_ops);
1278c2ecf20Sopenharmony_ci	if (!IS_ERR(mem)) {
1288c2ecf20Sopenharmony_ci		drm_info(&i915->drm, "Intel graphics fake LMEM: %pR\n",
1298c2ecf20Sopenharmony_ci			 &mem->region);
1308c2ecf20Sopenharmony_ci		drm_info(&i915->drm,
1318c2ecf20Sopenharmony_ci			 "Intel graphics fake LMEM IO start: %llx\n",
1328c2ecf20Sopenharmony_ci			(u64)mem->io_start);
1338c2ecf20Sopenharmony_ci		drm_info(&i915->drm, "Intel graphics fake LMEM size: %llx\n",
1348c2ecf20Sopenharmony_ci			 (u64)resource_size(&mem->region));
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return mem;
1388c2ecf20Sopenharmony_ci}
139