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