linux/drivers/gpu/drm/i915/intel_device_info.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2016 Intel Corporation
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21 * IN THE SOFTWARE.
  22 *
  23 */
  24
  25#include "i915_drv.h"
  26
  27#define PLATFORM_NAME(x) [INTEL_##x] = #x
  28static const char * const platform_names[] = {
  29        PLATFORM_NAME(I830),
  30        PLATFORM_NAME(I845G),
  31        PLATFORM_NAME(I85X),
  32        PLATFORM_NAME(I865G),
  33        PLATFORM_NAME(I915G),
  34        PLATFORM_NAME(I915GM),
  35        PLATFORM_NAME(I945G),
  36        PLATFORM_NAME(I945GM),
  37        PLATFORM_NAME(G33),
  38        PLATFORM_NAME(PINEVIEW),
  39        PLATFORM_NAME(I965G),
  40        PLATFORM_NAME(I965GM),
  41        PLATFORM_NAME(G45),
  42        PLATFORM_NAME(GM45),
  43        PLATFORM_NAME(IRONLAKE),
  44        PLATFORM_NAME(SANDYBRIDGE),
  45        PLATFORM_NAME(IVYBRIDGE),
  46        PLATFORM_NAME(VALLEYVIEW),
  47        PLATFORM_NAME(HASWELL),
  48        PLATFORM_NAME(BROADWELL),
  49        PLATFORM_NAME(CHERRYVIEW),
  50        PLATFORM_NAME(SKYLAKE),
  51        PLATFORM_NAME(BROXTON),
  52        PLATFORM_NAME(KABYLAKE),
  53        PLATFORM_NAME(GEMINILAKE),
  54        PLATFORM_NAME(COFFEELAKE),
  55        PLATFORM_NAME(CANNONLAKE),
  56};
  57#undef PLATFORM_NAME
  58
  59const char *intel_platform_name(enum intel_platform platform)
  60{
  61        BUILD_BUG_ON(ARRAY_SIZE(platform_names) != INTEL_MAX_PLATFORMS);
  62
  63        if (WARN_ON_ONCE(platform >= ARRAY_SIZE(platform_names) ||
  64                         platform_names[platform] == NULL))
  65                return "<unknown>";
  66
  67        return platform_names[platform];
  68}
  69
  70void intel_device_info_dump(struct drm_i915_private *dev_priv)
  71{
  72        const struct intel_device_info *info = &dev_priv->info;
  73
  74        DRM_DEBUG_DRIVER("i915 device info: platform=%s gen=%i pciid=0x%04x rev=0x%02x",
  75                         intel_platform_name(info->platform),
  76                         info->gen,
  77                         dev_priv->drm.pdev->device,
  78                         dev_priv->drm.pdev->revision);
  79#define PRINT_FLAG(name) \
  80        DRM_DEBUG_DRIVER("i915 device info: " #name ": %s", yesno(info->name))
  81        DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG);
  82#undef PRINT_FLAG
  83}
  84
  85static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv)
  86{
  87        struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
  88        u32 fuse, eu_dis;
  89
  90        fuse = I915_READ(CHV_FUSE_GT);
  91
  92        sseu->slice_mask = BIT(0);
  93
  94        if (!(fuse & CHV_FGT_DISABLE_SS0)) {
  95                sseu->subslice_mask |= BIT(0);
  96                eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
  97                                 CHV_FGT_EU_DIS_SS0_R1_MASK);
  98                sseu->eu_total += 8 - hweight32(eu_dis);
  99        }
 100
 101        if (!(fuse & CHV_FGT_DISABLE_SS1)) {
 102                sseu->subslice_mask |= BIT(1);
 103                eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK |
 104                                 CHV_FGT_EU_DIS_SS1_R1_MASK);
 105                sseu->eu_total += 8 - hweight32(eu_dis);
 106        }
 107
 108        /*
 109         * CHV expected to always have a uniform distribution of EU
 110         * across subslices.
 111        */
 112        sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
 113                                sseu->eu_total / sseu_subslice_total(sseu) :
 114                                0;
 115        /*
 116         * CHV supports subslice power gating on devices with more than
 117         * one subslice, and supports EU power gating on devices with
 118         * more than one EU pair per subslice.
 119        */
 120        sseu->has_slice_pg = 0;
 121        sseu->has_subslice_pg = sseu_subslice_total(sseu) > 1;
 122        sseu->has_eu_pg = (sseu->eu_per_subslice > 2);
 123}
 124
 125static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
 126{
 127        struct intel_device_info *info = mkwrite_device_info(dev_priv);
 128        struct sseu_dev_info *sseu = &info->sseu;
 129        int s_max = 3, ss_max = 4, eu_max = 8;
 130        int s, ss;
 131        u32 fuse2, eu_disable;
 132        u8 eu_mask = 0xff;
 133
 134        fuse2 = I915_READ(GEN8_FUSE2);
 135        sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
 136
 137        /*
 138         * The subslice disable field is global, i.e. it applies
 139         * to each of the enabled slices.
 140        */
 141        sseu->subslice_mask = (1 << ss_max) - 1;
 142        sseu->subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
 143                                 GEN9_F2_SS_DIS_SHIFT);
 144
 145        /*
 146         * Iterate through enabled slices and subslices to
 147         * count the total enabled EU.
 148        */
 149        for (s = 0; s < s_max; s++) {
 150                if (!(sseu->slice_mask & BIT(s)))
 151                        /* skip disabled slice */
 152                        continue;
 153
 154                eu_disable = I915_READ(GEN9_EU_DISABLE(s));
 155                for (ss = 0; ss < ss_max; ss++) {
 156                        int eu_per_ss;
 157
 158                        if (!(sseu->subslice_mask & BIT(ss)))
 159                                /* skip disabled subslice */
 160                                continue;
 161
 162                        eu_per_ss = eu_max - hweight8((eu_disable >> (ss*8)) &
 163                                                      eu_mask);
 164
 165                        /*
 166                         * Record which subslice(s) has(have) 7 EUs. we
 167                         * can tune the hash used to spread work among
 168                         * subslices if they are unbalanced.
 169                         */
 170                        if (eu_per_ss == 7)
 171                                sseu->subslice_7eu[s] |= BIT(ss);
 172
 173                        sseu->eu_total += eu_per_ss;
 174                }
 175        }
 176
 177        /*
 178         * SKL is expected to always have a uniform distribution
 179         * of EU across subslices with the exception that any one
 180         * EU in any one subslice may be fused off for die
 181         * recovery. BXT is expected to be perfectly uniform in EU
 182         * distribution.
 183        */
 184        sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
 185                                DIV_ROUND_UP(sseu->eu_total,
 186                                             sseu_subslice_total(sseu)) : 0;
 187        /*
 188         * SKL+ supports slice power gating on devices with more than
 189         * one slice, and supports EU power gating on devices with
 190         * more than one EU pair per subslice. BXT+ supports subslice
 191         * power gating on devices with more than one subslice, and
 192         * supports EU power gating on devices with more than one EU
 193         * pair per subslice.
 194        */
 195        sseu->has_slice_pg =
 196                !IS_GEN9_LP(dev_priv) && hweight8(sseu->slice_mask) > 1;
 197        sseu->has_subslice_pg =
 198                IS_GEN9_LP(dev_priv) && sseu_subslice_total(sseu) > 1;
 199        sseu->has_eu_pg = sseu->eu_per_subslice > 2;
 200
 201        if (IS_GEN9_LP(dev_priv)) {
 202#define IS_SS_DISABLED(ss)      (!(sseu->subslice_mask & BIT(ss)))
 203                info->has_pooled_eu = hweight8(sseu->subslice_mask) == 3;
 204
 205                /*
 206                 * There is a HW issue in 2x6 fused down parts that requires
 207                 * Pooled EU to be enabled as a WA. The pool configuration
 208                 * changes depending upon which subslice is fused down. This
 209                 * doesn't affect if the device has all 3 subslices enabled.
 210                 */
 211                /* WaEnablePooledEuFor2x6:bxt */
 212                info->has_pooled_eu |= (hweight8(sseu->subslice_mask) == 2 &&
 213                                        IS_BXT_REVID(dev_priv, 0, BXT_REVID_B_LAST));
 214
 215                sseu->min_eu_in_pool = 0;
 216                if (info->has_pooled_eu) {
 217                        if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))
 218                                sseu->min_eu_in_pool = 3;
 219                        else if (IS_SS_DISABLED(1))
 220                                sseu->min_eu_in_pool = 6;
 221                        else
 222                                sseu->min_eu_in_pool = 9;
 223                }
 224#undef IS_SS_DISABLED
 225        }
 226}
 227
 228static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
 229{
 230        struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
 231        const int s_max = 3, ss_max = 3, eu_max = 8;
 232        int s, ss;
 233        u32 fuse2, eu_disable[3]; /* s_max */
 234
 235        fuse2 = I915_READ(GEN8_FUSE2);
 236        sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
 237        /*
 238         * The subslice disable field is global, i.e. it applies
 239         * to each of the enabled slices.
 240         */
 241        sseu->subslice_mask = GENMASK(ss_max - 1, 0);
 242        sseu->subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
 243                                 GEN8_F2_SS_DIS_SHIFT);
 244
 245        eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK;
 246        eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) |
 247                        ((I915_READ(GEN8_EU_DISABLE1) & GEN8_EU_DIS1_S1_MASK) <<
 248                         (32 - GEN8_EU_DIS0_S1_SHIFT));
 249        eu_disable[2] = (I915_READ(GEN8_EU_DISABLE1) >> GEN8_EU_DIS1_S2_SHIFT) |
 250                        ((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) <<
 251                         (32 - GEN8_EU_DIS1_S2_SHIFT));
 252
 253        /*
 254         * Iterate through enabled slices and subslices to
 255         * count the total enabled EU.
 256         */
 257        for (s = 0; s < s_max; s++) {
 258                if (!(sseu->slice_mask & BIT(s)))
 259                        /* skip disabled slice */
 260                        continue;
 261
 262                for (ss = 0; ss < ss_max; ss++) {
 263                        u32 n_disabled;
 264
 265                        if (!(sseu->subslice_mask & BIT(ss)))
 266                                /* skip disabled subslice */
 267                                continue;
 268
 269                        n_disabled = hweight8(eu_disable[s] >> (ss * eu_max));
 270
 271                        /*
 272                         * Record which subslices have 7 EUs.
 273                         */
 274                        if (eu_max - n_disabled == 7)
 275                                sseu->subslice_7eu[s] |= 1 << ss;
 276
 277                        sseu->eu_total += eu_max - n_disabled;
 278                }
 279        }
 280
 281        /*
 282         * BDW is expected to always have a uniform distribution of EU across
 283         * subslices with the exception that any one EU in any one subslice may
 284         * be fused off for die recovery.
 285         */
 286        sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
 287                                DIV_ROUND_UP(sseu->eu_total,
 288                                             sseu_subslice_total(sseu)) : 0;
 289
 290        /*
 291         * BDW supports slice power gating on devices with more than
 292         * one slice.
 293         */
 294        sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;
 295        sseu->has_subslice_pg = 0;
 296        sseu->has_eu_pg = 0;
 297}
 298
 299/*
 300 * Determine various intel_device_info fields at runtime.
 301 *
 302 * Use it when either:
 303 *   - it's judged too laborious to fill n static structures with the limit
 304 *     when a simple if statement does the job,
 305 *   - run-time checks (eg read fuse/strap registers) are needed.
 306 *
 307 * This function needs to be called:
 308 *   - after the MMIO has been setup as we are reading registers,
 309 *   - after the PCH has been detected,
 310 *   - before the first usage of the fields it can tweak.
 311 */
 312void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
 313{
 314        struct intel_device_info *info = mkwrite_device_info(dev_priv);
 315        enum pipe pipe;
 316
 317        if (INTEL_GEN(dev_priv) >= 9) {
 318                info->num_scalers[PIPE_A] = 2;
 319                info->num_scalers[PIPE_B] = 2;
 320                info->num_scalers[PIPE_C] = 1;
 321        }
 322
 323        /*
 324         * Skylake and Broxton currently don't expose the topmost plane as its
 325         * use is exclusive with the legacy cursor and we only want to expose
 326         * one of those, not both. Until we can safely expose the topmost plane
 327         * as a DRM_PLANE_TYPE_CURSOR with all the features exposed/supported,
 328         * we don't expose the topmost plane at all to prevent ABI breakage
 329         * down the line.
 330         */
 331        if (IS_GEN10(dev_priv) || IS_GEMINILAKE(dev_priv))
 332                for_each_pipe(dev_priv, pipe)
 333                        info->num_sprites[pipe] = 3;
 334        else if (IS_BROXTON(dev_priv)) {
 335                info->num_sprites[PIPE_A] = 2;
 336                info->num_sprites[PIPE_B] = 2;
 337                info->num_sprites[PIPE_C] = 1;
 338        } else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
 339                for_each_pipe(dev_priv, pipe)
 340                        info->num_sprites[pipe] = 2;
 341        } else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv)) {
 342                for_each_pipe(dev_priv, pipe)
 343                        info->num_sprites[pipe] = 1;
 344        }
 345
 346        if (i915.disable_display) {
 347                DRM_INFO("Display disabled (module parameter)\n");
 348                info->num_pipes = 0;
 349        } else if (info->num_pipes > 0 &&
 350                   (IS_GEN7(dev_priv) || IS_GEN8(dev_priv)) &&
 351                   HAS_PCH_SPLIT(dev_priv)) {
 352                u32 fuse_strap = I915_READ(FUSE_STRAP);
 353                u32 sfuse_strap = I915_READ(SFUSE_STRAP);
 354
 355                /*
 356                 * SFUSE_STRAP is supposed to have a bit signalling the display
 357                 * is fused off. Unfortunately it seems that, at least in
 358                 * certain cases, fused off display means that PCH display
 359                 * reads don't land anywhere. In that case, we read 0s.
 360                 *
 361                 * On CPT/PPT, we can detect this case as SFUSE_STRAP_FUSE_LOCK
 362                 * should be set when taking over after the firmware.
 363                 */
 364                if (fuse_strap & ILK_INTERNAL_DISPLAY_DISABLE ||
 365                    sfuse_strap & SFUSE_STRAP_DISPLAY_DISABLED ||
 366                    (HAS_PCH_CPT(dev_priv) &&
 367                     !(sfuse_strap & SFUSE_STRAP_FUSE_LOCK))) {
 368                        DRM_INFO("Display fused off, disabling\n");
 369                        info->num_pipes = 0;
 370                } else if (fuse_strap & IVB_PIPE_C_DISABLE) {
 371                        DRM_INFO("PipeC fused off\n");
 372                        info->num_pipes -= 1;
 373                }
 374        } else if (info->num_pipes > 0 && IS_GEN9(dev_priv)) {
 375                u32 dfsm = I915_READ(SKL_DFSM);
 376                u8 disabled_mask = 0;
 377                bool invalid;
 378                int num_bits;
 379
 380                if (dfsm & SKL_DFSM_PIPE_A_DISABLE)
 381                        disabled_mask |= BIT(PIPE_A);
 382                if (dfsm & SKL_DFSM_PIPE_B_DISABLE)
 383                        disabled_mask |= BIT(PIPE_B);
 384                if (dfsm & SKL_DFSM_PIPE_C_DISABLE)
 385                        disabled_mask |= BIT(PIPE_C);
 386
 387                num_bits = hweight8(disabled_mask);
 388
 389                switch (disabled_mask) {
 390                case BIT(PIPE_A):
 391                case BIT(PIPE_B):
 392                case BIT(PIPE_A) | BIT(PIPE_B):
 393                case BIT(PIPE_A) | BIT(PIPE_C):
 394                        invalid = true;
 395                        break;
 396                default:
 397                        invalid = false;
 398                }
 399
 400                if (num_bits > info->num_pipes || invalid)
 401                        DRM_ERROR("invalid pipe fuse configuration: 0x%x\n",
 402                                  disabled_mask);
 403                else
 404                        info->num_pipes -= num_bits;
 405        }
 406
 407        /* Initialize slice/subslice/EU info */
 408        if (IS_CHERRYVIEW(dev_priv))
 409                cherryview_sseu_info_init(dev_priv);
 410        else if (IS_BROADWELL(dev_priv))
 411                broadwell_sseu_info_init(dev_priv);
 412        else if (INTEL_INFO(dev_priv)->gen >= 9)
 413                gen9_sseu_info_init(dev_priv);
 414
 415        info->has_snoop = !info->has_llc;
 416
 417        DRM_DEBUG_DRIVER("slice mask: %04x\n", info->sseu.slice_mask);
 418        DRM_DEBUG_DRIVER("slice total: %u\n", hweight8(info->sseu.slice_mask));
 419        DRM_DEBUG_DRIVER("subslice total: %u\n",
 420                         sseu_subslice_total(&info->sseu));
 421        DRM_DEBUG_DRIVER("subslice mask %04x\n", info->sseu.subslice_mask);
 422        DRM_DEBUG_DRIVER("subslice per slice: %u\n",
 423                         hweight8(info->sseu.subslice_mask));
 424        DRM_DEBUG_DRIVER("EU total: %u\n", info->sseu.eu_total);
 425        DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->sseu.eu_per_subslice);
 426        DRM_DEBUG_DRIVER("has slice power gating: %s\n",
 427                         info->sseu.has_slice_pg ? "y" : "n");
 428        DRM_DEBUG_DRIVER("has subslice power gating: %s\n",
 429                         info->sseu.has_subslice_pg ? "y" : "n");
 430        DRM_DEBUG_DRIVER("has EU power gating: %s\n",
 431                         info->sseu.has_eu_pg ? "y" : "n");
 432}
 433