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