]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - tools/power/x86/turbostat/turbostat.c
tools/power turbostat: initial BXT support
[mirror_ubuntu-artful-kernel.git] / tools / power / x86 / turbostat / turbostat.c
index c6793268d81fb6a0e5a097a70215d5012f2e445a..96d8eafdd38083151d8c4e167229800490a81316 100644 (file)
@@ -66,6 +66,8 @@ unsigned int do_slm_cstates;
 unsigned int use_c1_residency_msr;
 unsigned int has_aperf;
 unsigned int has_epb;
+unsigned int do_irtl_snb;
+unsigned int do_irtl_hsw;
 unsigned int units = 1000000;  /* MHz etc */
 unsigned int genuine_intel;
 unsigned int has_invariant_tsc;
@@ -90,6 +92,10 @@ char *output_buffer, *outp;
 unsigned int do_rapl;
 unsigned int do_dts;
 unsigned int do_ptm;
+unsigned int do_gfx_rc6_ms;
+unsigned long long  gfx_cur_rc6_ms;
+unsigned int do_gfx_mhz;
+unsigned int gfx_cur_mhz;
 unsigned int tcc_activation_temp;
 unsigned int tcc_activation_temp_override;
 double rapl_power_units, rapl_time_units;
@@ -183,6 +189,8 @@ struct pkg_data {
        unsigned long long pkg_any_core_c0;
        unsigned long long pkg_any_gfxe_c0;
        unsigned long long pkg_both_core_gfxe_c0;
+       unsigned long long gfx_rc6_ms;
+       unsigned int gfx_mhz;
        unsigned int package_id;
        unsigned int energy_pkg;        /* MSR_PKG_ENERGY_STATUS */
        unsigned int energy_dram;       /* MSR_DRAM_ENERGY_STATUS */
@@ -311,7 +319,7 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
 /*
  * Example Format w/ field column widths:
  *
- *  Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     IRQ   SMI   Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
+ *  Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     IRQ   SMI   Busy% CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp  PkgTmp  GFXMHz Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
  * 12345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
  */
 
@@ -362,6 +370,12 @@ void print_header(void)
        if (do_ptm)
                outp += sprintf(outp, "  PkgTmp");
 
+       if (do_gfx_rc6_ms)
+               outp += sprintf(outp, " GFX%%rc6");
+
+       if (do_gfx_mhz)
+               outp += sprintf(outp, "  GFXMHz");
+
        if (do_skl_residency) {
                outp += sprintf(outp, " Totl%%C0");
                outp += sprintf(outp, "  Any%%C0");
@@ -608,6 +622,14 @@ int format_counters(struct thread_data *t, struct core_data *c,
        if (do_ptm)
                outp += sprintf(outp, "%8d", p->pkg_temp_c);
 
+       /* GFXrc6 */
+       if (do_gfx_rc6_ms)
+               outp += sprintf(outp, "%8.2f", 100.0 * p->gfx_rc6_ms / 1000.0 / interval_float);
+
+       /* GFXMHz */
+       if (do_gfx_mhz)
+               outp += sprintf(outp, "%8d", p->gfx_mhz);
+
        /* Totl%C0, Any%C0 GFX%C0 CPUGFX% */
        if (do_skl_residency) {
                outp += sprintf(outp, "%8.2f", 100.0 * p->pkg_wtd_core_c0/t->tsc);
@@ -746,6 +768,9 @@ delta_package(struct pkg_data *new, struct pkg_data *old)
        old->pc10 = new->pc10 - old->pc10;
        old->pkg_temp_c = new->pkg_temp_c;
 
+       old->gfx_rc6_ms = new->gfx_rc6_ms - old->gfx_rc6_ms;
+       old->gfx_mhz = new->gfx_mhz;
+
        DELTA_WRAP32(new->energy_pkg, old->energy_pkg);
        DELTA_WRAP32(new->energy_cores, old->energy_cores);
        DELTA_WRAP32(new->energy_gfx, old->energy_gfx);
@@ -909,6 +934,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
        p->rapl_pkg_perf_status = 0;
        p->rapl_dram_perf_status = 0;
        p->pkg_temp_c = 0;
+
+       p->gfx_rc6_ms = 0;
+       p->gfx_mhz = 0;
 }
 int sum_counters(struct thread_data *t, struct core_data *c,
        struct pkg_data *p)
@@ -961,6 +989,9 @@ int sum_counters(struct thread_data *t, struct core_data *c,
        average.packages.energy_cores += p->energy_cores;
        average.packages.energy_gfx += p->energy_gfx;
 
+       average.packages.gfx_rc6_ms = p->gfx_rc6_ms;
+       average.packages.gfx_mhz = p->gfx_mhz;
+
        average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c);
 
        average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status;
@@ -1030,19 +1061,68 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 {
        int cpu = t->cpu_id;
        unsigned long long msr;
+       int aperf_mperf_retry_count = 0;
 
        if (cpu_migrate(cpu)) {
                fprintf(outf, "Could not migrate to CPU %d\n", cpu);
                return -1;
        }
 
+retry:
        t->tsc = rdtsc();       /* we are running on local CPU of interest */
 
        if (has_aperf) {
+               unsigned long long tsc_before, tsc_between, tsc_after, aperf_time, mperf_time;
+
+               /*
+                * The TSC, APERF and MPERF must be read together for
+                * APERF/MPERF and MPERF/TSC to give accurate results.
+                *
+                * Unfortunately, APERF and MPERF are read by
+                * individual system call, so delays may occur
+                * between them.  If the time to read them
+                * varies by a large amount, we re-read them.
+                */
+
+               /*
+                * This initial dummy APERF read has been seen to
+                * reduce jitter in the subsequent reads.
+                */
+
+               if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
+                       return -3;
+
+               t->tsc = rdtsc();       /* re-read close to APERF */
+
+               tsc_before = t->tsc;
+
                if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
                        return -3;
+
+               tsc_between = rdtsc();
+
                if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
                        return -4;
+
+               tsc_after = rdtsc();
+
+               aperf_time = tsc_between - tsc_before;
+               mperf_time = tsc_after - tsc_between;
+
+               /*
+                * If the system call latency to read APERF and MPERF
+                * differ by more than 2x, then try again.
+                */
+               if ((aperf_time > (2 * mperf_time)) || (mperf_time > (2 * aperf_time))) {
+                       aperf_mperf_retry_count++;
+                       if (aperf_mperf_retry_count < 5)
+                               goto retry;
+                       else
+                               warnx("cpu%d jitter %lld %lld",
+                                       cpu, aperf_time, mperf_time);
+               }
+               aperf_mperf_retry_count = 0;
+
                t->aperf = t->aperf * aperf_mperf_multiplier;
                t->mperf = t->mperf * aperf_mperf_multiplier;
        }
@@ -1176,6 +1256,13 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                        return -17;
                p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
        }
+
+       if (do_gfx_rc6_ms)
+               p->gfx_rc6_ms = gfx_cur_rc6_ms;
+
+       if (do_gfx_mhz)
+               p->gfx_mhz = gfx_cur_mhz;
+
        return 0;
 }
 
@@ -1211,6 +1298,7 @@ int hsw_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL__3, PCL__6, PCL__7, PCL_7S,
 int slv_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCLRSV, PCLRSV, PCL__4, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int amt_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCL__2, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int phi_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
+int bxt_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 
 
 static void
@@ -1447,7 +1535,7 @@ dump_nhm_cst_cfg(void)
                (msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "",
                (msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "",
                (msr & (1 << 15)) ? "" : "UN",
-               (unsigned int)msr & 7,
+               (unsigned int)msr & 0xF,
                pkg_cstate_limit_strings[pkg_cstate_limit]);
        return;
 }
@@ -1459,25 +1547,25 @@ dump_config_tdp(void)
 
        get_msr(base_cpu, MSR_CONFIG_TDP_NOMINAL, &msr);
        fprintf(outf, "cpu%d: MSR_CONFIG_TDP_NOMINAL: 0x%08llx", base_cpu, msr);
-       fprintf(outf, " (base_ratio=%d)\n", (unsigned int)msr & 0xEF);
+       fprintf(outf, " (base_ratio=%d)\n", (unsigned int)msr & 0xFF);
 
        get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_1, &msr);
        fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_1: 0x%08llx (", base_cpu, msr);
        if (msr) {
-               fprintf(outf, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0xEFFF);
-               fprintf(outf, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0xEFFF);
-               fprintf(outf, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF);
-               fprintf(outf, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0xEFFF);
+               fprintf(outf, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0x7FFF);
+               fprintf(outf, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0x7FFF);
+               fprintf(outf, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF);
+               fprintf(outf, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0x7FFF);
        }
        fprintf(outf, ")\n");
 
        get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_2, &msr);
        fprintf(outf, "cpu%d: MSR_CONFIG_TDP_LEVEL_2: 0x%08llx (", base_cpu, msr);
        if (msr) {
-               fprintf(outf, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0xEFFF);
-               fprintf(outf, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0xEFFF);
-               fprintf(outf, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF);
-               fprintf(outf, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0xEFFF);
+               fprintf(outf, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0x7FFF);
+               fprintf(outf, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0x7FFF);
+               fprintf(outf, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xFF);
+               fprintf(outf, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0x7FFF);
        }
        fprintf(outf, ")\n");
 
@@ -1490,10 +1578,51 @@ dump_config_tdp(void)
 
        get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr);
        fprintf(outf, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr);
-       fprintf(outf, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0x7F);
+       fprintf(outf, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0xFF);
        fprintf(outf, " lock=%d", (unsigned int)(msr >> 31) & 1);
        fprintf(outf, ")\n");
 }
+
+unsigned int irtl_time_units[] = {1, 32, 1024, 32768, 1048576, 33554432, 0, 0 };
+
+void print_irtl(void)
+{
+       unsigned long long msr;
+
+       get_msr(base_cpu, MSR_PKGC3_IRTL, &msr);
+       fprintf(outf, "cpu%d: MSR_PKGC3_IRTL: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
+               (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
+
+       get_msr(base_cpu, MSR_PKGC6_IRTL, &msr);
+       fprintf(outf, "cpu%d: MSR_PKGC6_IRTL: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
+               (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
+
+       get_msr(base_cpu, MSR_PKGC7_IRTL, &msr);
+       fprintf(outf, "cpu%d: MSR_PKGC7_IRTL: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
+               (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
+
+       if (!do_irtl_hsw)
+               return;
+
+       get_msr(base_cpu, MSR_PKGC8_IRTL, &msr);
+       fprintf(outf, "cpu%d: MSR_PKGC8_IRTL: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
+               (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
+
+       get_msr(base_cpu, MSR_PKGC9_IRTL, &msr);
+       fprintf(outf, "cpu%d: MSR_PKGC9_IRTL: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
+               (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
+
+       get_msr(base_cpu, MSR_PKGC10_IRTL, &msr);
+       fprintf(outf, "cpu%d: MSR_PKGC10_IRTL: 0x%08llx (", base_cpu, msr);
+       fprintf(outf, "%svalid, %lld ns)\n", msr & (1 << 15) ? "" : "NOT",
+               (msr & 0x3FF) * irtl_time_units[(msr >> 10) & 0x3]);
+
+}
 void free_fd_percpu(void)
 {
        int i;
@@ -1825,6 +1954,53 @@ int snapshot_proc_interrupts(void)
        }
        return 0;
 }
+/*
+ * snapshot_gfx_rc6_ms()
+ *
+ * record snapshot of
+ * /sys/class/drm/card0/power/rc6_residency_ms
+ *
+ * return 1 if config change requires a restart, else return 0
+ */
+int snapshot_gfx_rc6_ms(void)
+{
+       FILE *fp;
+       int retval;
+
+       fp = fopen_or_die("/sys/class/drm/card0/power/rc6_residency_ms", "r");
+
+       retval = fscanf(fp, "%lld", &gfx_cur_rc6_ms);
+       if (retval != 1)
+               err(1, "GFX rc6");
+
+       fclose(fp);
+
+       return 0;
+}
+/*
+ * snapshot_gfx_mhz()
+ *
+ * record snapshot of
+ * /sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz
+ *
+ * return 1 if config change requires a restart, else return 0
+ */
+int snapshot_gfx_mhz(void)
+{
+       static FILE *fp;
+       int retval;
+
+       if (fp == NULL)
+               fp = fopen_or_die("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", "r");
+       else
+               rewind(fp);
+
+       retval = fscanf(fp, "%d", &gfx_cur_mhz);
+       if (retval != 1)
+               err(1, "GFX MHz");
+
+       return 0;
+}
 
 /*
  * snapshot /proc and /sys files
@@ -1836,6 +2012,12 @@ int snapshot_proc_sysfs_files(void)
        if (snapshot_proc_interrupts())
                return 1;
 
+       if (do_gfx_rc6_ms)
+               snapshot_gfx_rc6_ms();
+
+       if (do_gfx_mhz)
+               snapshot_gfx_mhz();
+
        return 0;
 }
 
@@ -2018,6 +2200,9 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
        case 0x57:      /* PHI */
                pkg_cstate_limits = phi_pkg_cstate_limits;
                break;
+       case 0x5C:      /* BXT */
+               pkg_cstate_limits = bxt_pkg_cstate_limits;
+               break;
        default:
                return 0;
        }
@@ -2447,6 +2632,9 @@ void rapl_probe(unsigned int family, unsigned int model)
        case 0x47:      /* BDW */
                do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO;
                break;
+       case 0x5C:      /* BXT */
+               do_rapl = RAPL_PKG | RAPL_PKG_POWER_INFO;
+               break;
        case 0x4E:      /* SKL */
        case 0x5E:      /* SKL */
                do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO;
@@ -2733,6 +2921,7 @@ int has_snb_msrs(unsigned int family, unsigned int model)
        case 0x56:      /* BDX-DE */
        case 0x4E:      /* SKL */
        case 0x5E:      /* SKL */
+       case 0x5C:      /* BXT */
                return 1;
        }
        return 0;
@@ -2741,9 +2930,14 @@ int has_snb_msrs(unsigned int family, unsigned int model)
 /*
  * HSW adds support for additional MSRs:
  *
- * MSR_PKG_C8_RESIDENCY            0x00000630
- * MSR_PKG_C9_RESIDENCY            0x00000631
- * MSR_PKG_C10_RESIDENCY           0x00000632
+ * MSR_PKG_C8_RESIDENCY                0x00000630
+ * MSR_PKG_C9_RESIDENCY                0x00000631
+ * MSR_PKG_C10_RESIDENCY       0x00000632
+ *
+ * MSR_PKGC8_IRTL              0x00000633
+ * MSR_PKGC9_IRTL              0x00000634
+ * MSR_PKGC10_IRTL             0x00000635
+ *
  */
 int has_hsw_msrs(unsigned int family, unsigned int model)
 {
@@ -2755,6 +2949,7 @@ int has_hsw_msrs(unsigned int family, unsigned int model)
        case 0x3D:      /* BDW */
        case 0x4E:      /* SKL */
        case 0x5E:      /* SKL */
+       case 0x5C:      /* BXT */
                return 1;
        }
        return 0;
@@ -2914,6 +3109,17 @@ guess:
        return 0;
 }
 
+void decode_feature_control_msr(void)
+{
+       unsigned long long msr;
+
+       if (!get_msr(base_cpu, MSR_IA32_FEATURE_CONTROL, &msr))
+               fprintf(outf, "cpu%d: MSR_IA32_FEATURE_CONTROL: 0x%08llx (%sLocked %s)\n",
+                       base_cpu, msr,
+                       msr & FEATURE_CONTROL_LOCKED ? "" : "UN-",
+                       msr & (1 << 18) ? "SGX" : "");
+}
+
 void decode_misc_enable_msr(void)
 {
        unsigned long long msr;
@@ -2954,7 +3160,7 @@ void process_cpuid()
 
        eax = ebx = ecx = edx = 0;
 
-       __get_cpuid(0, &max_level, &ebx, &ecx, &edx);
+       __cpuid(0, max_level, ebx, ecx, edx);
 
        if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
                genuine_intel = 1;
@@ -2963,7 +3169,7 @@ void process_cpuid()
                fprintf(outf, "CPUID(0): %.4s%.4s%.4s ",
                        (char *)&ebx, (char *)&edx, (char *)&ecx);
 
-       __get_cpuid(1, &fms, &ebx, &ecx, &edx);
+       __cpuid(1, fms, ebx, ecx, edx);
        family = (fms >> 8) & 0xf;
        model = (fms >> 4) & 0xf;
        stepping = fms & 0xf;
@@ -2973,9 +3179,10 @@ void process_cpuid()
        if (debug) {
                fprintf(outf, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
                        max_level, family, model, stepping, family, model, stepping);
-               fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s\n",
+               fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s\n",
                        ecx & (1 << 0) ? "SSE3" : "-",
                        ecx & (1 << 3) ? "MONITOR" : "-",
+                       ecx & (1 << 6) ? "SMX" : "-",
                        ecx & (1 << 7) ? "EIST" : "-",
                        ecx & (1 << 8) ? "TM2" : "-",
                        edx & (1 << 4) ? "TSC" : "-",
@@ -2993,7 +3200,7 @@ void process_cpuid()
         * This check is valid for both Intel and AMD.
         */
        ebx = ecx = edx = 0;
-       __get_cpuid(0x80000000, &max_extended_level, &ebx, &ecx, &edx);
+       __cpuid(0x80000000, max_extended_level, ebx, ecx, edx);
 
        if (max_extended_level >= 0x80000007) {
 
@@ -3001,7 +3208,7 @@ void process_cpuid()
                 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
                 * this check is valid for both Intel and AMD
                 */
-               __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
+               __cpuid(0x80000007, eax, ebx, ecx, edx);
                has_invariant_tsc = edx & (1 << 8);
        }
 
@@ -3010,7 +3217,7 @@ void process_cpuid()
         * this check is valid for both Intel and AMD
         */
 
-       __get_cpuid(0x6, &eax, &ebx, &ecx, &edx);
+       __cpuid(0x6, eax, ebx, ecx, edx);
        has_aperf = ecx & (1 << 0);
        do_dts = eax & (1 << 0);
        do_ptm = eax & (1 << 6);
@@ -3037,6 +3244,20 @@ void process_cpuid()
        if (debug)
                decode_misc_enable_msr();
 
+       if (max_level >= 0x7 && debug) {
+               int has_sgx;
+
+               ecx = 0;
+
+               __cpuid_count(0x7, 0, eax, ebx, ecx, edx);
+
+               has_sgx = ebx & (1 << 2);
+               fprintf(outf, "CPUID(7): %sSGX\n", has_sgx ? "" : "No-");
+
+               if (has_sgx)
+                       decode_feature_control_msr();
+       }
+
        if (max_level >= 0x15) {
                unsigned int eax_crystal;
                unsigned int ebx_tsc;
@@ -3045,7 +3266,7 @@ void process_cpuid()
                 * CPUID 15H TSC/Crystal ratio, possibly Crystal Hz
                 */
                eax_crystal = ebx_tsc = crystal_hz = edx = 0;
-               __get_cpuid(0x15, &eax_crystal, &ebx_tsc, &crystal_hz, &edx);
+               __cpuid(0x15, eax_crystal, ebx_tsc, crystal_hz, edx);
 
                if (ebx_tsc != 0) {
 
@@ -3079,7 +3300,7 @@ void process_cpuid()
                 */
                base_mhz = max_mhz = bus_mhz = edx = 0;
 
-               __get_cpuid(0x16, &base_mhz, &max_mhz, &bus_mhz, &edx);
+               __cpuid(0x16, base_mhz, max_mhz, bus_mhz, edx);
                if (debug)
                        fprintf(outf, "CPUID(0x16): base_mhz: %d max_mhz: %d bus_mhz: %d\n",
                                base_mhz, max_mhz, bus_mhz);
@@ -3090,11 +3311,13 @@ void process_cpuid()
 
        do_nhm_platform_info = do_nhm_cstates = do_smi = probe_nhm_msrs(family, model);
        do_snb_cstates = has_snb_msrs(family, model);
+       do_irtl_snb = has_snb_msrs(family, model);
        do_pc2 = do_snb_cstates && (pkg_cstate_limit >= PCL__2);
        do_pc3 = (pkg_cstate_limit >= PCL__3);
        do_pc6 = (pkg_cstate_limit >= PCL__6);
        do_pc7 = do_snb_cstates && (pkg_cstate_limit >= PCL__7);
        do_c8_c9_c10 = has_hsw_msrs(family, model);
+       do_irtl_hsw = has_hsw_msrs(family, model);
        do_skl_residency = has_skl_msrs(family, model);
        do_slm_cstates = is_slm(family, model);
        do_knl_cstates  = is_knl(family, model);
@@ -3111,6 +3334,10 @@ void process_cpuid()
        if (has_skl_msrs(family, model))
                calculate_tsc_tweak();
 
+       do_gfx_rc6_ms = !access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK);
+
+       do_gfx_mhz = !access("/sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz", R_OK);
+
        return;
 }
 
@@ -3396,6 +3623,9 @@ void turbostat_init()
 
        if (debug)
                for_all_cpus(print_thermal, ODD_COUNTERS);
+
+       if (debug && do_irtl_snb)
+               print_irtl();
 }
 
 int fork_it(char **argv)
@@ -3461,7 +3691,7 @@ int get_and_dump_counters(void)
 }
 
 void print_version() {
-       fprintf(outf, "turbostat version 4.10 10 Dec, 2015"
+       fprintf(outf, "turbostat version 4.11 27 Feb 2016"
                " - Len Brown <lenb@kernel.org>\n");
 }