intel_region_lmem.c 6.9 KB
Newer Older
1 2 3 4 5 6
// SPDX-License-Identifier: MIT
/*
 * Copyright © 2019 Intel Corporation
 */

#include "i915_drv.h"
7
#include "i915_reg.h"
8
#include "intel_memory_region.h"
9 10
#include "intel_region_lmem.h"
#include "intel_region_ttm.h"
11 12
#include "gem/i915_gem_lmem.h"
#include "gem/i915_gem_region.h"
13
#include "gem/i915_gem_ttm.h"
14
#include "gt/intel_gt.h"
15
#include "gt/intel_gt_mcr.h"
16
#include "gt/intel_gt_regs.h"
17

18
#ifdef CONFIG_64BIT
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
static void _release_bars(struct pci_dev *pdev)
{
	int resno;

	for (resno = PCI_STD_RESOURCES; resno < PCI_STD_RESOURCE_END; resno++) {
		if (pci_resource_len(pdev, resno))
			pci_release_resource(pdev, resno);
	}
}

static void
_resize_bar(struct drm_i915_private *i915, int resno, resource_size_t size)
{
	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
	int bar_size = pci_rebar_bytes_to_size(size);
	int ret;

	_release_bars(pdev);

	ret = pci_resize_resource(pdev, resno, bar_size);
	if (ret) {
		drm_info(&i915->drm, "Failed to resize BAR%d to %dM (%pe)\n",
			 resno, 1 << bar_size, ERR_PTR(ret));
		return;
	}

	drm_info(&i915->drm, "BAR%d resized to %dM\n", resno, 1 << bar_size);
}

#define LMEM_BAR_NUM 2
static void i915_resize_lmem_bar(struct drm_i915_private *i915, resource_size_t lmem_size)
{
	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
	struct pci_bus *root = pdev->bus;
	struct resource *root_res;
	resource_size_t rebar_size;
55
	resource_size_t current_size;
56 57 58
	u32 pci_cmd;
	int i;

59
	current_size = roundup_pow_of_two(pci_resource_len(pdev, LMEM_BAR_NUM));
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	if (i915->params.lmem_bar_size) {
		u32 bar_sizes;

		rebar_size = i915->params.lmem_bar_size *
			(resource_size_t)SZ_1M;
		bar_sizes = pci_rebar_get_possible_sizes(pdev,
							 LMEM_BAR_NUM);

		if (rebar_size == current_size)
			return;

		if (!(bar_sizes & BIT(pci_rebar_bytes_to_size(rebar_size))) ||
		    rebar_size >= roundup_pow_of_two(lmem_size)) {
			rebar_size = lmem_size;

			drm_info(&i915->drm,
				 "Given bar size is not within supported size, setting it to default: %llu\n",
				 (u64)lmem_size >> 20);
		}
	} else {
		rebar_size = current_size;

		if (rebar_size != roundup_pow_of_two(lmem_size))
			rebar_size = lmem_size;
		else
			return;
	}
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

	/* Find out if root bus contains 64bit memory addressing */
	while (root->parent)
		root = root->parent;

	pci_bus_for_each_resource(root, root_res, i) {
		if (root_res && root_res->flags & (IORESOURCE_MEM | IORESOURCE_MEM_64) &&
		    root_res->start > 0x100000000ull)
			break;
	}

	/* pci_resize_resource will fail anyways */
	if (!root_res) {
		drm_info(&i915->drm, "Can't resize LMEM BAR - platform support is missing\n");
		return;
	}

	/* First disable PCI memory decoding references */
	pci_read_config_dword(pdev, PCI_COMMAND, &pci_cmd);
	pci_write_config_dword(pdev, PCI_COMMAND,
			       pci_cmd & ~PCI_COMMAND_MEMORY);

	_resize_bar(i915, LMEM_BAR_NUM, rebar_size);

	pci_assign_unassigned_bus_resources(pdev->bus);
	pci_write_config_dword(pdev, PCI_COMMAND, pci_cmd);
}
115 116 117
#else
static void i915_resize_lmem_bar(struct drm_i915_private *i915, resource_size_t lmem_size) {}
#endif
118

119
static int
120 121
region_lmem_release(struct intel_memory_region *mem)
{
122 123 124
	int ret;

	ret = intel_region_ttm_fini(mem);
125
	io_mapping_fini(&mem->iomap);
126 127

	return ret;
128 129 130 131 132 133 134 135 136
}

static int
region_lmem_init(struct intel_memory_region *mem)
{
	int ret;

	if (!io_mapping_init_wc(&mem->iomap,
				mem->io_start,
M
Matthew Auld 已提交
137
				mem->io_size))
138
		return -EIO;
139

140
	ret = intel_region_ttm_init(mem);
141
	if (ret)
142 143 144 145 146 147
		goto out_no_buddy;

	return 0;

out_no_buddy:
	io_mapping_fini(&mem->iomap);
148 149 150 151

	return ret;
}

152
static const struct intel_memory_region_ops intel_region_lmem_ops = {
153 154
	.init = region_lmem_init,
	.release = region_lmem_release,
155
	.init_object = __i915_gem_ttm_object_init,
156
};
157

158 159 160
static bool get_legacy_lowmem_region(struct intel_uncore *uncore,
				     u64 *start, u32 *size)
{
161
	if (!IS_DG1_GRAPHICS_STEP(uncore->i915, STEP_A0, STEP_C0))
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
		return false;

	*start = 0;
	*size = SZ_1M;

	drm_dbg(&uncore->i915->drm, "LMEM: reserved legacy low-memory [0x%llx-0x%llx]\n",
		*start, *start + *size);

	return true;
}

static int reserve_lowmem_region(struct intel_uncore *uncore,
				 struct intel_memory_region *mem)
{
	u64 reserve_start;
	u32 reserve_size;
	int ret;

	if (!get_legacy_lowmem_region(uncore, &reserve_start, &reserve_size))
		return 0;

	ret = intel_memory_region_reserve(mem, reserve_start, reserve_size);
	if (ret)
		drm_err(&uncore->i915->drm, "LMEM: reserving low memory region failed\n");

	return ret;
}

M
Matthew Auld 已提交
190 191 192
static struct intel_memory_region *setup_lmem(struct intel_gt *gt)
{
	struct drm_i915_private *i915 = gt->i915;
193
	struct intel_uncore *uncore = gt->uncore;
194
	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
M
Matthew Auld 已提交
195
	struct intel_memory_region *mem;
196
	resource_size_t min_page_size;
M
Matthew Auld 已提交
197
	resource_size_t io_start;
198
	resource_size_t io_size;
199
	resource_size_t lmem_size;
200
	int err;
M
Matthew Auld 已提交
201 202 203 204

	if (!IS_DGFX(i915))
		return ERR_PTR(-ENODEV);

205
	if (HAS_FLAT_CCS(i915)) {
206
		resource_size_t lmem_range;
207 208
		u64 tile_stolen, flat_ccs_base;

209 210
		lmem_range = intel_gt_mcr_read_any(&i915->gt0, XEHP_TILE0_ADDR_RANGE) & 0xFFFF;
		lmem_size = lmem_range >> XEHP_TILE_LMEM_RANGE_SHIFT;
211 212
		lmem_size *= SZ_1G;

213 214
		flat_ccs_base = intel_gt_mcr_read_any(gt, XEHP_FLAT_CCS_BASE_ADDR);
		flat_ccs_base = (flat_ccs_base >> XEHP_CCS_BASE_SHIFT) * SZ_64K;
215 216

		if (GEM_WARN_ON(lmem_size < flat_ccs_base))
217
			return ERR_PTR(-EIO);
218 219 220 221 222 223 224 225 226 227 228 229 230 231

		tile_stolen = lmem_size - flat_ccs_base;

		/* If the FLAT_CCS_BASE_ADDR register is not populated, flag an error */
		if (tile_stolen == lmem_size)
			drm_err(&i915->drm,
				"CCS_BASE_ADDR register did not have expected value\n");

		lmem_size -= tile_stolen;
	} else {
		/* Stolen starts from GSMBASE without CCS */
		lmem_size = intel_uncore_read64(&i915->uncore, GEN12_GSMBASE);
	}

232 233
	i915_resize_lmem_bar(i915, lmem_size);

C
CQ Tang 已提交
234 235 236 237
	if (i915->params.lmem_size > 0) {
		lmem_size = min_t(resource_size_t, lmem_size,
				  mul_u32_u32(i915->params.lmem_size, SZ_1M));
	}
238

M
Matthew Auld 已提交
239
	io_start = pci_resource_start(pdev, 2);
240 241
	io_size = min(pci_resource_len(pdev, 2), lmem_size);
	if (!io_size)
242
		return ERR_PTR(-EIO);
M
Matthew Auld 已提交
243

244 245
	min_page_size = HAS_64K_PAGES(i915) ? I915_GTT_PAGE_SIZE_64K :
						I915_GTT_PAGE_SIZE_4K;
M
Matthew Auld 已提交
246 247
	mem = intel_memory_region_create(i915,
					 0,
248
					 lmem_size,
249
					 min_page_size,
M
Matthew Auld 已提交
250
					 io_start,
251
					 io_size,
252 253
					 INTEL_MEMORY_LOCAL,
					 0,
M
Matthew Auld 已提交
254 255 256 257
					 &intel_region_lmem_ops);
	if (IS_ERR(mem))
		return mem;

258 259 260 261
	err = reserve_lowmem_region(uncore, mem);
	if (err)
		goto err_region_put;

M
Matthew Auld 已提交
262 263 264
	drm_dbg(&i915->drm, "Local memory: %pR\n", &mem->region);
	drm_dbg(&i915->drm, "Local memory IO start: %pa\n",
		&mem->io_start);
M
Matthew Auld 已提交
265 266
	drm_info(&i915->drm, "Local memory IO size: %pa\n",
		 &mem->io_size);
267 268
	drm_info(&i915->drm, "Local memory available: %pa\n",
		 &lmem_size);
M
Matthew Auld 已提交
269

270 271 272 273
	if (io_size < lmem_size)
		drm_info(&i915->drm, "Using a reduced BAR size of %lluMiB. Consider enabling 'Resizable BAR' or similar, if available in the BIOS.\n",
			 (u64)io_size >> 20);

M
Matthew Auld 已提交
274
	return mem;
275 276

err_region_put:
277
	intel_memory_region_destroy(mem);
278
	return ERR_PTR(err);
M
Matthew Auld 已提交
279 280 281 282 283 284
}

struct intel_memory_region *intel_gt_setup_lmem(struct intel_gt *gt)
{
	return setup_lmem(gt);
}