xref: /openbmc/linux/drivers/gpu/drm/i915/gt/intel_region_lmem.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1f178b897SMatthew Auld // SPDX-License-Identifier: MIT
2f178b897SMatthew Auld /*
3f178b897SMatthew Auld  * Copyright © 2019 Intel Corporation
4f178b897SMatthew Auld  */
5f178b897SMatthew Auld 
6f178b897SMatthew Auld #include "i915_drv.h"
71bba7323SPiotr Piórkowski #include "i915_pci.h"
8ce2fce25SMatt Roper #include "i915_reg.h"
9f178b897SMatthew Auld #include "intel_memory_region.h"
106bba2b30SPiotr Piórkowski #include "intel_pci_config.h"
11d1487389SThomas Hellström #include "intel_region_lmem.h"
12d1487389SThomas Hellström #include "intel_region_ttm.h"
13f178b897SMatthew Auld #include "gem/i915_gem_lmem.h"
14f178b897SMatthew Auld #include "gem/i915_gem_region.h"
15213d5092SThomas Hellström #include "gem/i915_gem_ttm.h"
163ffe82d7SDaniele Ceraolo Spurio #include "gt/intel_gt.h"
17e7858254SMatt Roper #include "gt/intel_gt_mcr.h"
1830424ebaSRodrigo Vivi #include "gt/intel_gt_regs.h"
19f178b897SMatthew Auld 
209cae5b31SNirmoy Das #ifdef CONFIG_64BIT
_release_bars(struct pci_dev * pdev)21a91d1a17SAkeem G Abodunrin static void _release_bars(struct pci_dev *pdev)
22a91d1a17SAkeem G Abodunrin {
23a91d1a17SAkeem G Abodunrin 	int resno;
24a91d1a17SAkeem G Abodunrin 
25a91d1a17SAkeem G Abodunrin 	for (resno = PCI_STD_RESOURCES; resno < PCI_STD_RESOURCE_END; resno++) {
26a91d1a17SAkeem G Abodunrin 		if (pci_resource_len(pdev, resno))
27a91d1a17SAkeem G Abodunrin 			pci_release_resource(pdev, resno);
28a91d1a17SAkeem G Abodunrin 	}
29a91d1a17SAkeem G Abodunrin }
30a91d1a17SAkeem G Abodunrin 
31a91d1a17SAkeem G Abodunrin static void
_resize_bar(struct drm_i915_private * i915,int resno,resource_size_t size)32a91d1a17SAkeem G Abodunrin _resize_bar(struct drm_i915_private *i915, int resno, resource_size_t size)
33a91d1a17SAkeem G Abodunrin {
34a91d1a17SAkeem G Abodunrin 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
35a91d1a17SAkeem G Abodunrin 	int bar_size = pci_rebar_bytes_to_size(size);
36a91d1a17SAkeem G Abodunrin 	int ret;
37a91d1a17SAkeem G Abodunrin 
38a91d1a17SAkeem G Abodunrin 	_release_bars(pdev);
39a91d1a17SAkeem G Abodunrin 
40a91d1a17SAkeem G Abodunrin 	ret = pci_resize_resource(pdev, resno, bar_size);
41a91d1a17SAkeem G Abodunrin 	if (ret) {
42a91d1a17SAkeem G Abodunrin 		drm_info(&i915->drm, "Failed to resize BAR%d to %dM (%pe)\n",
43a91d1a17SAkeem G Abodunrin 			 resno, 1 << bar_size, ERR_PTR(ret));
44a91d1a17SAkeem G Abodunrin 		return;
45a91d1a17SAkeem G Abodunrin 	}
46a91d1a17SAkeem G Abodunrin 
47a91d1a17SAkeem G Abodunrin 	drm_info(&i915->drm, "BAR%d resized to %dM\n", resno, 1 << bar_size);
48a91d1a17SAkeem G Abodunrin }
49a91d1a17SAkeem G Abodunrin 
i915_resize_lmem_bar(struct drm_i915_private * i915,resource_size_t lmem_size)50a91d1a17SAkeem G Abodunrin static void i915_resize_lmem_bar(struct drm_i915_private *i915, resource_size_t lmem_size)
51a91d1a17SAkeem G Abodunrin {
52a91d1a17SAkeem G Abodunrin 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
53a91d1a17SAkeem G Abodunrin 	struct pci_bus *root = pdev->bus;
54a91d1a17SAkeem G Abodunrin 	struct resource *root_res;
55a91d1a17SAkeem G Abodunrin 	resource_size_t rebar_size;
5617cd10a4SPriyanka Dandamudi 	resource_size_t current_size;
571de17842SAndrzej Hajda 	intel_wakeref_t wakeref;
58a91d1a17SAkeem G Abodunrin 	u32 pci_cmd;
59a91d1a17SAkeem G Abodunrin 	int i;
60a91d1a17SAkeem G Abodunrin 
616bba2b30SPiotr Piórkowski 	current_size = roundup_pow_of_two(pci_resource_len(pdev, GEN12_LMEM_BAR));
6217cd10a4SPriyanka Dandamudi 
6317cd10a4SPriyanka Dandamudi 	if (i915->params.lmem_bar_size) {
6417cd10a4SPriyanka Dandamudi 		u32 bar_sizes;
6517cd10a4SPriyanka Dandamudi 
6617cd10a4SPriyanka Dandamudi 		rebar_size = i915->params.lmem_bar_size *
6717cd10a4SPriyanka Dandamudi 			(resource_size_t)SZ_1M;
686bba2b30SPiotr Piórkowski 		bar_sizes = pci_rebar_get_possible_sizes(pdev, GEN12_LMEM_BAR);
6917cd10a4SPriyanka Dandamudi 
7017cd10a4SPriyanka Dandamudi 		if (rebar_size == current_size)
7117cd10a4SPriyanka Dandamudi 			return;
7217cd10a4SPriyanka Dandamudi 
7317cd10a4SPriyanka Dandamudi 		if (!(bar_sizes & BIT(pci_rebar_bytes_to_size(rebar_size))) ||
7417cd10a4SPriyanka Dandamudi 		    rebar_size >= roundup_pow_of_two(lmem_size)) {
7517cd10a4SPriyanka Dandamudi 			rebar_size = lmem_size;
7617cd10a4SPriyanka Dandamudi 
7717cd10a4SPriyanka Dandamudi 			drm_info(&i915->drm,
7817cd10a4SPriyanka Dandamudi 				 "Given bar size is not within supported size, setting it to default: %llu\n",
7917cd10a4SPriyanka Dandamudi 				 (u64)lmem_size >> 20);
8017cd10a4SPriyanka Dandamudi 		}
8117cd10a4SPriyanka Dandamudi 	} else {
8217cd10a4SPriyanka Dandamudi 		rebar_size = current_size;
83a91d1a17SAkeem G Abodunrin 
84a91d1a17SAkeem G Abodunrin 		if (rebar_size != roundup_pow_of_two(lmem_size))
85a91d1a17SAkeem G Abodunrin 			rebar_size = lmem_size;
86a91d1a17SAkeem G Abodunrin 		else
87a91d1a17SAkeem G Abodunrin 			return;
8817cd10a4SPriyanka Dandamudi 	}
89a91d1a17SAkeem G Abodunrin 
90a91d1a17SAkeem G Abodunrin 	/* Find out if root bus contains 64bit memory addressing */
91a91d1a17SAkeem G Abodunrin 	while (root->parent)
92a91d1a17SAkeem G Abodunrin 		root = root->parent;
93a91d1a17SAkeem G Abodunrin 
94a91d1a17SAkeem G Abodunrin 	pci_bus_for_each_resource(root, root_res, i) {
95a91d1a17SAkeem G Abodunrin 		if (root_res && root_res->flags & (IORESOURCE_MEM | IORESOURCE_MEM_64) &&
96a91d1a17SAkeem G Abodunrin 		    root_res->start > 0x100000000ull)
97a91d1a17SAkeem G Abodunrin 			break;
98a91d1a17SAkeem G Abodunrin 	}
99a91d1a17SAkeem G Abodunrin 
100a91d1a17SAkeem G Abodunrin 	/* pci_resize_resource will fail anyways */
101a91d1a17SAkeem G Abodunrin 	if (!root_res) {
102a91d1a17SAkeem G Abodunrin 		drm_info(&i915->drm, "Can't resize LMEM BAR - platform support is missing\n");
103a91d1a17SAkeem G Abodunrin 		return;
104a91d1a17SAkeem G Abodunrin 	}
105a91d1a17SAkeem G Abodunrin 
1061de17842SAndrzej Hajda 	/*
1071de17842SAndrzej Hajda 	 * Releasing forcewake during BAR resizing results in later forcewake
1081de17842SAndrzej Hajda 	 * ack timeouts and former can happen any time - it is asynchronous.
1091de17842SAndrzej Hajda 	 * Grabbing all forcewakes prevents it.
1101de17842SAndrzej Hajda 	 */
1111de17842SAndrzej Hajda 	with_intel_runtime_pm(i915->uncore.rpm, wakeref) {
1121de17842SAndrzej Hajda 		intel_uncore_forcewake_get(&i915->uncore, FORCEWAKE_ALL);
1131de17842SAndrzej Hajda 
114a91d1a17SAkeem G Abodunrin 		/* First disable PCI memory decoding references */
115a91d1a17SAkeem G Abodunrin 		pci_read_config_dword(pdev, PCI_COMMAND, &pci_cmd);
116a91d1a17SAkeem G Abodunrin 		pci_write_config_dword(pdev, PCI_COMMAND,
117a91d1a17SAkeem G Abodunrin 				       pci_cmd & ~PCI_COMMAND_MEMORY);
118a91d1a17SAkeem G Abodunrin 
1196bba2b30SPiotr Piórkowski 		_resize_bar(i915, GEN12_LMEM_BAR, rebar_size);
120a91d1a17SAkeem G Abodunrin 
121a91d1a17SAkeem G Abodunrin 		pci_assign_unassigned_bus_resources(pdev->bus);
122a91d1a17SAkeem G Abodunrin 		pci_write_config_dword(pdev, PCI_COMMAND, pci_cmd);
1231de17842SAndrzej Hajda 		intel_uncore_forcewake_put(&i915->uncore, FORCEWAKE_ALL);
1241de17842SAndrzej Hajda 	}
125a91d1a17SAkeem G Abodunrin }
1269cae5b31SNirmoy Das #else
i915_resize_lmem_bar(struct drm_i915_private * i915,resource_size_t lmem_size)1279cae5b31SNirmoy Das static void i915_resize_lmem_bar(struct drm_i915_private *i915, resource_size_t lmem_size) {}
1289cae5b31SNirmoy Das #endif
129a91d1a17SAkeem G Abodunrin 
1308b1f7f92SThomas Hellström static int
region_lmem_release(struct intel_memory_region * mem)131f178b897SMatthew Auld region_lmem_release(struct intel_memory_region *mem)
132f178b897SMatthew Auld {
1338b1f7f92SThomas Hellström 	int ret;
1348b1f7f92SThomas Hellström 
1358b1f7f92SThomas Hellström 	ret = intel_region_ttm_fini(mem);
136f178b897SMatthew Auld 	io_mapping_fini(&mem->iomap);
1378b1f7f92SThomas Hellström 
1388b1f7f92SThomas Hellström 	return ret;
139f178b897SMatthew Auld }
140f178b897SMatthew Auld 
141f178b897SMatthew Auld static int
region_lmem_init(struct intel_memory_region * mem)142f178b897SMatthew Auld region_lmem_init(struct intel_memory_region *mem)
143f178b897SMatthew Auld {
144f178b897SMatthew Auld 	int ret;
145f178b897SMatthew Auld 
146f178b897SMatthew Auld 	if (!io_mapping_init_wc(&mem->iomap,
147f178b897SMatthew Auld 				mem->io_start,
148235582caSMatthew Auld 				mem->io_size))
1498c26491fSLucas De Marchi 		return -EIO;
150f178b897SMatthew Auld 
151d1487389SThomas Hellström 	ret = intel_region_ttm_init(mem);
152f178b897SMatthew Auld 	if (ret)
153d1487389SThomas Hellström 		goto out_no_buddy;
154d1487389SThomas Hellström 
155d1487389SThomas Hellström 	return 0;
156d1487389SThomas Hellström 
157d1487389SThomas Hellström out_no_buddy:
158f178b897SMatthew Auld 	io_mapping_fini(&mem->iomap);
159f178b897SMatthew Auld 
160f178b897SMatthew Auld 	return ret;
161f178b897SMatthew Auld }
162f178b897SMatthew Auld 
163f178b897SMatthew Auld static const struct intel_memory_region_ops intel_region_lmem_ops = {
164f178b897SMatthew Auld 	.init = region_lmem_init,
165f178b897SMatthew Auld 	.release = region_lmem_release,
166213d5092SThomas Hellström 	.init_object = __i915_gem_ttm_object_init,
167f178b897SMatthew Auld };
168f178b897SMatthew Auld 
get_legacy_lowmem_region(struct intel_uncore * uncore,u64 * start,u32 * size)1697c5cc941SImre Deak static bool get_legacy_lowmem_region(struct intel_uncore *uncore,
1707c5cc941SImre Deak 				     u64 *start, u32 *size)
1717c5cc941SImre Deak {
1723c4b33d0SMatt Roper 	if (!IS_DG1(uncore->i915))
1737c5cc941SImre Deak 		return false;
1747c5cc941SImre Deak 
1757c5cc941SImre Deak 	*start = 0;
1767c5cc941SImre Deak 	*size = SZ_1M;
1777c5cc941SImre Deak 
1787c5cc941SImre Deak 	drm_dbg(&uncore->i915->drm, "LMEM: reserved legacy low-memory [0x%llx-0x%llx]\n",
1797c5cc941SImre Deak 		*start, *start + *size);
1807c5cc941SImre Deak 
1817c5cc941SImre Deak 	return true;
1827c5cc941SImre Deak }
1837c5cc941SImre Deak 
reserve_lowmem_region(struct intel_uncore * uncore,struct intel_memory_region * mem)1847c5cc941SImre Deak static int reserve_lowmem_region(struct intel_uncore *uncore,
1857c5cc941SImre Deak 				 struct intel_memory_region *mem)
1867c5cc941SImre Deak {
1877c5cc941SImre Deak 	u64 reserve_start;
1887c5cc941SImre Deak 	u32 reserve_size;
1897c5cc941SImre Deak 	int ret;
1907c5cc941SImre Deak 
1917c5cc941SImre Deak 	if (!get_legacy_lowmem_region(uncore, &reserve_start, &reserve_size))
1927c5cc941SImre Deak 		return 0;
1937c5cc941SImre Deak 
1947c5cc941SImre Deak 	ret = intel_memory_region_reserve(mem, reserve_start, reserve_size);
1957c5cc941SImre Deak 	if (ret)
1967c5cc941SImre Deak 		drm_err(&uncore->i915->drm, "LMEM: reserving low memory region failed\n");
1977c5cc941SImre Deak 
1987c5cc941SImre Deak 	return ret;
1997c5cc941SImre Deak }
2007c5cc941SImre Deak 
setup_lmem(struct intel_gt * gt)201a50ca39fSMatthew Auld static struct intel_memory_region *setup_lmem(struct intel_gt *gt)
202a50ca39fSMatthew Auld {
203a50ca39fSMatthew Auld 	struct drm_i915_private *i915 = gt->i915;
2047f2aa5b3SCQ Tang 	struct intel_uncore *uncore = gt->uncore;
20597c463b2SThomas Zimmermann 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
206a50ca39fSMatthew Auld 	struct intel_memory_region *mem;
207ca921624SMatthew Auld 	resource_size_t min_page_size;
208a50ca39fSMatthew Auld 	resource_size_t io_start;
20956eda725SMatthew Auld 	resource_size_t io_size;
2107f2aa5b3SCQ Tang 	resource_size_t lmem_size;
2117c5cc941SImre Deak 	int err;
212a50ca39fSMatthew Auld 
213a50ca39fSMatthew Auld 	if (!IS_DGFX(i915))
214a50ca39fSMatthew Auld 		return ERR_PTR(-ENODEV);
215a50ca39fSMatthew Auld 
2161bba7323SPiotr Piórkowski 	if (!i915_pci_resource_valid(pdev, GEN12_LMEM_BAR))
2171bba7323SPiotr Piórkowski 		return ERR_PTR(-ENXIO);
2181bba7323SPiotr Piórkowski 
2194b31b8e3SAbdiel Janulgue 	if (HAS_FLAT_CCS(i915)) {
2208f6de231SNirmoy Das 		resource_size_t lmem_range;
2214b31b8e3SAbdiel Janulgue 		u64 tile_stolen, flat_ccs_base;
2224b31b8e3SAbdiel Janulgue 
223*306f7a5bSAndi Shyti 		lmem_range = intel_gt_mcr_read_any(to_gt(i915), XEHP_TILE0_ADDR_RANGE) & 0xFFFF;
2247d809707SMatt Roper 		lmem_size = lmem_range >> XEHP_TILE_LMEM_RANGE_SHIFT;
2258f6de231SNirmoy Das 		lmem_size *= SZ_1G;
2268f6de231SNirmoy Das 
2277d809707SMatt Roper 		flat_ccs_base = intel_gt_mcr_read_any(gt, XEHP_FLAT_CCS_BASE_ADDR);
2287d809707SMatt Roper 		flat_ccs_base = (flat_ccs_base >> XEHP_CCS_BASE_SHIFT) * SZ_64K;
2294b31b8e3SAbdiel Janulgue 
2304b31b8e3SAbdiel Janulgue 		if (GEM_WARN_ON(lmem_size < flat_ccs_base))
231d158367cSNirmoy Das 			return ERR_PTR(-EIO);
2324b31b8e3SAbdiel Janulgue 
2334b31b8e3SAbdiel Janulgue 		tile_stolen = lmem_size - flat_ccs_base;
2344b31b8e3SAbdiel Janulgue 
2354b31b8e3SAbdiel Janulgue 		/* If the FLAT_CCS_BASE_ADDR register is not populated, flag an error */
2364b31b8e3SAbdiel Janulgue 		if (tile_stolen == lmem_size)
2374b31b8e3SAbdiel Janulgue 			drm_err(&i915->drm,
2384b31b8e3SAbdiel Janulgue 				"CCS_BASE_ADDR register did not have expected value\n");
2394b31b8e3SAbdiel Janulgue 
2404b31b8e3SAbdiel Janulgue 		lmem_size -= tile_stolen;
2414b31b8e3SAbdiel Janulgue 	} else {
2424b31b8e3SAbdiel Janulgue 		/* Stolen starts from GSMBASE without CCS */
2434b31b8e3SAbdiel Janulgue 		lmem_size = intel_uncore_read64(&i915->uncore, GEN12_GSMBASE);
2444b31b8e3SAbdiel Janulgue 	}
2454b31b8e3SAbdiel Janulgue 
246a91d1a17SAkeem G Abodunrin 	i915_resize_lmem_bar(i915, lmem_size);
247a91d1a17SAkeem G Abodunrin 
248be658e70SCQ Tang 	if (i915->params.lmem_size > 0) {
249be658e70SCQ Tang 		lmem_size = min_t(resource_size_t, lmem_size,
250be658e70SCQ Tang 				  mul_u32_u32(i915->params.lmem_size, SZ_1M));
251be658e70SCQ Tang 	}
2527f2aa5b3SCQ Tang 
2536bba2b30SPiotr Piórkowski 	io_start = pci_resource_start(pdev, GEN12_LMEM_BAR);
2546bba2b30SPiotr Piórkowski 	io_size = min(pci_resource_len(pdev, GEN12_LMEM_BAR), lmem_size);
25556eda725SMatthew Auld 	if (!io_size)
256d158367cSNirmoy Das 		return ERR_PTR(-EIO);
257a50ca39fSMatthew Auld 
258ca921624SMatthew Auld 	min_page_size = HAS_64K_PAGES(i915) ? I915_GTT_PAGE_SIZE_64K :
259ca921624SMatthew Auld 						I915_GTT_PAGE_SIZE_4K;
260a50ca39fSMatthew Auld 	mem = intel_memory_region_create(i915,
261a50ca39fSMatthew Auld 					 0,
2627f2aa5b3SCQ Tang 					 lmem_size,
263ca921624SMatthew Auld 					 min_page_size,
264a50ca39fSMatthew Auld 					 io_start,
26556eda725SMatthew Auld 					 io_size,
266d1487389SThomas Hellström 					 INTEL_MEMORY_LOCAL,
267d1487389SThomas Hellström 					 0,
268a50ca39fSMatthew Auld 					 &intel_region_lmem_ops);
269a50ca39fSMatthew Auld 	if (IS_ERR(mem))
270a50ca39fSMatthew Auld 		return mem;
271a50ca39fSMatthew Auld 
2727c5cc941SImre Deak 	err = reserve_lowmem_region(uncore, mem);
2737c5cc941SImre Deak 	if (err)
2747c5cc941SImre Deak 		goto err_region_put;
2757c5cc941SImre Deak 
276a50ca39fSMatthew Auld 	drm_dbg(&i915->drm, "Local memory: %pR\n", &mem->region);
277a50ca39fSMatthew Auld 	drm_dbg(&i915->drm, "Local memory IO start: %pa\n",
278a50ca39fSMatthew Auld 		&mem->io_start);
279235582caSMatthew Auld 	drm_info(&i915->drm, "Local memory IO size: %pa\n",
280235582caSMatthew Auld 		 &mem->io_size);
2817f2aa5b3SCQ Tang 	drm_info(&i915->drm, "Local memory available: %pa\n",
2827f2aa5b3SCQ Tang 		 &lmem_size);
283a50ca39fSMatthew Auld 
284eb1c535fSMatthew Auld 	if (io_size < lmem_size)
285eb1c535fSMatthew Auld 		drm_info(&i915->drm, "Using a reduced BAR size of %lluMiB. Consider enabling 'Resizable BAR' or similar, if available in the BIOS.\n",
286eb1c535fSMatthew Auld 			 (u64)io_size >> 20);
287eb1c535fSMatthew Auld 
288a50ca39fSMatthew Auld 	return mem;
2897c5cc941SImre Deak 
2907c5cc941SImre Deak err_region_put:
2918b1f7f92SThomas Hellström 	intel_memory_region_destroy(mem);
2927c5cc941SImre Deak 	return ERR_PTR(err);
293a50ca39fSMatthew Auld }
294a50ca39fSMatthew Auld 
intel_gt_setup_lmem(struct intel_gt * gt)295a50ca39fSMatthew Auld struct intel_memory_region *intel_gt_setup_lmem(struct intel_gt *gt)
296a50ca39fSMatthew Auld {
297a50ca39fSMatthew Auld 	return setup_lmem(gt);
298a50ca39fSMatthew Auld }
299