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 #include "intel_uc.h" 11 #include "i915_drv.h" 12 13 /* 14 * The Additional Data Struct (ADS) has pointers for different buffers used by 15 * the GuC. One single gem object contains the ADS struct itself (guc_ads) and 16 * all the extra buffers indirectly linked via the ADS struct's entries. 17 * 18 * Layout of the ADS blob allocated for the GuC: 19 * 20 * +---------------------------------------+ <== base 21 * | guc_ads | 22 * +---------------------------------------+ 23 * | guc_policies | 24 * +---------------------------------------+ 25 * | guc_gt_system_info | 26 * +---------------------------------------+ 27 * | guc_clients_info | 28 * +---------------------------------------+ 29 * | guc_ct_pool_entry[size] | 30 * +---------------------------------------+ 31 * | padding | 32 * +---------------------------------------+ <== 4K aligned 33 * | private data | 34 * +---------------------------------------+ 35 * | padding | 36 * +---------------------------------------+ <== 4K aligned 37 */ 38 struct __guc_ads_blob { 39 struct guc_ads ads; 40 struct guc_policies policies; 41 struct guc_gt_system_info system_info; 42 struct guc_clients_info clients_info; 43 struct guc_ct_pool_entry ct_pool[GUC_CT_POOL_SIZE]; 44 } __packed; 45 46 static u32 guc_ads_private_data_size(struct intel_guc *guc) 47 { 48 return PAGE_ALIGN(guc->fw.private_data_size); 49 } 50 51 static u32 guc_ads_private_data_offset(struct intel_guc *guc) 52 { 53 return PAGE_ALIGN(sizeof(struct __guc_ads_blob)); 54 } 55 56 static u32 guc_ads_blob_size(struct intel_guc *guc) 57 { 58 return guc_ads_private_data_offset(guc) + 59 guc_ads_private_data_size(guc); 60 } 61 62 static void guc_policy_init(struct guc_policy *policy) 63 { 64 policy->execution_quantum = POLICY_DEFAULT_EXECUTION_QUANTUM_US; 65 policy->preemption_time = POLICY_DEFAULT_PREEMPTION_TIME_US; 66 policy->fault_time = POLICY_DEFAULT_FAULT_TIME_US; 67 policy->policy_flags = 0; 68 } 69 70 static void guc_policies_init(struct guc_policies *policies) 71 { 72 struct guc_policy *policy; 73 u32 p, i; 74 75 policies->dpc_promote_time = POLICY_DEFAULT_DPC_PROMOTE_TIME_US; 76 policies->max_num_work_items = POLICY_MAX_NUM_WI; 77 78 for (p = 0; p < GUC_CLIENT_PRIORITY_NUM; p++) { 79 for (i = 0; i < GUC_MAX_ENGINE_CLASSES; i++) { 80 policy = &policies->policy[p][i]; 81 82 guc_policy_init(policy); 83 } 84 } 85 86 policies->is_valid = 1; 87 } 88 89 static void guc_ct_pool_entries_init(struct guc_ct_pool_entry *pool, u32 num) 90 { 91 memset(pool, 0, num * sizeof(*pool)); 92 } 93 94 static void guc_mapping_table_init(struct intel_gt *gt, 95 struct guc_gt_system_info *system_info) 96 { 97 unsigned int i, j; 98 struct intel_engine_cs *engine; 99 enum intel_engine_id id; 100 101 /* Table must be set to invalid values for entries not used */ 102 for (i = 0; i < GUC_MAX_ENGINE_CLASSES; ++i) 103 for (j = 0; j < GUC_MAX_INSTANCES_PER_CLASS; ++j) 104 system_info->mapping_table[i][j] = 105 GUC_MAX_INSTANCES_PER_CLASS; 106 107 for_each_engine(engine, gt, id) { 108 u8 guc_class = engine_class_to_guc_class(engine->class); 109 110 system_info->mapping_table[guc_class][engine->instance] = 111 engine->instance; 112 } 113 } 114 115 /* 116 * The first 80 dwords of the register state context, containing the 117 * execlists and ppgtt registers. 118 */ 119 #define LR_HW_CONTEXT_SIZE (80 * sizeof(u32)) 120 121 static void __guc_ads_init(struct intel_guc *guc) 122 { 123 struct intel_gt *gt = guc_to_gt(guc); 124 struct drm_i915_private *i915 = gt->i915; 125 struct __guc_ads_blob *blob = guc->ads_blob; 126 const u32 skipped_size = LRC_PPHWSP_SZ * PAGE_SIZE + LR_HW_CONTEXT_SIZE; 127 u32 base; 128 u8 engine_class, guc_class; 129 130 /* GuC scheduling policies */ 131 guc_policies_init(&blob->policies); 132 133 /* 134 * GuC expects a per-engine-class context image and size 135 * (minus hwsp and ring context). The context image will be 136 * used to reinitialize engines after a reset. It must exist 137 * and be pinned in the GGTT, so that the address won't change after 138 * we have told GuC where to find it. The context size will be used 139 * to validate that the LRC base + size fall within allowed GGTT. 140 */ 141 for (engine_class = 0; engine_class <= MAX_ENGINE_CLASS; ++engine_class) { 142 if (engine_class == OTHER_CLASS) 143 continue; 144 145 guc_class = engine_class_to_guc_class(engine_class); 146 147 /* 148 * TODO: Set context pointer to default state to allow 149 * GuC to re-init guilty contexts after internal reset. 150 */ 151 blob->ads.golden_context_lrca[guc_class] = 0; 152 blob->ads.eng_state_size[guc_class] = 153 intel_engine_context_size(guc_to_gt(guc), 154 engine_class) - 155 skipped_size; 156 } 157 158 /* System info */ 159 blob->system_info.engine_enabled_masks[GUC_RENDER_CLASS] = 1; 160 blob->system_info.engine_enabled_masks[GUC_BLITTER_CLASS] = 1; 161 blob->system_info.engine_enabled_masks[GUC_VIDEO_CLASS] = VDBOX_MASK(gt); 162 blob->system_info.engine_enabled_masks[GUC_VIDEOENHANCE_CLASS] = VEBOX_MASK(gt); 163 164 blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED] = 165 hweight8(gt->info.sseu.slice_mask); 166 blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK] = 167 gt->info.vdbox_sfc_access; 168 169 if (GRAPHICS_VER(i915) >= 12 && !IS_DGFX(i915)) { 170 u32 distdbreg = intel_uncore_read(gt->uncore, 171 GEN12_DIST_DBS_POPULATED); 172 blob->system_info.generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_DOORBELL_COUNT_PER_SQIDI] = 173 ((distdbreg >> GEN12_DOORBELLS_PER_SQIDI_SHIFT) & 174 GEN12_DOORBELLS_PER_SQIDI) + 1; 175 } 176 177 guc_mapping_table_init(guc_to_gt(guc), &blob->system_info); 178 179 base = intel_guc_ggtt_offset(guc, guc->ads_vma); 180 181 /* Clients info */ 182 guc_ct_pool_entries_init(blob->ct_pool, ARRAY_SIZE(blob->ct_pool)); 183 184 blob->clients_info.clients_num = 1; 185 blob->clients_info.ct_pool_addr = base + ptr_offset(blob, ct_pool); 186 blob->clients_info.ct_pool_count = ARRAY_SIZE(blob->ct_pool); 187 188 /* ADS */ 189 blob->ads.scheduler_policies = base + ptr_offset(blob, policies); 190 blob->ads.gt_system_info = base + ptr_offset(blob, system_info); 191 blob->ads.clients_info = base + ptr_offset(blob, clients_info); 192 193 /* Private Data */ 194 blob->ads.private_data = base + guc_ads_private_data_offset(guc); 195 196 i915_gem_object_flush_map(guc->ads_vma->obj); 197 } 198 199 /** 200 * intel_guc_ads_create() - allocates and initializes GuC ADS. 201 * @guc: intel_guc struct 202 * 203 * GuC needs memory block (Additional Data Struct), where it will store 204 * some data. Allocate and initialize such memory block for GuC use. 205 */ 206 int intel_guc_ads_create(struct intel_guc *guc) 207 { 208 u32 size; 209 int ret; 210 211 GEM_BUG_ON(guc->ads_vma); 212 213 size = guc_ads_blob_size(guc); 214 215 ret = intel_guc_allocate_and_map_vma(guc, size, &guc->ads_vma, 216 (void **)&guc->ads_blob); 217 if (ret) 218 return ret; 219 220 __guc_ads_init(guc); 221 222 return 0; 223 } 224 225 void intel_guc_ads_destroy(struct intel_guc *guc) 226 { 227 i915_vma_unpin_and_release(&guc->ads_vma, I915_VMA_RELEASE_MAP); 228 guc->ads_blob = NULL; 229 } 230 231 static void guc_ads_private_data_reset(struct intel_guc *guc) 232 { 233 u32 size; 234 235 size = guc_ads_private_data_size(guc); 236 if (!size) 237 return; 238 239 memset((void *)guc->ads_blob + guc_ads_private_data_offset(guc), 0, 240 size); 241 } 242 243 /** 244 * intel_guc_ads_reset() - prepares GuC Additional Data Struct for reuse 245 * @guc: intel_guc struct 246 * 247 * GuC stores some data in ADS, which might be stale after a reset. 248 * Reinitialize whole ADS in case any part of it was corrupted during 249 * previous GuC run. 250 */ 251 void intel_guc_ads_reset(struct intel_guc *guc) 252 { 253 if (!guc->ads_vma) 254 return; 255 256 __guc_ads_init(guc); 257 258 guc_ads_private_data_reset(guc); 259 } 260