LCOV - code coverage report
Current view: top level - dev/pci/drm/i915 - intel_mocs.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 84 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 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             :  * The above copyright notice and this permission notice (including the next
      11             :  * paragraph) shall be included in all copies or substantial portions of the
      12             :  * Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      17             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      20             :  * SOFTWARE.
      21             :  */
      22             : 
      23             : #include "intel_mocs.h"
      24             : #include "intel_lrc.h"
      25             : #include "intel_ringbuffer.h"
      26             : 
      27             : /* structures required */
      28             : struct drm_i915_mocs_entry {
      29             :         u32 control_value;
      30             :         u16 l3cc_value;
      31             : };
      32             : 
      33             : struct drm_i915_mocs_table {
      34             :         u32 size;
      35             :         const struct drm_i915_mocs_entry *table;
      36             : };
      37             : 
      38             : /* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */
      39             : #define LE_CACHEABILITY(value)  ((value) << 0)
      40             : #define LE_TGT_CACHE(value)     ((value) << 2)
      41             : #define LE_LRUM(value)          ((value) << 4)
      42             : #define LE_AOM(value)           ((value) << 6)
      43             : #define LE_RSC(value)           ((value) << 7)
      44             : #define LE_SCC(value)           ((value) << 8)
      45             : #define LE_PFM(value)           ((value) << 11)
      46             : #define LE_SCF(value)           ((value) << 14)
      47             : 
      48             : /* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */
      49             : #define L3_ESC(value)           ((value) << 0)
      50             : #define L3_SCC(value)           ((value) << 1)
      51             : #define L3_CACHEABILITY(value)  ((value) << 4)
      52             : 
      53             : /* Helper defines */
      54             : #define GEN9_NUM_MOCS_ENTRIES   62  /* 62 out of 64 - 63 & 64 are reserved. */
      55             : 
      56             : /* (e)LLC caching options */
      57             : #define LE_PAGETABLE            0
      58             : #define LE_UC                   1
      59             : #define LE_WT                   2
      60             : #define LE_WB                   3
      61             : 
      62             : /* L3 caching options */
      63             : #define L3_DIRECT               0
      64             : #define L3_UC                   1
      65             : #define L3_RESERVED             2
      66             : #define L3_WB                   3
      67             : 
      68             : /* Target cache */
      69             : #define ELLC                    0
      70             : #define LLC                     1
      71             : #define LLC_ELLC                2
      72             : 
      73             : /*
      74             :  * MOCS tables
      75             :  *
      76             :  * These are the MOCS tables that are programmed across all the rings.
      77             :  * The control value is programmed to all the rings that support the
      78             :  * MOCS registers. While the l3cc_values are only programmed to the
      79             :  * LNCFCMOCS0 - LNCFCMOCS32 registers.
      80             :  *
      81             :  * These tables are intended to be kept reasonably consistent across
      82             :  * platforms. However some of the fields are not applicable to all of
      83             :  * them.
      84             :  *
      85             :  * Entries not part of the following tables are undefined as far as
      86             :  * userspace is concerned and shouldn't be relied upon.  For the time
      87             :  * being they will be implicitly initialized to the strictest caching
      88             :  * configuration (uncached) to guarantee forwards compatibility with
      89             :  * userspace programs written against more recent kernels providing
      90             :  * additional MOCS entries.
      91             :  *
      92             :  * NOTE: These tables MUST start with being uncached and the length
      93             :  *       MUST be less than 63 as the last two registers are reserved
      94             :  *       by the hardware.  These tables are part of the kernel ABI and
      95             :  *       may only be updated incrementally by adding entries at the
      96             :  *       end.
      97             :  */
      98             : static const struct drm_i915_mocs_entry skylake_mocs_table[] = {
      99             :         /* { 0x00000009, 0x0010 } */
     100             :         { (LE_CACHEABILITY(LE_UC) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(0) |
     101             :            LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)),
     102             :           (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC)) },
     103             :         /* { 0x00000038, 0x0030 } */
     104             :         { (LE_CACHEABILITY(LE_PAGETABLE) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) |
     105             :            LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)),
     106             :           (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) },
     107             :         /* { 0x0000003b, 0x0030 } */
     108             :         { (LE_CACHEABILITY(LE_WB) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) |
     109             :            LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)),
     110             :           (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) }
     111             : };
     112             : 
     113             : /* NOTE: the LE_TGT_CACHE is not used on Broxton */
     114             : static const struct drm_i915_mocs_entry broxton_mocs_table[] = {
     115             :         /* { 0x00000009, 0x0010 } */
     116             :         { (LE_CACHEABILITY(LE_UC) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(0) |
     117             :            LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)),
     118             :           (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC)) },
     119             :         /* { 0x00000038, 0x0030 } */
     120             :         { (LE_CACHEABILITY(LE_PAGETABLE) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) |
     121             :            LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)),
     122             :           (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) },
     123             :         /* { 0x0000003b, 0x0030 } */
     124             :         { (LE_CACHEABILITY(LE_WB) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) |
     125             :            LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)),
     126             :           (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) }
     127             : };
     128             : 
     129             : /**
     130             :  * get_mocs_settings()
     131             :  * @dev:        DRM device.
     132             :  * @table:      Output table that will be made to point at appropriate
     133             :  *              MOCS values for the device.
     134             :  *
     135             :  * This function will return the values of the MOCS table that needs to
     136             :  * be programmed for the platform. It will return the values that need
     137             :  * to be programmed and if they need to be programmed.
     138             :  *
     139             :  * Return: true if there are applicable MOCS settings for the device.
     140             :  */
     141           0 : static bool get_mocs_settings(struct drm_device *dev,
     142             :                               struct drm_i915_mocs_table *table)
     143             : {
     144             :         bool result = false;
     145             : 
     146           0 :         if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
     147           0 :                 table->size  = ARRAY_SIZE(skylake_mocs_table);
     148           0 :                 table->table = skylake_mocs_table;
     149             :                 result = true;
     150           0 :         } else if (IS_BROXTON(dev)) {
     151           0 :                 table->size  = ARRAY_SIZE(broxton_mocs_table);
     152           0 :                 table->table = broxton_mocs_table;
     153             :                 result = true;
     154           0 :         } else {
     155           0 :                 WARN_ONCE(INTEL_INFO(dev)->gen >= 9,
     156             :                           "Platform that should have a MOCS table does not.\n");
     157             :         }
     158             : 
     159             :         /* WaDisableSkipCaching:skl,bxt,kbl */
     160           0 :         if (IS_GEN9(dev)) {
     161             :                 int i;
     162             : 
     163           0 :                 for (i = 0; i < table->size; i++)
     164           0 :                         if (WARN_ON(table->table[i].l3cc_value &
     165             :                                     (L3_ESC(1) || L3_SCC(0x7))))
     166           0 :                         return false;
     167           0 :         }
     168             : 
     169           0 :         return result;
     170           0 : }
     171             : 
     172             : /**
     173             :  * emit_mocs_control_table() - emit the mocs control table
     174             :  * @req:        Request to set up the MOCS table for.
     175             :  * @table:      The values to program into the control regs.
     176             :  * @reg_base:   The base for the engine that needs to be programmed.
     177             :  *
     178             :  * This function simply emits a MI_LOAD_REGISTER_IMM command for the
     179             :  * given table starting at the given address.
     180             :  *
     181             :  * Return: 0 on success, otherwise the error status.
     182             :  */
     183           0 : static int emit_mocs_control_table(struct drm_i915_gem_request *req,
     184             :                                    const struct drm_i915_mocs_table *table,
     185             :                                    u32 reg_base)
     186             : {
     187           0 :         struct intel_ringbuffer *ringbuf = req->ringbuf;
     188             :         unsigned int index;
     189             :         int ret;
     190             : 
     191           0 :         if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES))
     192           0 :                 return -ENODEV;
     193             : 
     194           0 :         ret = intel_logical_ring_begin(req, 2 + 2 * GEN9_NUM_MOCS_ENTRIES);
     195           0 :         if (ret) {
     196             :                 DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);
     197           0 :                 return ret;
     198             :         }
     199             : 
     200           0 :         intel_logical_ring_emit(ringbuf,
     201             :                                 MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES));
     202             : 
     203           0 :         for (index = 0; index < table->size; index++) {
     204           0 :                 intel_logical_ring_emit(ringbuf, reg_base + index * 4);
     205           0 :                 intel_logical_ring_emit(ringbuf,
     206           0 :                                         table->table[index].control_value);
     207             :         }
     208             : 
     209             :         /*
     210             :          * Ok, now set the unused entries to uncached. These entries
     211             :          * are officially undefined and no contract for the contents
     212             :          * and settings is given for these entries.
     213             :          *
     214             :          * Entry 0 in the table is uncached - so we are just writing
     215             :          * that value to all the used entries.
     216             :          */
     217           0 :         for (; index < GEN9_NUM_MOCS_ENTRIES; index++) {
     218           0 :                 intel_logical_ring_emit(ringbuf, reg_base + index * 4);
     219           0 :                 intel_logical_ring_emit(ringbuf, table->table[0].control_value);
     220             :         }
     221             : 
     222           0 :         intel_logical_ring_emit(ringbuf, MI_NOOP);
     223           0 :         intel_logical_ring_advance(ringbuf);
     224             : 
     225           0 :         return 0;
     226           0 : }
     227             : 
     228             : /**
     229             :  * emit_mocs_l3cc_table() - emit the mocs control table
     230             :  * @req:        Request to set up the MOCS table for.
     231             :  * @table:      The values to program into the control regs.
     232             :  *
     233             :  * This function simply emits a MI_LOAD_REGISTER_IMM command for the
     234             :  * given table starting at the given address. This register set is
     235             :  * programmed in pairs.
     236             :  *
     237             :  * Return: 0 on success, otherwise the error status.
     238             :  */
     239           0 : static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req,
     240             :                                 const struct drm_i915_mocs_table *table)
     241             : {
     242           0 :         struct intel_ringbuffer *ringbuf = req->ringbuf;
     243             :         unsigned int count;
     244             :         unsigned int i;
     245             :         u32 value;
     246           0 :         u32 filler = (table->table[0].l3cc_value & 0xffff) |
     247           0 :                         ((table->table[0].l3cc_value & 0xffff) << 16);
     248             :         int ret;
     249             : 
     250           0 :         if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES))
     251           0 :                 return -ENODEV;
     252             : 
     253           0 :         ret = intel_logical_ring_begin(req, 2 + GEN9_NUM_MOCS_ENTRIES);
     254           0 :         if (ret) {
     255             :                 DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret);
     256           0 :                 return ret;
     257             :         }
     258             : 
     259           0 :         intel_logical_ring_emit(ringbuf,
     260             :                         MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2));
     261             : 
     262           0 :         for (i = 0, count = 0; i < table->size / 2; i++, count += 2) {
     263           0 :                 value = (table->table[count].l3cc_value & 0xffff) |
     264           0 :                         ((table->table[count + 1].l3cc_value & 0xffff) << 16);
     265             : 
     266           0 :                 intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4);
     267           0 :                 intel_logical_ring_emit(ringbuf, value);
     268             :         }
     269             : 
     270           0 :         if (table->size & 0x01) {
     271             :                 /* Odd table size - 1 left over */
     272           0 :                 value = (table->table[count].l3cc_value & 0xffff) |
     273           0 :                         ((table->table[0].l3cc_value & 0xffff) << 16);
     274           0 :         } else
     275             :                 value = filler;
     276             : 
     277             :         /*
     278             :          * Now set the rest of the table to uncached - use entry 0 as
     279             :          * this will be uncached. Leave the last pair uninitialised as
     280             :          * they are reserved by the hardware.
     281             :          */
     282           0 :         for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) {
     283           0 :                 intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4);
     284           0 :                 intel_logical_ring_emit(ringbuf, value);
     285             : 
     286             :                 value = filler;
     287             :         }
     288             : 
     289           0 :         intel_logical_ring_emit(ringbuf, MI_NOOP);
     290           0 :         intel_logical_ring_advance(ringbuf);
     291             : 
     292           0 :         return 0;
     293           0 : }
     294             : 
     295             : /**
     296             :  * intel_rcs_context_init_mocs() - program the MOCS register.
     297             :  * @req:        Request to set up the MOCS tables for.
     298             :  *
     299             :  * This function will emit a batch buffer with the values required for
     300             :  * programming the MOCS register values for all the currently supported
     301             :  * rings.
     302             :  *
     303             :  * These registers are partially stored in the RCS context, so they are
     304             :  * emitted at the same time so that when a context is created these registers
     305             :  * are set up. These registers have to be emitted into the start of the
     306             :  * context as setting the ELSP will re-init some of these registers back
     307             :  * to the hw values.
     308             :  *
     309             :  * Return: 0 on success, otherwise the error status.
     310             :  */
     311           0 : int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req)
     312             : {
     313           0 :         struct drm_i915_mocs_table t;
     314             :         int ret;
     315             : 
     316           0 :         if (get_mocs_settings(req->ring->dev, &t)) {
     317             :                 /* Program the control registers */
     318           0 :                 ret = emit_mocs_control_table(req, &t, GEN9_GFX_MOCS_0);
     319           0 :                 if (ret)
     320           0 :                         return ret;
     321             : 
     322           0 :                 ret = emit_mocs_control_table(req, &t, GEN9_MFX0_MOCS_0);
     323           0 :                 if (ret)
     324           0 :                         return ret;
     325             : 
     326           0 :                 ret = emit_mocs_control_table(req, &t, GEN9_MFX1_MOCS_0);
     327           0 :                 if (ret)
     328           0 :                         return ret;
     329             : 
     330           0 :                 ret = emit_mocs_control_table(req, &t, GEN9_VEBOX_MOCS_0);
     331           0 :                 if (ret)
     332           0 :                         return ret;
     333             : 
     334           0 :                 ret = emit_mocs_control_table(req, &t, GEN9_BLT_MOCS_0);
     335           0 :                 if (ret)
     336           0 :                         return ret;
     337             : 
     338             :                 /* Now program the l3cc registers */
     339           0 :                 ret = emit_mocs_l3cc_table(req, &t);
     340           0 :                 if (ret)
     341           0 :                         return ret;
     342             :         }
     343             : 
     344           0 :         return 0;
     345           0 : }

Generated by: LCOV version 1.13