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