Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2015 Intel Corporation
0004  */
0005 
0006 #include "i915_drv.h"
0007 
0008 #include "intel_engine.h"
0009 #include "intel_gt.h"
0010 #include "intel_gt_regs.h"
0011 #include "intel_mocs.h"
0012 #include "intel_ring.h"
0013 
0014 /* structures required */
0015 struct drm_i915_mocs_entry {
0016     u32 control_value;
0017     u16 l3cc_value;
0018     u16 used;
0019 };
0020 
0021 struct drm_i915_mocs_table {
0022     unsigned int size;
0023     unsigned int n_entries;
0024     const struct drm_i915_mocs_entry *table;
0025     u8 uc_index;
0026     u8 wb_index; /* Only used on HAS_L3_CCS_READ() platforms */
0027     u8 unused_entries_index;
0028 };
0029 
0030 /* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
0031 #define _LE_CACHEABILITY(value) ((value) << 0)
0032 #define _LE_TGT_CACHE(value)    ((value) << 2)
0033 #define LE_LRUM(value)      ((value) << 4)
0034 #define LE_AOM(value)       ((value) << 6)
0035 #define LE_RSC(value)       ((value) << 7)
0036 #define LE_SCC(value)       ((value) << 8)
0037 #define LE_PFM(value)       ((value) << 11)
0038 #define LE_SCF(value)       ((value) << 14)
0039 #define LE_COS(value)       ((value) << 15)
0040 #define LE_SSE(value)       ((value) << 17)
0041 
0042 /* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
0043 #define L3_ESC(value)       ((value) << 0)
0044 #define L3_SCC(value)       ((value) << 1)
0045 #define _L3_CACHEABILITY(value) ((value) << 4)
0046 #define L3_GLBGO(value)     ((value) << 6)
0047 #define L3_LKUP(value)      ((value) << 7)
0048 
0049 /* Helper defines */
0050 #define GEN9_NUM_MOCS_ENTRIES   64  /* 63-64 are reserved, but configured. */
0051 #define PVC_NUM_MOCS_ENTRIES    3
0052 
0053 /* (e)LLC caching options */
0054 /*
0055  * Note: LE_0_PAGETABLE works only up to Gen11; for newer gens it means
0056  * the same as LE_UC
0057  */
0058 #define LE_0_PAGETABLE      _LE_CACHEABILITY(0)
0059 #define LE_1_UC         _LE_CACHEABILITY(1)
0060 #define LE_2_WT         _LE_CACHEABILITY(2)
0061 #define LE_3_WB         _LE_CACHEABILITY(3)
0062 
0063 /* Target cache */
0064 #define LE_TC_0_PAGETABLE   _LE_TGT_CACHE(0)
0065 #define LE_TC_1_LLC     _LE_TGT_CACHE(1)
0066 #define LE_TC_2_LLC_ELLC    _LE_TGT_CACHE(2)
0067 #define LE_TC_3_LLC_ELLC_ALT    _LE_TGT_CACHE(3)
0068 
0069 /* L3 caching options */
0070 #define L3_0_DIRECT     _L3_CACHEABILITY(0)
0071 #define L3_1_UC         _L3_CACHEABILITY(1)
0072 #define L3_2_RESERVED       _L3_CACHEABILITY(2)
0073 #define L3_3_WB         _L3_CACHEABILITY(3)
0074 
0075 #define MOCS_ENTRY(__idx, __control_value, __l3cc_value) \
0076     [__idx] = { \
0077         .control_value = __control_value, \
0078         .l3cc_value = __l3cc_value, \
0079         .used = 1, \
0080     }
0081 
0082 /*
0083  * MOCS tables
0084  *
0085  * These are the MOCS tables that are programmed across all the rings.
0086  * The control value is programmed to all the rings that support the
0087  * MOCS registers. While the l3cc_values are only programmed to the
0088  * LNCFCMOCS0 - LNCFCMOCS32 registers.
0089  *
0090  * These tables are intended to be kept reasonably consistent across
0091  * HW platforms, and for ICL+, be identical across OSes. To achieve
0092  * that, for Icelake and above, list of entries is published as part
0093  * of bspec.
0094  *
0095  * Entries not part of the following tables are undefined as far as
0096  * userspace is concerned and shouldn't be relied upon.  For Gen < 12
0097  * they will be initialized to PTE. Gen >= 12 don't have a setting for
0098  * PTE and those platforms except TGL/RKL will be initialized L3 WB to
0099  * catch accidental use of reserved and unused mocs indexes.
0100  *
0101  * The last few entries are reserved by the hardware. For ICL+ they
0102  * should be initialized according to bspec and never used, for older
0103  * platforms they should never be written to.
0104  *
0105  * NOTE1: These tables are part of bspec and defined as part of hardware
0106  *       interface for ICL+. For older platforms, they are part of kernel
0107  *       ABI. It is expected that, for specific hardware platform, existing
0108  *       entries will remain constant and the table will only be updated by
0109  *       adding new entries, filling unused positions.
0110  *
0111  * NOTE2: For GEN >= 12 except TGL and RKL, reserved and unspecified MOCS
0112  *       indices have been set to L3 WB. These reserved entries should never
0113  *       be used, they may be changed to low performant variants with better
0114  *       coherency in the future if more entries are needed.
0115  *       For TGL/RKL, all the unspecified MOCS indexes are mapped to L3 UC.
0116  */
0117 #define GEN9_MOCS_ENTRIES \
0118     MOCS_ENTRY(I915_MOCS_UNCACHED, \
0119            LE_1_UC | LE_TC_2_LLC_ELLC, \
0120            L3_1_UC), \
0121     MOCS_ENTRY(I915_MOCS_PTE, \
0122            LE_0_PAGETABLE | LE_TC_0_PAGETABLE | LE_LRUM(3), \
0123            L3_3_WB)
0124 
0125 static const struct drm_i915_mocs_entry skl_mocs_table[] = {
0126     GEN9_MOCS_ENTRIES,
0127     MOCS_ENTRY(I915_MOCS_CACHED,
0128            LE_3_WB | LE_TC_2_LLC_ELLC | LE_LRUM(3),
0129            L3_3_WB),
0130 
0131     /*
0132      * mocs:63
0133      * - used by the L3 for all of its evictions.
0134      *   Thus it is expected to allow LLC cacheability to enable coherent
0135      *   flows to be maintained.
0136      * - used to force L3 uncachable cycles.
0137      *   Thus it is expected to make the surface L3 uncacheable.
0138      */
0139     MOCS_ENTRY(63,
0140            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
0141            L3_1_UC)
0142 };
0143 
0144 /* NOTE: the LE_TGT_CACHE is not used on Broxton */
0145 static const struct drm_i915_mocs_entry broxton_mocs_table[] = {
0146     GEN9_MOCS_ENTRIES,
0147     MOCS_ENTRY(I915_MOCS_CACHED,
0148            LE_1_UC | LE_TC_2_LLC_ELLC | LE_LRUM(3),
0149            L3_3_WB)
0150 };
0151 
0152 #define GEN11_MOCS_ENTRIES \
0153     /* Entries 0 and 1 are defined per-platform */ \
0154     /* Base - L3 + LLC */ \
0155     MOCS_ENTRY(2, \
0156            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \
0157            L3_3_WB), \
0158     /* Base - Uncached */ \
0159     MOCS_ENTRY(3, \
0160            LE_1_UC | LE_TC_1_LLC, \
0161            L3_1_UC), \
0162     /* Base - L3 */ \
0163     MOCS_ENTRY(4, \
0164            LE_1_UC | LE_TC_1_LLC, \
0165            L3_3_WB), \
0166     /* Base - LLC */ \
0167     MOCS_ENTRY(5, \
0168            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \
0169            L3_1_UC), \
0170     /* Age 0 - LLC */ \
0171     MOCS_ENTRY(6, \
0172            LE_3_WB | LE_TC_1_LLC | LE_LRUM(1), \
0173            L3_1_UC), \
0174     /* Age 0 - L3 + LLC */ \
0175     MOCS_ENTRY(7, \
0176            LE_3_WB | LE_TC_1_LLC | LE_LRUM(1), \
0177            L3_3_WB), \
0178     /* Age: Don't Chg. - LLC */ \
0179     MOCS_ENTRY(8, \
0180            LE_3_WB | LE_TC_1_LLC | LE_LRUM(2), \
0181            L3_1_UC), \
0182     /* Age: Don't Chg. - L3 + LLC */ \
0183     MOCS_ENTRY(9, \
0184            LE_3_WB | LE_TC_1_LLC | LE_LRUM(2), \
0185            L3_3_WB), \
0186     /* No AOM - LLC */ \
0187     MOCS_ENTRY(10, \
0188            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1), \
0189            L3_1_UC), \
0190     /* No AOM - L3 + LLC */ \
0191     MOCS_ENTRY(11, \
0192            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_AOM(1), \
0193            L3_3_WB), \
0194     /* No AOM; Age 0 - LLC */ \
0195     MOCS_ENTRY(12, \
0196            LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1), \
0197            L3_1_UC), \
0198     /* No AOM; Age 0 - L3 + LLC */ \
0199     MOCS_ENTRY(13, \
0200            LE_3_WB | LE_TC_1_LLC | LE_LRUM(1) | LE_AOM(1), \
0201            L3_3_WB), \
0202     /* No AOM; Age:DC - LLC */ \
0203     MOCS_ENTRY(14, \
0204            LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1), \
0205            L3_1_UC), \
0206     /* No AOM; Age:DC - L3 + LLC */ \
0207     MOCS_ENTRY(15, \
0208            LE_3_WB | LE_TC_1_LLC | LE_LRUM(2) | LE_AOM(1), \
0209            L3_3_WB), \
0210     /* Self-Snoop - L3 + LLC */ \
0211     MOCS_ENTRY(18, \
0212            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SSE(3), \
0213            L3_3_WB), \
0214     /* Skip Caching - L3 + LLC(12.5%) */ \
0215     MOCS_ENTRY(19, \
0216            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(7), \
0217            L3_3_WB), \
0218     /* Skip Caching - L3 + LLC(25%) */ \
0219     MOCS_ENTRY(20, \
0220            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(3), \
0221            L3_3_WB), \
0222     /* Skip Caching - L3 + LLC(50%) */ \
0223     MOCS_ENTRY(21, \
0224            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_SCC(1), \
0225            L3_3_WB), \
0226     /* Skip Caching - L3 + LLC(75%) */ \
0227     MOCS_ENTRY(22, \
0228            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(3), \
0229            L3_3_WB), \
0230     /* Skip Caching - L3 + LLC(87.5%) */ \
0231     MOCS_ENTRY(23, \
0232            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3) | LE_RSC(1) | LE_SCC(7), \
0233            L3_3_WB), \
0234     /* HW Reserved - SW program but never use */ \
0235     MOCS_ENTRY(62, \
0236            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \
0237            L3_1_UC), \
0238     /* HW Reserved - SW program but never use */ \
0239     MOCS_ENTRY(63, \
0240            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3), \
0241            L3_1_UC)
0242 
0243 static const struct drm_i915_mocs_entry tgl_mocs_table[] = {
0244     /*
0245      * NOTE:
0246      * Reserved and unspecified MOCS indices have been set to (L3 + LCC).
0247      * These reserved entries should never be used, they may be changed
0248      * to low performant variants with better coherency in the future if
0249      * more entries are needed. We are programming index I915_MOCS_PTE(1)
0250      * only, __init_mocs_table() take care to program unused index with
0251      * this entry.
0252      */
0253     MOCS_ENTRY(I915_MOCS_PTE,
0254            LE_0_PAGETABLE | LE_TC_0_PAGETABLE,
0255            L3_1_UC),
0256     GEN11_MOCS_ENTRIES,
0257 
0258     /* Implicitly enable L1 - HDC:L1 + L3 + LLC */
0259     MOCS_ENTRY(48,
0260            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
0261            L3_3_WB),
0262     /* Implicitly enable L1 - HDC:L1 + L3 */
0263     MOCS_ENTRY(49,
0264            LE_1_UC | LE_TC_1_LLC,
0265            L3_3_WB),
0266     /* Implicitly enable L1 - HDC:L1 + LLC */
0267     MOCS_ENTRY(50,
0268            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
0269            L3_1_UC),
0270     /* Implicitly enable L1 - HDC:L1 */
0271     MOCS_ENTRY(51,
0272            LE_1_UC | LE_TC_1_LLC,
0273            L3_1_UC),
0274     /* HW Special Case (CCS) */
0275     MOCS_ENTRY(60,
0276            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
0277            L3_1_UC),
0278     /* HW Special Case (Displayable) */
0279     MOCS_ENTRY(61,
0280            LE_1_UC | LE_TC_1_LLC,
0281            L3_3_WB),
0282 };
0283 
0284 static const struct drm_i915_mocs_entry icl_mocs_table[] = {
0285     /* Base - Uncached (Deprecated) */
0286     MOCS_ENTRY(I915_MOCS_UNCACHED,
0287            LE_1_UC | LE_TC_1_LLC,
0288            L3_1_UC),
0289     /* Base - L3 + LeCC:PAT (Deprecated) */
0290     MOCS_ENTRY(I915_MOCS_PTE,
0291            LE_0_PAGETABLE | LE_TC_0_PAGETABLE,
0292            L3_3_WB),
0293 
0294     GEN11_MOCS_ENTRIES
0295 };
0296 
0297 static const struct drm_i915_mocs_entry dg1_mocs_table[] = {
0298 
0299     /* UC */
0300     MOCS_ENTRY(1, 0, L3_1_UC),
0301     /* WB - L3 */
0302     MOCS_ENTRY(5, 0, L3_3_WB),
0303     /* WB - L3 50% */
0304     MOCS_ENTRY(6, 0, L3_ESC(1) | L3_SCC(1) | L3_3_WB),
0305     /* WB - L3 25% */
0306     MOCS_ENTRY(7, 0, L3_ESC(1) | L3_SCC(3) | L3_3_WB),
0307     /* WB - L3 12.5% */
0308     MOCS_ENTRY(8, 0, L3_ESC(1) | L3_SCC(7) | L3_3_WB),
0309 
0310     /* HDC:L1 + L3 */
0311     MOCS_ENTRY(48, 0, L3_3_WB),
0312     /* HDC:L1 */
0313     MOCS_ENTRY(49, 0, L3_1_UC),
0314 
0315     /* HW Reserved */
0316     MOCS_ENTRY(60, 0, L3_1_UC),
0317     MOCS_ENTRY(61, 0, L3_1_UC),
0318     MOCS_ENTRY(62, 0, L3_1_UC),
0319     MOCS_ENTRY(63, 0, L3_1_UC),
0320 };
0321 
0322 static const struct drm_i915_mocs_entry gen12_mocs_table[] = {
0323     GEN11_MOCS_ENTRIES,
0324     /* Implicitly enable L1 - HDC:L1 + L3 + LLC */
0325     MOCS_ENTRY(48,
0326            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
0327            L3_3_WB),
0328     /* Implicitly enable L1 - HDC:L1 + L3 */
0329     MOCS_ENTRY(49,
0330            LE_1_UC | LE_TC_1_LLC,
0331            L3_3_WB),
0332     /* Implicitly enable L1 - HDC:L1 + LLC */
0333     MOCS_ENTRY(50,
0334            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
0335            L3_1_UC),
0336     /* Implicitly enable L1 - HDC:L1 */
0337     MOCS_ENTRY(51,
0338            LE_1_UC | LE_TC_1_LLC,
0339            L3_1_UC),
0340     /* HW Special Case (CCS) */
0341     MOCS_ENTRY(60,
0342            LE_3_WB | LE_TC_1_LLC | LE_LRUM(3),
0343            L3_1_UC),
0344     /* HW Special Case (Displayable) */
0345     MOCS_ENTRY(61,
0346            LE_1_UC | LE_TC_1_LLC,
0347            L3_3_WB),
0348 };
0349 
0350 static const struct drm_i915_mocs_entry xehpsdv_mocs_table[] = {
0351     /* wa_1608975824 */
0352     MOCS_ENTRY(0, 0, L3_3_WB | L3_LKUP(1)),
0353 
0354     /* UC - Coherent; GO:L3 */
0355     MOCS_ENTRY(1, 0, L3_1_UC | L3_LKUP(1)),
0356     /* UC - Coherent; GO:Memory */
0357     MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
0358     /* UC - Non-Coherent; GO:Memory */
0359     MOCS_ENTRY(3, 0, L3_1_UC | L3_GLBGO(1)),
0360     /* UC - Non-Coherent; GO:L3 */
0361     MOCS_ENTRY(4, 0, L3_1_UC),
0362 
0363     /* WB */
0364     MOCS_ENTRY(5, 0, L3_3_WB | L3_LKUP(1)),
0365 
0366     /* HW Reserved - SW program but never use. */
0367     MOCS_ENTRY(48, 0, L3_3_WB | L3_LKUP(1)),
0368     MOCS_ENTRY(49, 0, L3_1_UC | L3_LKUP(1)),
0369     MOCS_ENTRY(60, 0, L3_1_UC),
0370     MOCS_ENTRY(61, 0, L3_1_UC),
0371     MOCS_ENTRY(62, 0, L3_1_UC),
0372     MOCS_ENTRY(63, 0, L3_1_UC),
0373 };
0374 
0375 static const struct drm_i915_mocs_entry dg2_mocs_table[] = {
0376     /* UC - Coherent; GO:L3 */
0377     MOCS_ENTRY(0, 0, L3_1_UC | L3_LKUP(1)),
0378     /* UC - Coherent; GO:Memory */
0379     MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
0380     /* UC - Non-Coherent; GO:Memory */
0381     MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)),
0382 
0383     /* WB - LC */
0384     MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)),
0385 };
0386 
0387 static const struct drm_i915_mocs_entry dg2_mocs_table_g10_ax[] = {
0388     /* Wa_14011441408: Set Go to Memory for MOCS#0 */
0389     MOCS_ENTRY(0, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
0390     /* UC - Coherent; GO:Memory */
0391     MOCS_ENTRY(1, 0, L3_1_UC | L3_GLBGO(1) | L3_LKUP(1)),
0392     /* UC - Non-Coherent; GO:Memory */
0393     MOCS_ENTRY(2, 0, L3_1_UC | L3_GLBGO(1)),
0394 
0395     /* WB - LC */
0396     MOCS_ENTRY(3, 0, L3_3_WB | L3_LKUP(1)),
0397 };
0398 
0399 static const struct drm_i915_mocs_entry pvc_mocs_table[] = {
0400     /* Error */
0401     MOCS_ENTRY(0, 0, L3_3_WB),
0402 
0403     /* UC */
0404     MOCS_ENTRY(1, 0, L3_1_UC),
0405 
0406     /* WB */
0407     MOCS_ENTRY(2, 0, L3_3_WB),
0408 };
0409 
0410 enum {
0411     HAS_GLOBAL_MOCS = BIT(0),
0412     HAS_ENGINE_MOCS = BIT(1),
0413     HAS_RENDER_L3CC = BIT(2),
0414 };
0415 
0416 static bool has_l3cc(const struct drm_i915_private *i915)
0417 {
0418     return true;
0419 }
0420 
0421 static bool has_global_mocs(const struct drm_i915_private *i915)
0422 {
0423     return HAS_GLOBAL_MOCS_REGISTERS(i915);
0424 }
0425 
0426 static bool has_mocs(const struct drm_i915_private *i915)
0427 {
0428     return !IS_DGFX(i915);
0429 }
0430 
0431 static unsigned int get_mocs_settings(const struct drm_i915_private *i915,
0432                       struct drm_i915_mocs_table *table)
0433 {
0434     unsigned int flags;
0435 
0436     memset(table, 0, sizeof(struct drm_i915_mocs_table));
0437 
0438     table->unused_entries_index = I915_MOCS_PTE;
0439     if (IS_PONTEVECCHIO(i915)) {
0440         table->size = ARRAY_SIZE(pvc_mocs_table);
0441         table->table = pvc_mocs_table;
0442         table->n_entries = PVC_NUM_MOCS_ENTRIES;
0443         table->uc_index = 1;
0444         table->wb_index = 2;
0445         table->unused_entries_index = 2;
0446     } else if (IS_DG2(i915)) {
0447         if (IS_DG2_GRAPHICS_STEP(i915, G10, STEP_A0, STEP_B0)) {
0448             table->size = ARRAY_SIZE(dg2_mocs_table_g10_ax);
0449             table->table = dg2_mocs_table_g10_ax;
0450         } else {
0451             table->size = ARRAY_SIZE(dg2_mocs_table);
0452             table->table = dg2_mocs_table;
0453         }
0454         table->uc_index = 1;
0455         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0456         table->unused_entries_index = 3;
0457     } else if (IS_XEHPSDV(i915)) {
0458         table->size = ARRAY_SIZE(xehpsdv_mocs_table);
0459         table->table = xehpsdv_mocs_table;
0460         table->uc_index = 2;
0461         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0462         table->unused_entries_index = 5;
0463     } else if (IS_DG1(i915)) {
0464         table->size = ARRAY_SIZE(dg1_mocs_table);
0465         table->table = dg1_mocs_table;
0466         table->uc_index = 1;
0467         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0468         table->uc_index = 1;
0469         table->unused_entries_index = 5;
0470     } else if (IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915)) {
0471         /* For TGL/RKL, Can't be changed now for ABI reasons */
0472         table->size  = ARRAY_SIZE(tgl_mocs_table);
0473         table->table = tgl_mocs_table;
0474         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0475         table->uc_index = 3;
0476     } else if (GRAPHICS_VER(i915) >= 12) {
0477         table->size  = ARRAY_SIZE(gen12_mocs_table);
0478         table->table = gen12_mocs_table;
0479         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0480         table->uc_index = 3;
0481         table->unused_entries_index = 2;
0482     } else if (GRAPHICS_VER(i915) == 11) {
0483         table->size  = ARRAY_SIZE(icl_mocs_table);
0484         table->table = icl_mocs_table;
0485         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0486     } else if (IS_GEN9_BC(i915)) {
0487         table->size  = ARRAY_SIZE(skl_mocs_table);
0488         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0489         table->table = skl_mocs_table;
0490     } else if (IS_GEN9_LP(i915)) {
0491         table->size  = ARRAY_SIZE(broxton_mocs_table);
0492         table->n_entries = GEN9_NUM_MOCS_ENTRIES;
0493         table->table = broxton_mocs_table;
0494     } else {
0495         drm_WARN_ONCE(&i915->drm, GRAPHICS_VER(i915) >= 9,
0496                   "Platform that should have a MOCS table does not.\n");
0497         return 0;
0498     }
0499 
0500     if (GEM_DEBUG_WARN_ON(table->size > table->n_entries))
0501         return 0;
0502 
0503     /* WaDisableSkipCaching:skl,bxt,kbl,glk */
0504     if (GRAPHICS_VER(i915) == 9) {
0505         int i;
0506 
0507         for (i = 0; i < table->size; i++)
0508             if (GEM_DEBUG_WARN_ON(table->table[i].l3cc_value &
0509                           (L3_ESC(1) | L3_SCC(0x7))))
0510                 return 0;
0511     }
0512 
0513     flags = 0;
0514     if (has_mocs(i915)) {
0515         if (has_global_mocs(i915))
0516             flags |= HAS_GLOBAL_MOCS;
0517         else
0518             flags |= HAS_ENGINE_MOCS;
0519     }
0520     if (has_l3cc(i915))
0521         flags |= HAS_RENDER_L3CC;
0522 
0523     return flags;
0524 }
0525 
0526 /*
0527  * Get control_value from MOCS entry taking into account when it's not used
0528  * then if unused_entries_index is non-zero then its value will be returned
0529  * otherwise I915_MOCS_PTE's value is returned in this case.
0530  */
0531 static u32 get_entry_control(const struct drm_i915_mocs_table *table,
0532                  unsigned int index)
0533 {
0534     if (index < table->size && table->table[index].used)
0535         return table->table[index].control_value;
0536     return table->table[table->unused_entries_index].control_value;
0537 }
0538 
0539 #define for_each_mocs(mocs, t, i) \
0540     for (i = 0; \
0541          i < (t)->n_entries ? (mocs = get_entry_control((t), i)), 1 : 0;\
0542          i++)
0543 
0544 static void __init_mocs_table(struct intel_uncore *uncore,
0545                   const struct drm_i915_mocs_table *table,
0546                   u32 addr)
0547 {
0548     unsigned int i;
0549     u32 mocs;
0550 
0551     drm_WARN_ONCE(&uncore->i915->drm, !table->unused_entries_index,
0552               "Unused entries index should have been defined\n");
0553     for_each_mocs(mocs, table, i)
0554         intel_uncore_write_fw(uncore, _MMIO(addr + i * 4), mocs);
0555 }
0556 
0557 static u32 mocs_offset(const struct intel_engine_cs *engine)
0558 {
0559     static const u32 offset[] = {
0560         [RCS0]  =  __GEN9_RCS0_MOCS0,
0561         [VCS0]  =  __GEN9_VCS0_MOCS0,
0562         [VCS1]  =  __GEN9_VCS1_MOCS0,
0563         [VECS0] =  __GEN9_VECS0_MOCS0,
0564         [BCS0]  =  __GEN9_BCS0_MOCS0,
0565         [VCS2]  = __GEN11_VCS2_MOCS0,
0566     };
0567 
0568     GEM_BUG_ON(engine->id >= ARRAY_SIZE(offset));
0569     return offset[engine->id];
0570 }
0571 
0572 static void init_mocs_table(struct intel_engine_cs *engine,
0573                 const struct drm_i915_mocs_table *table)
0574 {
0575     __init_mocs_table(engine->uncore, table, mocs_offset(engine));
0576 }
0577 
0578 /*
0579  * Get l3cc_value from MOCS entry taking into account when it's not used
0580  * then if unused_entries_index is not zero then its value will be returned
0581  * otherwise I915_MOCS_PTE's value is returned in this case.
0582  */
0583 static u16 get_entry_l3cc(const struct drm_i915_mocs_table *table,
0584               unsigned int index)
0585 {
0586     if (index < table->size && table->table[index].used)
0587         return table->table[index].l3cc_value;
0588     return table->table[table->unused_entries_index].l3cc_value;
0589 }
0590 
0591 static u32 l3cc_combine(u16 low, u16 high)
0592 {
0593     return low | (u32)high << 16;
0594 }
0595 
0596 #define for_each_l3cc(l3cc, t, i) \
0597     for (i = 0; \
0598          i < ((t)->n_entries + 1) / 2 ? \
0599          (l3cc = l3cc_combine(get_entry_l3cc((t), 2 * i), \
0600                   get_entry_l3cc((t), 2 * i + 1))), 1 : \
0601          0; \
0602          i++)
0603 
0604 static void init_l3cc_table(struct intel_uncore *uncore,
0605                 const struct drm_i915_mocs_table *table)
0606 {
0607     unsigned int i;
0608     u32 l3cc;
0609 
0610     for_each_l3cc(l3cc, table, i)
0611         intel_uncore_write_fw(uncore, GEN9_LNCFCMOCS(i), l3cc);
0612 }
0613 
0614 void intel_mocs_init_engine(struct intel_engine_cs *engine)
0615 {
0616     struct drm_i915_mocs_table table;
0617     unsigned int flags;
0618 
0619     /* Called under a blanket forcewake */
0620     assert_forcewakes_active(engine->uncore, FORCEWAKE_ALL);
0621 
0622     flags = get_mocs_settings(engine->i915, &table);
0623     if (!flags)
0624         return;
0625 
0626     /* Platforms with global MOCS do not need per-engine initialization. */
0627     if (flags & HAS_ENGINE_MOCS)
0628         init_mocs_table(engine, &table);
0629 
0630     if (flags & HAS_RENDER_L3CC && engine->class == RENDER_CLASS)
0631         init_l3cc_table(engine->uncore, &table);
0632 }
0633 
0634 static u32 global_mocs_offset(void)
0635 {
0636     return i915_mmio_reg_offset(GEN12_GLOBAL_MOCS(0));
0637 }
0638 
0639 void intel_set_mocs_index(struct intel_gt *gt)
0640 {
0641     struct drm_i915_mocs_table table;
0642 
0643     get_mocs_settings(gt->i915, &table);
0644     gt->mocs.uc_index = table.uc_index;
0645     if (HAS_L3_CCS_READ(gt->i915))
0646         gt->mocs.wb_index = table.wb_index;
0647 }
0648 
0649 void intel_mocs_init(struct intel_gt *gt)
0650 {
0651     struct drm_i915_mocs_table table;
0652     unsigned int flags;
0653 
0654     /*
0655      * LLC and eDRAM control values are not applicable to dgfx
0656      */
0657     flags = get_mocs_settings(gt->i915, &table);
0658     if (flags & HAS_GLOBAL_MOCS)
0659         __init_mocs_table(gt->uncore, &table, global_mocs_offset());
0660 
0661     /*
0662      * Initialize the L3CC table as part of mocs initalization to make
0663      * sure the LNCFCMOCSx registers are programmed for the subsequent
0664      * memory transactions including guc transactions
0665      */
0666     if (flags & HAS_RENDER_L3CC)
0667         init_l3cc_table(gt->uncore, &table);
0668 }
0669 
0670 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
0671 #include "selftest_mocs.c"
0672 #endif