linux/drivers/gpu/drm/etnaviv/etnaviv_perfmon.c
<<
>>
Prefs
   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
  12struct etnaviv_pm_domain;
  13
  14struct 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
  23struct 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
  34struct etnaviv_pm_domain_meta {
  35        unsigned int feature;
  36        const struct etnaviv_pm_domain *domains;
  37        u32 nr_domains;
  38};
  39
  40static 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
  49static 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
  57static 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
  76static 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
  95static 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
 109static 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
 123static 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
 425static 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
 441static const struct etnaviv_pm_domain doms_vg[] = {
 442};
 443
 444static 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
 462static 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
 476static 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
 499int 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
 523int 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
 552int 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
 569void 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