1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2017 Etnaviv Project 4 * Copyright (C) 2017 Zodiac Inflight Innovations 5 */ 6 7 #include "etnaviv_gpu.h" 8 #include "etnaviv_perfmon.h" 9 #include "state_hi.xml.h" 10 11 struct etnaviv_pm_domain; 12 13 struct etnaviv_pm_signal { 14 char name[64]; 15 u32 data; 16 17 u32 (*sample)(struct etnaviv_gpu *gpu, 18 const struct etnaviv_pm_domain *domain, 19 const struct etnaviv_pm_signal *signal); 20 }; 21 22 struct etnaviv_pm_domain { 23 char name[64]; 24 25 /* profile register */ 26 u32 profile_read; 27 u32 profile_config; 28 29 u8 nr_signals; 30 const struct etnaviv_pm_signal *signal; 31 }; 32 33 struct etnaviv_pm_domain_meta { 34 const struct etnaviv_pm_domain *domains; 35 u32 nr_domains; 36 }; 37 38 static u32 simple_reg_read(struct etnaviv_gpu *gpu, 39 const struct etnaviv_pm_domain *domain, 40 const struct etnaviv_pm_signal *signal) 41 { 42 return gpu_read(gpu, signal->data); 43 } 44 45 static u32 perf_reg_read(struct etnaviv_gpu *gpu, 46 const struct etnaviv_pm_domain *domain, 47 const struct etnaviv_pm_signal *signal) 48 { 49 gpu_write(gpu, domain->profile_config, signal->data); 50 51 return gpu_read(gpu, domain->profile_read); 52 } 53 54 static u32 pipe_reg_read(struct etnaviv_gpu *gpu, 55 const struct etnaviv_pm_domain *domain, 56 const struct etnaviv_pm_signal *signal) 57 { 58 u32 clock = gpu_read(gpu, VIVS_HI_CLOCK_CONTROL); 59 u32 value = 0; 60 unsigned i; 61 62 for (i = 0; i < gpu->identity.pixel_pipes; i++) { 63 clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK); 64 clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(i); 65 gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock); 66 gpu_write(gpu, domain->profile_config, signal->data); 67 value += gpu_read(gpu, domain->profile_read); 68 } 69 70 /* switch back to pixel pipe 0 to prevent GPU hang */ 71 clock &= ~(VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE__MASK); 72 clock |= VIVS_HI_CLOCK_CONTROL_DEBUG_PIXEL_PIPE(0); 73 gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, clock); 74 75 return value; 76 } 77 78 static const struct etnaviv_pm_domain doms_3d[] = { 79 { 80 .name = "HI", 81 .profile_read = VIVS_MC_PROFILE_HI_READ, 82 .profile_config = VIVS_MC_PROFILE_CONFIG2, 83 .nr_signals = 5, 84 .signal = (const struct etnaviv_pm_signal[]) { 85 { 86 "TOTAL_CYCLES", 87 VIVS_HI_PROFILE_TOTAL_CYCLES, 88 &simple_reg_read 89 }, 90 { 91 "IDLE_CYCLES", 92 VIVS_HI_PROFILE_IDLE_CYCLES, 93 &simple_reg_read 94 }, 95 { 96 "AXI_CYCLES_READ_REQUEST_STALLED", 97 VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_READ_REQUEST_STALLED, 98 &perf_reg_read 99 }, 100 { 101 "AXI_CYCLES_WRITE_REQUEST_STALLED", 102 VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_REQUEST_STALLED, 103 &perf_reg_read 104 }, 105 { 106 "AXI_CYCLES_WRITE_DATA_STALLED", 107 VIVS_MC_PROFILE_CONFIG2_HI_AXI_CYCLES_WRITE_DATA_STALLED, 108 &perf_reg_read 109 } 110 } 111 }, 112 { 113 .name = "PE", 114 .profile_read = VIVS_MC_PROFILE_PE_READ, 115 .profile_config = VIVS_MC_PROFILE_CONFIG0, 116 .nr_signals = 5, 117 .signal = (const struct etnaviv_pm_signal[]) { 118 { 119 "PIXEL_COUNT_KILLED_BY_COLOR_PIPE", 120 VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_COLOR_PIPE, 121 &pipe_reg_read 122 }, 123 { 124 "PIXEL_COUNT_KILLED_BY_DEPTH_PIPE", 125 VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_KILLED_BY_DEPTH_PIPE, 126 &pipe_reg_read 127 }, 128 { 129 "PIXEL_COUNT_DRAWN_BY_COLOR_PIPE", 130 VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_COLOR_PIPE, 131 &pipe_reg_read 132 }, 133 { 134 "PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE", 135 VIVS_MC_PROFILE_CONFIG0_PE_PIXEL_COUNT_DRAWN_BY_DEPTH_PIPE, 136 &pipe_reg_read 137 } 138 } 139 }, 140 { 141 .name = "SH", 142 .profile_read = VIVS_MC_PROFILE_SH_READ, 143 .profile_config = VIVS_MC_PROFILE_CONFIG0, 144 .nr_signals = 9, 145 .signal = (const struct etnaviv_pm_signal[]) { 146 { 147 "SHADER_CYCLES", 148 VIVS_MC_PROFILE_CONFIG0_SH_SHADER_CYCLES, 149 &perf_reg_read 150 }, 151 { 152 "PS_INST_COUNTER", 153 VIVS_MC_PROFILE_CONFIG0_SH_PS_INST_COUNTER, 154 &perf_reg_read 155 }, 156 { 157 "RENDERED_PIXEL_COUNTER", 158 VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_PIXEL_COUNTER, 159 &perf_reg_read 160 }, 161 { 162 "VS_INST_COUNTER", 163 VIVS_MC_PROFILE_CONFIG0_SH_VS_INST_COUNTER, 164 &pipe_reg_read 165 }, 166 { 167 "RENDERED_VERTICE_COUNTER", 168 VIVS_MC_PROFILE_CONFIG0_SH_RENDERED_VERTICE_COUNTER, 169 &pipe_reg_read 170 }, 171 { 172 "VTX_BRANCH_INST_COUNTER", 173 VIVS_MC_PROFILE_CONFIG0_SH_VTX_BRANCH_INST_COUNTER, 174 &pipe_reg_read 175 }, 176 { 177 "VTX_TEXLD_INST_COUNTER", 178 VIVS_MC_PROFILE_CONFIG0_SH_VTX_TEXLD_INST_COUNTER, 179 &pipe_reg_read 180 }, 181 { 182 "PXL_BRANCH_INST_COUNTER", 183 VIVS_MC_PROFILE_CONFIG0_SH_PXL_BRANCH_INST_COUNTER, 184 &pipe_reg_read 185 }, 186 { 187 "PXL_TEXLD_INST_COUNTER", 188 VIVS_MC_PROFILE_CONFIG0_SH_PXL_TEXLD_INST_COUNTER, 189 &pipe_reg_read 190 } 191 } 192 }, 193 { 194 .name = "PA", 195 .profile_read = VIVS_MC_PROFILE_PA_READ, 196 .profile_config = VIVS_MC_PROFILE_CONFIG1, 197 .nr_signals = 6, 198 .signal = (const struct etnaviv_pm_signal[]) { 199 { 200 "INPUT_VTX_COUNTER", 201 VIVS_MC_PROFILE_CONFIG1_PA_INPUT_VTX_COUNTER, 202 &perf_reg_read 203 }, 204 { 205 "INPUT_PRIM_COUNTER", 206 VIVS_MC_PROFILE_CONFIG1_PA_INPUT_PRIM_COUNTER, 207 &perf_reg_read 208 }, 209 { 210 "OUTPUT_PRIM_COUNTER", 211 VIVS_MC_PROFILE_CONFIG1_PA_OUTPUT_PRIM_COUNTER, 212 &perf_reg_read 213 }, 214 { 215 "DEPTH_CLIPPED_COUNTER", 216 VIVS_MC_PROFILE_CONFIG1_PA_DEPTH_CLIPPED_COUNTER, 217 &pipe_reg_read 218 }, 219 { 220 "TRIVIAL_REJECTED_COUNTER", 221 VIVS_MC_PROFILE_CONFIG1_PA_TRIVIAL_REJECTED_COUNTER, 222 &pipe_reg_read 223 }, 224 { 225 "CULLED_COUNTER", 226 VIVS_MC_PROFILE_CONFIG1_PA_CULLED_COUNTER, 227 &pipe_reg_read 228 } 229 } 230 }, 231 { 232 .name = "SE", 233 .profile_read = VIVS_MC_PROFILE_SE_READ, 234 .profile_config = VIVS_MC_PROFILE_CONFIG1, 235 .nr_signals = 2, 236 .signal = (const struct etnaviv_pm_signal[]) { 237 { 238 "CULLED_TRIANGLE_COUNT", 239 VIVS_MC_PROFILE_CONFIG1_SE_CULLED_TRIANGLE_COUNT, 240 &perf_reg_read 241 }, 242 { 243 "CULLED_LINES_COUNT", 244 VIVS_MC_PROFILE_CONFIG1_SE_CULLED_LINES_COUNT, 245 &perf_reg_read 246 } 247 } 248 }, 249 { 250 .name = "RA", 251 .profile_read = VIVS_MC_PROFILE_RA_READ, 252 .profile_config = VIVS_MC_PROFILE_CONFIG1, 253 .nr_signals = 7, 254 .signal = (const struct etnaviv_pm_signal[]) { 255 { 256 "VALID_PIXEL_COUNT", 257 VIVS_MC_PROFILE_CONFIG1_RA_VALID_PIXEL_COUNT, 258 &perf_reg_read 259 }, 260 { 261 "TOTAL_QUAD_COUNT", 262 VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_QUAD_COUNT, 263 &perf_reg_read 264 }, 265 { 266 "VALID_QUAD_COUNT_AFTER_EARLY_Z", 267 VIVS_MC_PROFILE_CONFIG1_RA_VALID_QUAD_COUNT_AFTER_EARLY_Z, 268 &perf_reg_read 269 }, 270 { 271 "TOTAL_PRIMITIVE_COUNT", 272 VIVS_MC_PROFILE_CONFIG1_RA_TOTAL_PRIMITIVE_COUNT, 273 &perf_reg_read 274 }, 275 { 276 "PIPE_CACHE_MISS_COUNTER", 277 VIVS_MC_PROFILE_CONFIG1_RA_PIPE_CACHE_MISS_COUNTER, 278 &perf_reg_read 279 }, 280 { 281 "PREFETCH_CACHE_MISS_COUNTER", 282 VIVS_MC_PROFILE_CONFIG1_RA_PREFETCH_CACHE_MISS_COUNTER, 283 &perf_reg_read 284 }, 285 { 286 "CULLED_QUAD_COUNT", 287 VIVS_MC_PROFILE_CONFIG1_RA_CULLED_QUAD_COUNT, 288 &perf_reg_read 289 } 290 } 291 }, 292 { 293 .name = "TX", 294 .profile_read = VIVS_MC_PROFILE_TX_READ, 295 .profile_config = VIVS_MC_PROFILE_CONFIG1, 296 .nr_signals = 9, 297 .signal = (const struct etnaviv_pm_signal[]) { 298 { 299 "TOTAL_BILINEAR_REQUESTS", 300 VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_BILINEAR_REQUESTS, 301 &perf_reg_read 302 }, 303 { 304 "TOTAL_TRILINEAR_REQUESTS", 305 VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TRILINEAR_REQUESTS, 306 &perf_reg_read 307 }, 308 { 309 "TOTAL_DISCARDED_TEXTURE_REQUESTS", 310 VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_DISCARDED_TEXTURE_REQUESTS, 311 &perf_reg_read 312 }, 313 { 314 "TOTAL_TEXTURE_REQUESTS", 315 VIVS_MC_PROFILE_CONFIG1_TX_TOTAL_TEXTURE_REQUESTS, 316 &perf_reg_read 317 }, 318 { 319 "MEM_READ_COUNT", 320 VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_COUNT, 321 &perf_reg_read 322 }, 323 { 324 "MEM_READ_IN_8B_COUNT", 325 VIVS_MC_PROFILE_CONFIG1_TX_MEM_READ_IN_8B_COUNT, 326 &perf_reg_read 327 }, 328 { 329 "CACHE_MISS_COUNT", 330 VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_COUNT, 331 &perf_reg_read 332 }, 333 { 334 "CACHE_HIT_TEXEL_COUNT", 335 VIVS_MC_PROFILE_CONFIG1_TX_CACHE_HIT_TEXEL_COUNT, 336 &perf_reg_read 337 }, 338 { 339 "CACHE_MISS_TEXEL_COUNT", 340 VIVS_MC_PROFILE_CONFIG1_TX_CACHE_MISS_TEXEL_COUNT, 341 &perf_reg_read 342 } 343 } 344 }, 345 { 346 .name = "MC", 347 .profile_read = VIVS_MC_PROFILE_MC_READ, 348 .profile_config = VIVS_MC_PROFILE_CONFIG2, 349 .nr_signals = 3, 350 .signal = (const struct etnaviv_pm_signal[]) { 351 { 352 "TOTAL_READ_REQ_8B_FROM_PIPELINE", 353 VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_PIPELINE, 354 &perf_reg_read 355 }, 356 { 357 "TOTAL_READ_REQ_8B_FROM_IP", 358 VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_READ_REQ_8B_FROM_IP, 359 &perf_reg_read 360 }, 361 { 362 "TOTAL_WRITE_REQ_8B_FROM_PIPELINE", 363 VIVS_MC_PROFILE_CONFIG2_MC_TOTAL_WRITE_REQ_8B_FROM_PIPELINE, 364 &perf_reg_read 365 } 366 } 367 } 368 }; 369 370 static const struct etnaviv_pm_domain doms_2d[] = { 371 { 372 .name = "PE", 373 .profile_read = VIVS_MC_PROFILE_PE_READ, 374 .profile_config = VIVS_MC_PROFILE_CONFIG0, 375 .nr_signals = 1, 376 .signal = (const struct etnaviv_pm_signal[]) { 377 { 378 "PIXELS_RENDERED_2D", 379 VIVS_MC_PROFILE_CONFIG0_PE_PIXELS_RENDERED_2D, 380 &pipe_reg_read 381 } 382 } 383 } 384 }; 385 386 static const struct etnaviv_pm_domain doms_vg[] = { 387 }; 388 389 static const struct etnaviv_pm_domain_meta doms_meta[] = { 390 { 391 .nr_domains = ARRAY_SIZE(doms_3d), 392 .domains = &doms_3d[0] 393 }, 394 { 395 .nr_domains = ARRAY_SIZE(doms_2d), 396 .domains = &doms_2d[0] 397 }, 398 { 399 .nr_domains = ARRAY_SIZE(doms_vg), 400 .domains = &doms_vg[0] 401 } 402 }; 403 404 int etnaviv_pm_query_dom(struct etnaviv_gpu *gpu, 405 struct drm_etnaviv_pm_domain *domain) 406 { 407 const struct etnaviv_pm_domain_meta *meta = &doms_meta[domain->pipe]; 408 const struct etnaviv_pm_domain *dom; 409 410 if (domain->iter >= meta->nr_domains) 411 return -EINVAL; 412 413 dom = meta->domains + domain->iter; 414 415 domain->id = domain->iter; 416 domain->nr_signals = dom->nr_signals; 417 strncpy(domain->name, dom->name, sizeof(domain->name)); 418 419 domain->iter++; 420 if (domain->iter == meta->nr_domains) 421 domain->iter = 0xff; 422 423 return 0; 424 } 425 426 int etnaviv_pm_query_sig(struct etnaviv_gpu *gpu, 427 struct drm_etnaviv_pm_signal *signal) 428 { 429 const struct etnaviv_pm_domain_meta *meta = &doms_meta[signal->pipe]; 430 const struct etnaviv_pm_domain *dom; 431 const struct etnaviv_pm_signal *sig; 432 433 if (signal->domain >= meta->nr_domains) 434 return -EINVAL; 435 436 dom = meta->domains + signal->domain; 437 438 if (signal->iter > dom->nr_signals) 439 return -EINVAL; 440 441 sig = &dom->signal[signal->iter]; 442 443 signal->id = signal->iter; 444 strncpy(signal->name, sig->name, sizeof(signal->name)); 445 446 signal->iter++; 447 if (signal->iter == dom->nr_signals) 448 signal->iter = 0xffff; 449 450 return 0; 451 } 452 453 int etnaviv_pm_req_validate(const struct drm_etnaviv_gem_submit_pmr *r, 454 u32 exec_state) 455 { 456 const struct etnaviv_pm_domain_meta *meta = &doms_meta[exec_state]; 457 const struct etnaviv_pm_domain *dom; 458 459 if (r->domain >= meta->nr_domains) 460 return -EINVAL; 461 462 dom = meta->domains + r->domain; 463 464 if (r->signal > dom->nr_signals) 465 return -EINVAL; 466 467 return 0; 468 } 469 470 void etnaviv_perfmon_process(struct etnaviv_gpu *gpu, 471 const struct etnaviv_perfmon_request *pmr, u32 exec_state) 472 { 473 const struct etnaviv_pm_domain_meta *meta = &doms_meta[exec_state]; 474 const struct etnaviv_pm_domain *dom; 475 const struct etnaviv_pm_signal *sig; 476 u32 *bo = pmr->bo_vma; 477 u32 val; 478 479 dom = meta->domains + pmr->domain; 480 sig = &dom->signal[pmr->signal]; 481 val = sig->sample(gpu, dom, sig); 482 483 *(bo + pmr->offset) = val; 484 } 485