1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2019 Intel Corporation
4  */
5 
6 #include "i915_drv.h"
7 #include "i915_reg.h"
8 #include "intel_memory_region.h"
9 #include "intel_region_lmem.h"
10 #include "intel_region_ttm.h"
11 #include "gem/i915_gem_lmem.h"
12 #include "gem/i915_gem_region.h"
13 #include "gem/i915_gem_ttm.h"
14 #include "gt/intel_gt.h"
15 #include "gt/intel_gt_regs.h"
16 
17 static int
18 region_lmem_release(struct intel_memory_region *mem)
19 {
20 	int ret;
21 
22 	ret = intel_region_ttm_fini(mem);
23 	io_mapping_fini(&mem->iomap);
24 
25 	return ret;
26 }
27 
28 static int
29 region_lmem_init(struct intel_memory_region *mem)
30 {
31 	int ret;
32 
33 	if (!io_mapping_init_wc(&mem->iomap,
34 				mem->io_start,
35 				mem->io_size))
36 		return -EIO;
37 
38 	ret = intel_region_ttm_init(mem);
39 	if (ret)
40 		goto out_no_buddy;
41 
42 	return 0;
43 
44 out_no_buddy:
45 	io_mapping_fini(&mem->iomap);
46 
47 	return ret;
48 }
49 
50 static const struct intel_memory_region_ops intel_region_lmem_ops = {
51 	.init = region_lmem_init,
52 	.release = region_lmem_release,
53 	.init_object = __i915_gem_ttm_object_init,
54 };
55 
56 static bool get_legacy_lowmem_region(struct intel_uncore *uncore,
57 				     u64 *start, u32 *size)
58 {
59 	if (!IS_DG1_GRAPHICS_STEP(uncore->i915, STEP_A0, STEP_C0))
60 		return false;
61 
62 	*start = 0;
63 	*size = SZ_1M;
64 
65 	drm_dbg(&uncore->i915->drm, "LMEM: reserved legacy low-memory [0x%llx-0x%llx]\n",
66 		*start, *start + *size);
67 
68 	return true;
69 }
70 
71 static int reserve_lowmem_region(struct intel_uncore *uncore,
72 				 struct intel_memory_region *mem)
73 {
74 	u64 reserve_start;
75 	u32 reserve_size;
76 	int ret;
77 
78 	if (!get_legacy_lowmem_region(uncore, &reserve_start, &reserve_size))
79 		return 0;
80 
81 	ret = intel_memory_region_reserve(mem, reserve_start, reserve_size);
82 	if (ret)
83 		drm_err(&uncore->i915->drm, "LMEM: reserving low memory region failed\n");
84 
85 	return ret;
86 }
87 
88 static struct intel_memory_region *setup_lmem(struct intel_gt *gt)
89 {
90 	struct drm_i915_private *i915 = gt->i915;
91 	struct intel_uncore *uncore = gt->uncore;
92 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
93 	struct intel_memory_region *mem;
94 	resource_size_t min_page_size;
95 	resource_size_t io_start;
96 	resource_size_t lmem_size;
97 	int err;
98 
99 	if (!IS_DGFX(i915))
100 		return ERR_PTR(-ENODEV);
101 
102 	if (HAS_FLAT_CCS(i915)) {
103 		u64 tile_stolen, flat_ccs_base;
104 
105 		lmem_size = pci_resource_len(pdev, 2);
106 		flat_ccs_base = intel_gt_read_register(gt, XEHPSDV_FLAT_CCS_BASE_ADDR);
107 		flat_ccs_base = (flat_ccs_base >> XEHPSDV_CCS_BASE_SHIFT) * SZ_64K;
108 
109 		if (GEM_WARN_ON(lmem_size < flat_ccs_base))
110 			return ERR_PTR(-ENODEV);
111 
112 		tile_stolen = lmem_size - flat_ccs_base;
113 
114 		/* If the FLAT_CCS_BASE_ADDR register is not populated, flag an error */
115 		if (tile_stolen == lmem_size)
116 			drm_err(&i915->drm,
117 				"CCS_BASE_ADDR register did not have expected value\n");
118 
119 		lmem_size -= tile_stolen;
120 	} else {
121 		/* Stolen starts from GSMBASE without CCS */
122 		lmem_size = intel_uncore_read64(&i915->uncore, GEN12_GSMBASE);
123 	}
124 
125 
126 	io_start = pci_resource_start(pdev, 2);
127 	if (GEM_WARN_ON(lmem_size > pci_resource_len(pdev, 2)))
128 		return ERR_PTR(-ENODEV);
129 
130 	min_page_size = HAS_64K_PAGES(i915) ? I915_GTT_PAGE_SIZE_64K :
131 						I915_GTT_PAGE_SIZE_4K;
132 	mem = intel_memory_region_create(i915,
133 					 0,
134 					 lmem_size,
135 					 min_page_size,
136 					 io_start,
137 					 lmem_size,
138 					 INTEL_MEMORY_LOCAL,
139 					 0,
140 					 &intel_region_lmem_ops);
141 	if (IS_ERR(mem))
142 		return mem;
143 
144 	err = reserve_lowmem_region(uncore, mem);
145 	if (err)
146 		goto err_region_put;
147 
148 	drm_dbg(&i915->drm, "Local memory: %pR\n", &mem->region);
149 	drm_dbg(&i915->drm, "Local memory IO start: %pa\n",
150 		&mem->io_start);
151 	drm_info(&i915->drm, "Local memory IO size: %pa\n",
152 		 &mem->io_size);
153 	drm_info(&i915->drm, "Local memory available: %pa\n",
154 		 &lmem_size);
155 
156 	return mem;
157 
158 err_region_put:
159 	intel_memory_region_destroy(mem);
160 	return ERR_PTR(err);
161 }
162 
163 struct intel_memory_region *intel_gt_setup_lmem(struct intel_gt *gt)
164 {
165 	return setup_lmem(gt);
166 }
167