intel_guc_ads.c 6.5 KB
Newer Older
1
// SPDX-License-Identifier: MIT
2
/*
3
 * Copyright © 2014-2019 Intel Corporation
4 5
 */

6
#include "gt/intel_gt.h"
7
#include "gt/intel_lrc.h"
8
#include "intel_guc_ads.h"
9
#include "intel_guc_fwif.h"
10 11 12 13 14
#include "intel_uc.h"
#include "i915_drv.h"

/*
 * The Additional Data Struct (ADS) has pointers for different buffers used by
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 * the GuC. One single gem object contains the ADS struct itself (guc_ads) and
 * all the extra buffers indirectly linked via the ADS struct's entries.
 *
 * Layout of the ADS blob allocated for the GuC:
 *
 *      +---------------------------------------+ <== base
 *      | guc_ads                               |
 *      +---------------------------------------+
 *      | guc_policies                          |
 *      +---------------------------------------+
 *      | guc_gt_system_info                    |
 *      +---------------------------------------+
 *      | padding                               |
 *      +---------------------------------------+ <== 4K aligned
 *      | private data                          |
 *      +---------------------------------------+
 *      | padding                               |
 *      +---------------------------------------+ <== 4K aligned
33
 */
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
struct __guc_ads_blob {
	struct guc_ads ads;
	struct guc_policies policies;
	struct guc_gt_system_info system_info;
} __packed;

static u32 guc_ads_private_data_size(struct intel_guc *guc)
{
	return PAGE_ALIGN(guc->fw.private_data_size);
}

static u32 guc_ads_private_data_offset(struct intel_guc *guc)
{
	return PAGE_ALIGN(sizeof(struct __guc_ads_blob));
}

static u32 guc_ads_blob_size(struct intel_guc *guc)
{
	return guc_ads_private_data_offset(guc) +
	       guc_ads_private_data_size(guc);
}
55 56 57

static void guc_policies_init(struct guc_policies *policies)
{
58 59 60 61
	policies->dpc_promote_time = GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US;
	policies->max_num_work_items = GLOBAL_POLICY_MAX_NUM_WI;
	/* Disable automatic resets as not yet supported. */
	policies->global_flags = GLOBAL_POLICY_DISABLE_ENGINE_RESET;
62 63 64
	policies->is_valid = 1;
}

65 66 67 68 69 70 71 72 73 74 75 76 77 78
static void guc_mapping_table_init(struct intel_gt *gt,
				   struct guc_gt_system_info *system_info)
{
	unsigned int i, j;
	struct intel_engine_cs *engine;
	enum intel_engine_id id;

	/* Table must be set to invalid values for entries not used */
	for (i = 0; i < GUC_MAX_ENGINE_CLASSES; ++i)
		for (j = 0; j < GUC_MAX_INSTANCES_PER_CLASS; ++j)
			system_info->mapping_table[i][j] =
				GUC_MAX_INSTANCES_PER_CLASS;

	for_each_engine(engine, gt, id) {
79
		u8 guc_class = engine_class_to_guc_class(engine->class);
80 81 82 83 84 85

		system_info->mapping_table[guc_class][engine->instance] =
			engine->instance;
	}
}

86 87 88 89 90 91
/*
 * The first 80 dwords of the register state context, containing the
 * execlists and ppgtt registers.
 */
#define LR_HW_CONTEXT_SIZE	(80 * sizeof(u32))

92
static void __guc_ads_init(struct intel_guc *guc)
93
{
94
	struct intel_gt *gt = guc_to_gt(guc);
95
	struct drm_i915_private *i915 = gt->i915;
96
	struct __guc_ads_blob *blob = guc->ads_blob;
97 98
	const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE;
	u32 base;
99
	u8 engine_class, guc_class;
100 101 102 103 104

	/* GuC scheduling policies */
	guc_policies_init(&blob->policies);

	/*
105 106 107 108 109 110
	 * GuC expects a per-engine-class context image and size
	 * (minus hwsp and ring context). The context image will be
	 * used to reinitialize engines after a reset. It must exist
	 * and be pinned in the GGTT, so that the address won't change after
	 * we have told GuC where to find it. The context size will be used
	 * to validate that the LRC base + size fall within allowed GGTT.
111
	 */
112 113 114
	for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; ++engine_class) {
		if (engine_class == OTHER_CLASS)
			continue;
115 116 117

		guc_class = engine_class_to_guc_class(engine_class);

118 119 120 121
		/*
		 * TODO: Set context pointer to default state to allow
		 * GuC to re-init guilty contexts after internal reset.
		 */
122 123
		blob->ads.golden_context_lrca[guc_class] = 0;
		blob->ads.eng_state_size[guc_class] =
124 125
			intel_engine_context_size(guc_to_gt(guc),
						  engine_class) -
126 127
			skipped_size;
	}
128

129
	/* System info */
130 131 132 133
	blob->system_info.engine_enabled_masks[GUC_RENDER_CLASS] = 1;
	blob->system_info.engine_enabled_masks[GUC_BLITTER_CLASS] = 1;
	blob->system_info.engine_enabled_masks[GUC_VIDEO_CLASS] = VDBOX_MASK(gt);
	blob->system_info.engine_enabled_masks[GUC_VIDEOENHANCE_CLASS] = VEBOX_MASK(gt);
134 135 136 137 138 139

	blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED] =
		hweight8(gt->info.sseu.slice_mask);
	blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK] =
		gt->info.vdbox_sfc_access;

140
	if (GRAPHICS_VER(i915) >= 12 && !IS_DGFX(i915)) {
141 142 143 144 145 146
		u32 distdbreg = intel_uncore_read(gt->uncore,
						  GEN12_DIST_DBS_POPULATED);
		blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI] =
			((distdbreg >> GEN12_DOORBELLS_PER_SQIDI_SHIFT) &
			 GEN12_DOORBELLS_PER_SQIDI) + 1;
	}
147

148
	guc_mapping_table_init(guc_to_gt(guc), &blob->system_info);
149

150
	base = intel_guc_ggtt_offset(guc, guc->ads_vma);
151 152

	/* ADS */
153
	blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
154
	blob->ads.gt_system_info = base + ptr_offset(blob, system_info);
155

156 157 158
	/* Private Data */
	blob->ads.private_data = base + guc_ads_private_data_offset(guc);

159
	i915_gem_object_flush_map(guc->ads_vma->obj);
160 161 162 163 164 165 166 167 168 169 170
}

/**
 * intel_guc_ads_create() - allocates and initializes GuC ADS.
 * @guc: intel_guc struct
 *
 * GuC needs memory block (Additional Data Struct), where it will store
 * some data. Allocate and initialize such memory block for GuC use.
 */
int intel_guc_ads_create(struct intel_guc *guc)
{
171
	u32 size;
172 173 174 175
	int ret;

	GEM_BUG_ON(guc->ads_vma);

176 177
	size = guc_ads_blob_size(guc);

178 179 180 181
	ret = intel_guc_allocate_and_map_vma(guc, size, &guc->ads_vma,
					     (void **)&guc->ads_blob);
	if (ret)
		return ret;
182

183
	__guc_ads_init(guc);
184 185

	return 0;
186 187 188 189
}

void intel_guc_ads_destroy(struct intel_guc *guc)
{
190
	i915_vma_unpin_and_release(&guc->ads_vma, I915_VMA_RELEASE_MAP);
191
	guc->ads_blob = NULL;
192
}
193

194 195 196 197 198 199 200 201 202 203 204 205
static void guc_ads_private_data_reset(struct intel_guc *guc)
{
	u32 size;

	size = guc_ads_private_data_size(guc);
	if (!size)
		return;

	memset((void *)guc->ads_blob + guc_ads_private_data_offset(guc), 0,
	       size);
}

206 207 208 209 210 211 212 213 214 215 216 217
/**
 * intel_guc_ads_reset() - prepares GuC Additional Data Struct for reuse
 * @guc: intel_guc struct
 *
 * GuC stores some data in ADS, which might be stale after a reset.
 * Reinitialize whole ADS in case any part of it was corrupted during
 * previous GuC run.
 */
void intel_guc_ads_reset(struct intel_guc *guc)
{
	if (!guc->ads_vma)
		return;
218

219
	__guc_ads_init(guc);
220 221

	guc_ads_private_data_reset(guc);
222
}