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