LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915/gt - intel_rc6.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 366 0.0 %
Date: 2022-04-01 13:59:58 Functions: 0 22 0.0 %
Branches: 0 184 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * SPDX-License-Identifier: MIT
       3                 :            :  *
       4                 :            :  * Copyright © 2019 Intel Corporation
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <linux/pm_runtime.h>
       8                 :            : 
       9                 :            : #include "i915_drv.h"
      10                 :            : #include "intel_gt.h"
      11                 :            : #include "intel_gt_pm.h"
      12                 :            : #include "intel_rc6.h"
      13                 :            : #include "intel_sideband.h"
      14                 :            : 
      15                 :            : /**
      16                 :            :  * DOC: RC6
      17                 :            :  *
      18                 :            :  * RC6 is a special power stage which allows the GPU to enter an very
      19                 :            :  * low-voltage mode when idle, using down to 0V while at this stage.  This
      20                 :            :  * stage is entered automatically when the GPU is idle when RC6 support is
      21                 :            :  * enabled, and as soon as new workload arises GPU wakes up automatically as
      22                 :            :  * well.
      23                 :            :  *
      24                 :            :  * There are different RC6 modes available in Intel GPU, which differentiate
      25                 :            :  * among each other with the latency required to enter and leave RC6 and
      26                 :            :  * voltage consumed by the GPU in different states.
      27                 :            :  *
      28                 :            :  * The combination of the following flags define which states GPU is allowed
      29                 :            :  * to enter, while RC6 is the normal RC6 state, RC6p is the deep RC6, and
      30                 :            :  * RC6pp is deepest RC6. Their support by hardware varies according to the
      31                 :            :  * GPU, BIOS, chipset and platform. RC6 is usually the safest one and the one
      32                 :            :  * which brings the most power savings; deeper states save more power, but
      33                 :            :  * require higher latency to switch to and wake up.
      34                 :            :  */
      35                 :            : 
      36                 :          0 : static struct intel_gt *rc6_to_gt(struct intel_rc6 *rc6)
      37                 :            : {
      38                 :          0 :         return container_of(rc6, struct intel_gt, rc6);
      39                 :            : }
      40                 :            : 
      41                 :          0 : static struct intel_uncore *rc6_to_uncore(struct intel_rc6 *rc)
      42                 :            : {
      43                 :          0 :         return rc6_to_gt(rc)->uncore;
      44                 :            : }
      45                 :            : 
      46                 :          0 : static struct drm_i915_private *rc6_to_i915(struct intel_rc6 *rc)
      47                 :            : {
      48   [ #  #  #  # ]:          0 :         return rc6_to_gt(rc)->i915;
      49                 :            : }
      50                 :            : 
      51                 :          0 : static inline void set(struct intel_uncore *uncore, i915_reg_t reg, u32 val)
      52                 :            : {
      53                 :          0 :         intel_uncore_write_fw(uncore, reg, val);
      54                 :            : }
      55                 :            : 
      56                 :          0 : static void gen11_rc6_enable(struct intel_rc6 *rc6)
      57                 :            : {
      58                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
      59                 :          0 :         struct intel_engine_cs *engine;
      60                 :          0 :         enum intel_engine_id id;
      61                 :            : 
      62                 :            :         /* 2b: Program RC6 thresholds.*/
      63                 :          0 :         set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16 | 85);
      64                 :          0 :         set(uncore, GEN10_MEDIA_WAKE_RATE_LIMIT, 150);
      65                 :            : 
      66                 :          0 :         set(uncore, GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */
      67                 :          0 :         set(uncore, GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */
      68   [ #  #  #  # ]:          0 :         for_each_engine(engine, rc6_to_gt(rc6), id)
      69                 :          0 :                 set(uncore, RING_MAX_IDLE(engine->mmio_base), 10);
      70                 :            : 
      71                 :          0 :         set(uncore, GUC_MAX_IDLE_COUNT, 0xA);
      72                 :            : 
      73                 :          0 :         set(uncore, GEN6_RC_SLEEP, 0);
      74                 :            : 
      75                 :          0 :         set(uncore, GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
      76                 :            : 
      77                 :            :         /*
      78                 :            :          * 2c: Program Coarse Power Gating Policies.
      79                 :            :          *
      80                 :            :          * Bspec's guidance is to use 25us (really 25 * 1280ns) here. What we
      81                 :            :          * use instead is a more conservative estimate for the maximum time
      82                 :            :          * it takes us to service a CS interrupt and submit a new ELSP - that
      83                 :            :          * is the time which the GPU is idle waiting for the CPU to select the
      84                 :            :          * next request to execute. If the idle hysteresis is less than that
      85                 :            :          * interrupt service latency, the hardware will automatically gate
      86                 :            :          * the power well and we will then incur the wake up cost on top of
      87                 :            :          * the service latency. A similar guide from plane_state is that we
      88                 :            :          * do not want the enable hysteresis to less than the wakeup latency.
      89                 :            :          *
      90                 :            :          * igt/gem_exec_nop/sequential provides a rough estimate for the
      91                 :            :          * service latency, and puts it under 10us for Icelake, similar to
      92                 :            :          * Broadwell+, To be conservative, we want to factor in a context
      93                 :            :          * switch on top (due to ksoftirqd).
      94                 :            :          */
      95                 :          0 :         set(uncore, GEN9_MEDIA_PG_IDLE_HYSTERESIS, 60);
      96                 :          0 :         set(uncore, GEN9_RENDER_PG_IDLE_HYSTERESIS, 60);
      97                 :            : 
      98                 :            :         /* 3a: Enable RC6 */
      99                 :          0 :         rc6->ctl_enable =
     100                 :            :                 GEN6_RC_CTL_HW_ENABLE |
     101                 :            :                 GEN6_RC_CTL_RC6_ENABLE |
     102                 :            :                 GEN6_RC_CTL_EI_MODE(1);
     103                 :            : 
     104                 :          0 :         set(uncore, GEN9_PG_ENABLE,
     105                 :            :             GEN9_RENDER_PG_ENABLE |
     106                 :            :             GEN9_MEDIA_PG_ENABLE |
     107                 :            :             GEN11_MEDIA_SAMPLER_PG_ENABLE);
     108                 :          0 : }
     109                 :            : 
     110                 :          0 : static void gen9_rc6_enable(struct intel_rc6 *rc6)
     111                 :            : {
     112                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     113                 :          0 :         struct intel_engine_cs *engine;
     114                 :          0 :         enum intel_engine_id id;
     115                 :          0 :         u32 rc6_mode;
     116                 :            : 
     117                 :            :         /* 2b: Program RC6 thresholds.*/
     118         [ #  # ]:          0 :         if (INTEL_GEN(rc6_to_i915(rc6)) >= 10) {
     119                 :          0 :                 set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16 | 85);
     120                 :          0 :                 set(uncore, GEN10_MEDIA_WAKE_RATE_LIMIT, 150);
     121         [ #  # ]:          0 :         } else if (IS_SKYLAKE(rc6_to_i915(rc6))) {
     122                 :            :                 /*
     123                 :            :                  * WaRsDoubleRc6WrlWithCoarsePowerGating:skl Doubling WRL only
     124                 :            :                  * when CPG is enabled
     125                 :            :                  */
     126                 :          0 :                 set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 108 << 16);
     127                 :            :         } else {
     128                 :          0 :                 set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16);
     129                 :            :         }
     130                 :            : 
     131                 :          0 :         set(uncore, GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */
     132                 :          0 :         set(uncore, GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */
     133   [ #  #  #  # ]:          0 :         for_each_engine(engine, rc6_to_gt(rc6), id)
     134                 :          0 :                 set(uncore, RING_MAX_IDLE(engine->mmio_base), 10);
     135                 :            : 
     136                 :          0 :         set(uncore, GUC_MAX_IDLE_COUNT, 0xA);
     137                 :            : 
     138                 :          0 :         set(uncore, GEN6_RC_SLEEP, 0);
     139                 :            : 
     140                 :            :         /*
     141                 :            :          * 2c: Program Coarse Power Gating Policies.
     142                 :            :          *
     143                 :            :          * Bspec's guidance is to use 25us (really 25 * 1280ns) here. What we
     144                 :            :          * use instead is a more conservative estimate for the maximum time
     145                 :            :          * it takes us to service a CS interrupt and submit a new ELSP - that
     146                 :            :          * is the time which the GPU is idle waiting for the CPU to select the
     147                 :            :          * next request to execute. If the idle hysteresis is less than that
     148                 :            :          * interrupt service latency, the hardware will automatically gate
     149                 :            :          * the power well and we will then incur the wake up cost on top of
     150                 :            :          * the service latency. A similar guide from plane_state is that we
     151                 :            :          * do not want the enable hysteresis to less than the wakeup latency.
     152                 :            :          *
     153                 :            :          * igt/gem_exec_nop/sequential provides a rough estimate for the
     154                 :            :          * service latency, and puts it around 10us for Broadwell (and other
     155                 :            :          * big core) and around 40us for Broxton (and other low power cores).
     156                 :            :          * [Note that for legacy ringbuffer submission, this is less than 1us!]
     157                 :            :          * However, the wakeup latency on Broxton is closer to 100us. To be
     158                 :            :          * conservative, we have to factor in a context switch on top (due
     159                 :            :          * to ksoftirqd).
     160                 :            :          */
     161                 :          0 :         set(uncore, GEN9_MEDIA_PG_IDLE_HYSTERESIS, 250);
     162                 :          0 :         set(uncore, GEN9_RENDER_PG_IDLE_HYSTERESIS, 250);
     163                 :            : 
     164                 :            :         /* 3a: Enable RC6 */
     165                 :          0 :         set(uncore, GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */
     166                 :            : 
     167                 :            :         /* WaRsUseTimeoutMode:cnl (pre-prod) */
     168   [ #  #  #  # ]:          0 :         if (IS_CNL_REVID(rc6_to_i915(rc6), CNL_REVID_A0, CNL_REVID_C0))
     169                 :            :                 rc6_mode = GEN7_RC_CTL_TO_MODE;
     170                 :            :         else
     171                 :            :                 rc6_mode = GEN6_RC_CTL_EI_MODE(1);
     172                 :            : 
     173                 :          0 :         rc6->ctl_enable =
     174                 :            :                 GEN6_RC_CTL_HW_ENABLE |
     175                 :          0 :                 GEN6_RC_CTL_RC6_ENABLE |
     176                 :            :                 rc6_mode;
     177                 :            : 
     178                 :            :         /*
     179                 :            :          * WaRsDisableCoarsePowerGating:skl,cnl
     180                 :            :          *   - Render/Media PG need to be disabled with RC6.
     181                 :            :          */
     182   [ #  #  #  #  :          0 :         if (!NEEDS_WaRsDisableCoarsePowerGating(rc6_to_i915(rc6)))
          #  #  #  #  #  
                      # ]
     183                 :          0 :                 set(uncore, GEN9_PG_ENABLE,
     184                 :            :                     GEN9_RENDER_PG_ENABLE | GEN9_MEDIA_PG_ENABLE);
     185                 :          0 : }
     186                 :            : 
     187                 :          0 : static void gen8_rc6_enable(struct intel_rc6 *rc6)
     188                 :            : {
     189                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     190                 :          0 :         struct intel_engine_cs *engine;
     191                 :          0 :         enum intel_engine_id id;
     192                 :            : 
     193                 :            :         /* 2b: Program RC6 thresholds.*/
     194                 :          0 :         set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16);
     195                 :          0 :         set(uncore, GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */
     196                 :          0 :         set(uncore, GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */
     197   [ #  #  #  # ]:          0 :         for_each_engine(engine, rc6_to_gt(rc6), id)
     198                 :          0 :                 set(uncore, RING_MAX_IDLE(engine->mmio_base), 10);
     199                 :          0 :         set(uncore, GEN6_RC_SLEEP, 0);
     200                 :          0 :         set(uncore, GEN6_RC6_THRESHOLD, 625); /* 800us/1.28 for TO */
     201                 :            : 
     202                 :            :         /* 3: Enable RC6 */
     203                 :          0 :         rc6->ctl_enable =
     204                 :            :             GEN6_RC_CTL_HW_ENABLE |
     205                 :            :             GEN7_RC_CTL_TO_MODE |
     206                 :            :             GEN6_RC_CTL_RC6_ENABLE;
     207                 :          0 : }
     208                 :            : 
     209                 :          0 : static void gen6_rc6_enable(struct intel_rc6 *rc6)
     210                 :            : {
     211                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     212                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     213                 :          0 :         struct intel_engine_cs *engine;
     214                 :          0 :         enum intel_engine_id id;
     215                 :          0 :         u32 rc6vids, rc6_mask;
     216                 :          0 :         int ret;
     217                 :            : 
     218                 :          0 :         set(uncore, GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
     219                 :          0 :         set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
     220                 :          0 :         set(uncore, GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
     221                 :          0 :         set(uncore, GEN6_RC_EVALUATION_INTERVAL, 125000);
     222                 :          0 :         set(uncore, GEN6_RC_IDLE_HYSTERSIS, 25);
     223                 :            : 
     224   [ #  #  #  # ]:          0 :         for_each_engine(engine, rc6_to_gt(rc6), id)
     225                 :          0 :                 set(uncore, RING_MAX_IDLE(engine->mmio_base), 10);
     226                 :            : 
     227                 :          0 :         set(uncore, GEN6_RC_SLEEP, 0);
     228                 :          0 :         set(uncore, GEN6_RC1e_THRESHOLD, 1000);
     229         [ #  # ]:          0 :         if (IS_IVYBRIDGE(i915))
     230                 :          0 :                 set(uncore, GEN6_RC6_THRESHOLD, 125000);
     231                 :            :         else
     232                 :          0 :                 set(uncore, GEN6_RC6_THRESHOLD, 50000);
     233                 :          0 :         set(uncore, GEN6_RC6p_THRESHOLD, 150000);
     234                 :          0 :         set(uncore, GEN6_RC6pp_THRESHOLD, 64000); /* unused */
     235                 :            : 
     236                 :            :         /* We don't use those on Haswell */
     237                 :          0 :         rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
     238         [ #  # ]:          0 :         if (HAS_RC6p(i915))
     239                 :          0 :                 rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
     240                 :          0 :         if (HAS_RC6pp(i915))
     241                 :            :                 rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
     242                 :          0 :         rc6->ctl_enable =
     243                 :            :             rc6_mask |
     244                 :          0 :             GEN6_RC_CTL_EI_MODE(1) |
     245                 :            :             GEN6_RC_CTL_HW_ENABLE;
     246                 :            : 
     247                 :          0 :         rc6vids = 0;
     248                 :          0 :         ret = sandybridge_pcode_read(i915, GEN6_PCODE_READ_RC6VIDS,
     249                 :            :                                      &rc6vids, NULL);
     250   [ #  #  #  # ]:          0 :         if (IS_GEN(i915, 6) && ret) {
     251                 :          0 :                 DRM_DEBUG_DRIVER("Couldn't check for BIOS workaround\n");
     252         [ #  # ]:          0 :         } else if (IS_GEN(i915, 6) &&
     253         [ #  # ]:          0 :                    (GEN6_DECODE_RC6_VID(rc6vids & 0xff) < 450)) {
     254                 :          0 :                 DRM_DEBUG_DRIVER("You should update your BIOS. Correcting minimum rc6 voltage (%dmV->%dmV)\n",
     255                 :            :                                  GEN6_DECODE_RC6_VID(rc6vids & 0xff), 450);
     256                 :          0 :                 rc6vids &= 0xffff00;
     257                 :          0 :                 rc6vids |= GEN6_ENCODE_RC6_VID(450);
     258                 :          0 :                 ret = sandybridge_pcode_write(i915, GEN6_PCODE_WRITE_RC6VIDS, rc6vids);
     259         [ #  # ]:          0 :                 if (ret)
     260                 :          0 :                         DRM_ERROR("Couldn't fix incorrect rc6 voltage\n");
     261                 :            :         }
     262                 :          0 : }
     263                 :            : 
     264                 :            : /* Check that the pcbr address is not empty. */
     265                 :          0 : static int chv_rc6_init(struct intel_rc6 *rc6)
     266                 :            : {
     267                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     268                 :          0 :         resource_size_t pctx_paddr, paddr;
     269                 :          0 :         resource_size_t pctx_size = 32 * SZ_1K;
     270                 :          0 :         u32 pcbr;
     271                 :            : 
     272                 :          0 :         pcbr = intel_uncore_read(uncore, VLV_PCBR);
     273         [ #  # ]:          0 :         if ((pcbr >> VLV_PCBR_ADDR_SHIFT) == 0) {
     274                 :          0 :                 DRM_DEBUG_DRIVER("BIOS didn't set up PCBR, fixing up\n");
     275                 :          0 :                 paddr = rc6_to_i915(rc6)->dsm.end + 1 - pctx_size;
     276                 :          0 :                 GEM_BUG_ON(paddr > U32_MAX);
     277                 :            : 
     278                 :          0 :                 pctx_paddr = (paddr & ~4095);
     279                 :          0 :                 intel_uncore_write(uncore, VLV_PCBR, pctx_paddr);
     280                 :            :         }
     281                 :            : 
     282                 :          0 :         return 0;
     283                 :            : }
     284                 :            : 
     285                 :          0 : static int vlv_rc6_init(struct intel_rc6 *rc6)
     286                 :            : {
     287                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     288                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     289                 :          0 :         struct drm_i915_gem_object *pctx;
     290                 :          0 :         resource_size_t pctx_paddr;
     291                 :          0 :         resource_size_t pctx_size = 24 * SZ_1K;
     292                 :          0 :         u32 pcbr;
     293                 :            : 
     294                 :          0 :         pcbr = intel_uncore_read(uncore, VLV_PCBR);
     295         [ #  # ]:          0 :         if (pcbr) {
     296                 :            :                 /* BIOS set it up already, grab the pre-alloc'd space */
     297                 :          0 :                 resource_size_t pcbr_offset;
     298                 :            : 
     299                 :          0 :                 pcbr_offset = (pcbr & ~4095) - i915->dsm.start;
     300                 :          0 :                 pctx = i915_gem_object_create_stolen_for_preallocated(i915,
     301                 :            :                                                                       pcbr_offset,
     302                 :            :                                                                       I915_GTT_OFFSET_NONE,
     303                 :            :                                                                       pctx_size);
     304         [ #  # ]:          0 :                 if (IS_ERR(pctx))
     305                 :          0 :                         return PTR_ERR(pctx);
     306                 :            : 
     307                 :          0 :                 goto out;
     308                 :            :         }
     309                 :            : 
     310                 :          0 :         DRM_DEBUG_DRIVER("BIOS didn't set up PCBR, fixing up\n");
     311                 :            : 
     312                 :            :         /*
     313                 :            :          * From the Gunit register HAS:
     314                 :            :          * The Gfx driver is expected to program this register and ensure
     315                 :            :          * proper allocation within Gfx stolen memory.  For example, this
     316                 :            :          * register should be programmed such than the PCBR range does not
     317                 :            :          * overlap with other ranges, such as the frame buffer, protected
     318                 :            :          * memory, or any other relevant ranges.
     319                 :            :          */
     320                 :          0 :         pctx = i915_gem_object_create_stolen(i915, pctx_size);
     321         [ #  # ]:          0 :         if (IS_ERR(pctx)) {
     322                 :          0 :                 DRM_DEBUG("not enough stolen space for PCTX, disabling\n");
     323                 :          0 :                 return PTR_ERR(pctx);
     324                 :            :         }
     325                 :            : 
     326                 :          0 :         GEM_BUG_ON(range_overflows_t(u64,
     327                 :            :                                      i915->dsm.start,
     328                 :            :                                      pctx->stolen->start,
     329                 :            :                                      U32_MAX));
     330                 :          0 :         pctx_paddr = i915->dsm.start + pctx->stolen->start;
     331                 :          0 :         intel_uncore_write(uncore, VLV_PCBR, pctx_paddr);
     332                 :            : 
     333                 :          0 : out:
     334                 :          0 :         rc6->pctx = pctx;
     335                 :          0 :         return 0;
     336                 :            : }
     337                 :            : 
     338                 :          0 : static void chv_rc6_enable(struct intel_rc6 *rc6)
     339                 :            : {
     340                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     341                 :          0 :         struct intel_engine_cs *engine;
     342                 :          0 :         enum intel_engine_id id;
     343                 :            : 
     344                 :            :         /* 2a: Program RC6 thresholds.*/
     345                 :          0 :         set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16);
     346                 :          0 :         set(uncore, GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */
     347                 :          0 :         set(uncore, GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */
     348                 :            : 
     349   [ #  #  #  # ]:          0 :         for_each_engine(engine, rc6_to_gt(rc6), id)
     350                 :          0 :                 set(uncore, RING_MAX_IDLE(engine->mmio_base), 10);
     351                 :          0 :         set(uncore, GEN6_RC_SLEEP, 0);
     352                 :            : 
     353                 :            :         /* TO threshold set to 500 us (0x186 * 1.28 us) */
     354                 :          0 :         set(uncore, GEN6_RC6_THRESHOLD, 0x186);
     355                 :            : 
     356                 :            :         /* Allows RC6 residency counter to work */
     357                 :          0 :         set(uncore, VLV_COUNTER_CONTROL,
     358                 :          0 :             _MASKED_BIT_ENABLE(VLV_COUNT_RANGE_HIGH |
     359                 :            :                                VLV_MEDIA_RC6_COUNT_EN |
     360                 :            :                                VLV_RENDER_RC6_COUNT_EN));
     361                 :            : 
     362                 :            :         /* 3: Enable RC6 */
     363                 :          0 :         rc6->ctl_enable = GEN7_RC_CTL_TO_MODE;
     364                 :          0 : }
     365                 :            : 
     366                 :          0 : static void vlv_rc6_enable(struct intel_rc6 *rc6)
     367                 :            : {
     368                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     369                 :          0 :         struct intel_engine_cs *engine;
     370                 :          0 :         enum intel_engine_id id;
     371                 :            : 
     372                 :          0 :         set(uncore, GEN6_RC6_WAKE_RATE_LIMIT, 0x00280000);
     373                 :          0 :         set(uncore, GEN6_RC_EVALUATION_INTERVAL, 125000);
     374                 :          0 :         set(uncore, GEN6_RC_IDLE_HYSTERSIS, 25);
     375                 :            : 
     376   [ #  #  #  # ]:          0 :         for_each_engine(engine, rc6_to_gt(rc6), id)
     377                 :          0 :                 set(uncore, RING_MAX_IDLE(engine->mmio_base), 10);
     378                 :            : 
     379                 :          0 :         set(uncore, GEN6_RC6_THRESHOLD, 0x557);
     380                 :            : 
     381                 :            :         /* Allows RC6 residency counter to work */
     382                 :          0 :         set(uncore, VLV_COUNTER_CONTROL,
     383                 :          0 :             _MASKED_BIT_ENABLE(VLV_COUNT_RANGE_HIGH |
     384                 :            :                                VLV_MEDIA_RC0_COUNT_EN |
     385                 :            :                                VLV_RENDER_RC0_COUNT_EN |
     386                 :            :                                VLV_MEDIA_RC6_COUNT_EN |
     387                 :            :                                VLV_RENDER_RC6_COUNT_EN));
     388                 :            : 
     389                 :          0 :         rc6->ctl_enable =
     390                 :            :             GEN7_RC_CTL_TO_MODE | VLV_RC_CTL_CTX_RST_PARALLEL;
     391                 :          0 : }
     392                 :            : 
     393                 :          0 : static bool bxt_check_bios_rc6_setup(struct intel_rc6 *rc6)
     394                 :            : {
     395                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     396                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     397                 :          0 :         u32 rc6_ctx_base, rc_ctl, rc_sw_target;
     398                 :          0 :         bool enable_rc6 = true;
     399                 :            : 
     400                 :          0 :         rc_ctl = intel_uncore_read(uncore, GEN6_RC_CONTROL);
     401                 :          0 :         rc_sw_target = intel_uncore_read(uncore, GEN6_RC_STATE);
     402                 :          0 :         rc_sw_target &= RC_SW_TARGET_STATE_MASK;
     403                 :          0 :         rc_sw_target >>= RC_SW_TARGET_STATE_SHIFT;
     404   [ #  #  #  # ]:          0 :         DRM_DEBUG_DRIVER("BIOS enabled RC states: "
     405                 :            :                          "HW_CTRL %s HW_RC6 %s SW_TARGET_STATE %x\n",
     406                 :            :                          onoff(rc_ctl & GEN6_RC_CTL_HW_ENABLE),
     407                 :            :                          onoff(rc_ctl & GEN6_RC_CTL_RC6_ENABLE),
     408                 :            :                          rc_sw_target);
     409                 :            : 
     410         [ #  # ]:          0 :         if (!(intel_uncore_read(uncore, RC6_LOCATION) & RC6_CTX_IN_DRAM)) {
     411                 :          0 :                 DRM_DEBUG_DRIVER("RC6 Base location not set properly.\n");
     412                 :          0 :                 enable_rc6 = false;
     413                 :            :         }
     414                 :            : 
     415                 :            :         /*
     416                 :            :          * The exact context size is not known for BXT, so assume a page size
     417                 :            :          * for this check.
     418                 :            :          */
     419                 :          0 :         rc6_ctx_base =
     420                 :          0 :                 intel_uncore_read(uncore, RC6_CTX_BASE) & RC6_CTX_BASE_MASK;
     421         [ #  # ]:          0 :         if (!(rc6_ctx_base >= i915->dsm_reserved.start &&
     422         [ #  # ]:          0 :               rc6_ctx_base + PAGE_SIZE < i915->dsm_reserved.end)) {
     423                 :          0 :                 DRM_DEBUG_DRIVER("RC6 Base address not as expected.\n");
     424                 :          0 :                 enable_rc6 = false;
     425                 :            :         }
     426                 :            : 
     427         [ #  # ]:          0 :         if (!((intel_uncore_read(uncore, PWRCTX_MAXCNT_RCSUNIT) & IDLE_TIME_MASK) > 1 &&
     428         [ #  # ]:          0 :               (intel_uncore_read(uncore, PWRCTX_MAXCNT_VCSUNIT0) & IDLE_TIME_MASK) > 1 &&
     429         [ #  # ]:          0 :               (intel_uncore_read(uncore, PWRCTX_MAXCNT_BCSUNIT) & IDLE_TIME_MASK) > 1 &&
     430         [ #  # ]:          0 :               (intel_uncore_read(uncore, PWRCTX_MAXCNT_VECSUNIT) & IDLE_TIME_MASK) > 1)) {
     431                 :          0 :                 DRM_DEBUG_DRIVER("Engine Idle wait time not set properly.\n");
     432                 :          0 :                 enable_rc6 = false;
     433                 :            :         }
     434                 :            : 
     435         [ #  # ]:          0 :         if (!intel_uncore_read(uncore, GEN8_PUSHBUS_CONTROL) ||
     436         [ #  # ]:          0 :             !intel_uncore_read(uncore, GEN8_PUSHBUS_ENABLE) ||
     437         [ #  # ]:          0 :             !intel_uncore_read(uncore, GEN8_PUSHBUS_SHIFT)) {
     438                 :          0 :                 DRM_DEBUG_DRIVER("Pushbus not setup properly.\n");
     439                 :          0 :                 enable_rc6 = false;
     440                 :            :         }
     441                 :            : 
     442         [ #  # ]:          0 :         if (!intel_uncore_read(uncore, GEN6_GFXPAUSE)) {
     443                 :          0 :                 DRM_DEBUG_DRIVER("GFX pause not setup properly.\n");
     444                 :          0 :                 enable_rc6 = false;
     445                 :            :         }
     446                 :            : 
     447         [ #  # ]:          0 :         if (!intel_uncore_read(uncore, GEN8_MISC_CTRL0)) {
     448                 :          0 :                 DRM_DEBUG_DRIVER("GPM control not setup properly.\n");
     449                 :          0 :                 enable_rc6 = false;
     450                 :            :         }
     451                 :            : 
     452                 :          0 :         return enable_rc6;
     453                 :            : }
     454                 :            : 
     455                 :          0 : static bool rc6_supported(struct intel_rc6 *rc6)
     456                 :            : {
     457                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     458                 :            : 
     459         [ #  # ]:          0 :         if (!HAS_RC6(i915))
     460                 :            :                 return false;
     461                 :            : 
     462         [ #  # ]:          0 :         if (intel_vgpu_active(i915))
     463                 :            :                 return false;
     464                 :            : 
     465         [ #  # ]:          0 :         if (is_mock_gt(rc6_to_gt(rc6)))
     466                 :            :                 return false;
     467                 :            : 
     468   [ #  #  #  #  :          0 :         if (IS_GEN9_LP(i915) && !bxt_check_bios_rc6_setup(rc6)) {
                   #  # ]
     469                 :          0 :                 dev_notice(i915->drm.dev,
     470                 :            :                            "RC6 and powersaving disabled by BIOS\n");
     471                 :          0 :                 return false;
     472                 :            :         }
     473                 :            : 
     474                 :            :         return true;
     475                 :            : }
     476                 :            : 
     477                 :          0 : static void rpm_get(struct intel_rc6 *rc6)
     478                 :            : {
     479                 :          0 :         GEM_BUG_ON(rc6->wakeref);
     480                 :          0 :         pm_runtime_get_sync(&rc6_to_i915(rc6)->drm.pdev->dev);
     481                 :          0 :         rc6->wakeref = true;
     482                 :            : }
     483                 :            : 
     484                 :          0 : static void rpm_put(struct intel_rc6 *rc6)
     485                 :            : {
     486                 :          0 :         GEM_BUG_ON(!rc6->wakeref);
     487                 :          0 :         pm_runtime_put(&rc6_to_i915(rc6)->drm.pdev->dev);
     488                 :          0 :         rc6->wakeref = false;
     489                 :          0 : }
     490                 :            : 
     491                 :          0 : static bool pctx_corrupted(struct intel_rc6 *rc6)
     492                 :            : {
     493                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     494                 :            : 
     495   [ #  #  #  # ]:          0 :         if (!NEEDS_RC6_CTX_CORRUPTION_WA(i915))
     496                 :            :                 return false;
     497                 :            : 
     498         [ #  # ]:          0 :         if (intel_uncore_read(rc6_to_uncore(rc6), GEN8_RC6_CTX_INFO))
     499                 :            :                 return false;
     500                 :            : 
     501                 :          0 :         dev_notice(i915->drm.dev,
     502                 :            :                    "RC6 context corruption, disabling runtime power management\n");
     503                 :          0 :         return true;
     504                 :            : }
     505                 :            : 
     506                 :          0 : static void __intel_rc6_disable(struct intel_rc6 *rc6)
     507                 :            : {
     508                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     509                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     510                 :            : 
     511                 :          0 :         intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
     512         [ #  # ]:          0 :         if (INTEL_GEN(i915) >= 9)
     513                 :          0 :                 set(uncore, GEN9_PG_ENABLE, 0);
     514                 :          0 :         set(uncore, GEN6_RC_CONTROL, 0);
     515                 :          0 :         set(uncore, GEN6_RC_STATE, 0);
     516                 :          0 :         intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
     517                 :          0 : }
     518                 :            : 
     519                 :          0 : void intel_rc6_init(struct intel_rc6 *rc6)
     520                 :            : {
     521                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     522                 :          0 :         int err;
     523                 :            : 
     524                 :            :         /* Disable runtime-pm until we can save the GPU state with rc6 pctx */
     525                 :          0 :         rpm_get(rc6);
     526                 :            : 
     527         [ #  # ]:          0 :         if (!rc6_supported(rc6))
     528                 :            :                 return;
     529                 :            : 
     530         [ #  # ]:          0 :         if (IS_CHERRYVIEW(i915))
     531                 :          0 :                 err = chv_rc6_init(rc6);
     532         [ #  # ]:          0 :         else if (IS_VALLEYVIEW(i915))
     533                 :          0 :                 err = vlv_rc6_init(rc6);
     534                 :            :         else
     535                 :            :                 err = 0;
     536                 :            : 
     537                 :            :         /* Sanitize rc6, ensure it is disabled before we are ready. */
     538                 :          0 :         __intel_rc6_disable(rc6);
     539                 :            : 
     540                 :          0 :         rc6->supported = err == 0;
     541                 :            : }
     542                 :            : 
     543                 :          0 : void intel_rc6_sanitize(struct intel_rc6 *rc6)
     544                 :            : {
     545         [ #  # ]:          0 :         if (rc6->enabled) { /* unbalanced suspend/resume */
     546                 :          0 :                 rpm_get(rc6);
     547                 :          0 :                 rc6->enabled = false;
     548                 :            :         }
     549                 :            : 
     550         [ #  # ]:          0 :         if (rc6->supported)
     551                 :          0 :                 __intel_rc6_disable(rc6);
     552                 :          0 : }
     553                 :            : 
     554                 :          0 : void intel_rc6_enable(struct intel_rc6 *rc6)
     555                 :            : {
     556                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     557                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     558                 :            : 
     559         [ #  # ]:          0 :         if (!rc6->supported)
     560                 :            :                 return;
     561                 :            : 
     562                 :          0 :         GEM_BUG_ON(rc6->enabled);
     563                 :            : 
     564                 :          0 :         intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
     565                 :            : 
     566         [ #  # ]:          0 :         if (IS_CHERRYVIEW(i915))
     567                 :          0 :                 chv_rc6_enable(rc6);
     568         [ #  # ]:          0 :         else if (IS_VALLEYVIEW(i915))
     569                 :          0 :                 vlv_rc6_enable(rc6);
     570         [ #  # ]:          0 :         else if (INTEL_GEN(i915) >= 11)
     571                 :          0 :                 gen11_rc6_enable(rc6);
     572         [ #  # ]:          0 :         else if (INTEL_GEN(i915) >= 9)
     573                 :          0 :                 gen9_rc6_enable(rc6);
     574         [ #  # ]:          0 :         else if (IS_BROADWELL(i915))
     575                 :          0 :                 gen8_rc6_enable(rc6);
     576         [ #  # ]:          0 :         else if (INTEL_GEN(i915) >= 6)
     577                 :          0 :                 gen6_rc6_enable(rc6);
     578                 :            : 
     579                 :          0 :         rc6->manual = rc6->ctl_enable & GEN6_RC_CTL_RC6_ENABLE;
     580   [ #  #  #  # ]:          0 :         if (NEEDS_RC6_CTX_CORRUPTION_WA(i915))
     581                 :          0 :                 rc6->ctl_enable = 0;
     582                 :            : 
     583                 :          0 :         intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
     584                 :            : 
     585         [ #  # ]:          0 :         if (unlikely(pctx_corrupted(rc6)))
     586                 :            :                 return;
     587                 :            : 
     588                 :            :         /* rc6 is ready, runtime-pm is go! */
     589                 :          0 :         rpm_put(rc6);
     590                 :          0 :         rc6->enabled = true;
     591                 :            : }
     592                 :            : 
     593                 :          0 : void intel_rc6_unpark(struct intel_rc6 *rc6)
     594                 :            : {
     595                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     596                 :            : 
     597         [ #  # ]:          0 :         if (!rc6->enabled)
     598                 :            :                 return;
     599                 :            : 
     600                 :            :         /* Restore HW timers for automatic RC6 entry while busy */
     601                 :          0 :         set(uncore, GEN6_RC_CONTROL, rc6->ctl_enable);
     602                 :            : }
     603                 :            : 
     604                 :          0 : void intel_rc6_park(struct intel_rc6 *rc6)
     605                 :            : {
     606                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     607                 :            : 
     608         [ #  # ]:          0 :         if (!rc6->enabled)
     609                 :            :                 return;
     610                 :            : 
     611         [ #  # ]:          0 :         if (unlikely(pctx_corrupted(rc6))) {
     612                 :          0 :                 intel_rc6_disable(rc6);
     613                 :          0 :                 return;
     614                 :            :         }
     615                 :            : 
     616         [ #  # ]:          0 :         if (!rc6->manual)
     617                 :            :                 return;
     618                 :            : 
     619                 :            :         /* Turn off the HW timers and go directly to rc6 */
     620                 :          0 :         set(uncore, GEN6_RC_CONTROL, GEN6_RC_CTL_RC6_ENABLE);
     621                 :          0 :         set(uncore, GEN6_RC_STATE, 0x4 << RC_SW_TARGET_STATE_SHIFT);
     622                 :            : }
     623                 :            : 
     624                 :          0 : void intel_rc6_disable(struct intel_rc6 *rc6)
     625                 :            : {
     626         [ #  # ]:          0 :         if (!rc6->enabled)
     627                 :            :                 return;
     628                 :            : 
     629                 :          0 :         rpm_get(rc6);
     630                 :          0 :         rc6->enabled = false;
     631                 :            : 
     632                 :          0 :         __intel_rc6_disable(rc6);
     633                 :            : }
     634                 :            : 
     635                 :          0 : void intel_rc6_fini(struct intel_rc6 *rc6)
     636                 :            : {
     637                 :          0 :         struct drm_i915_gem_object *pctx;
     638                 :            : 
     639                 :          0 :         intel_rc6_disable(rc6);
     640                 :            : 
     641                 :          0 :         pctx = fetch_and_zero(&rc6->pctx);
     642         [ #  # ]:          0 :         if (pctx)
     643                 :          0 :                 i915_gem_object_put(pctx);
     644                 :            : 
     645         [ #  # ]:          0 :         if (rc6->wakeref)
     646                 :          0 :                 rpm_put(rc6);
     647                 :          0 : }
     648                 :            : 
     649                 :          0 : static u64 vlv_residency_raw(struct intel_uncore *uncore, const i915_reg_t reg)
     650                 :            : {
     651                 :          0 :         u32 lower, upper, tmp;
     652                 :          0 :         int loop = 2;
     653                 :            : 
     654                 :            :         /*
     655                 :            :          * The register accessed do not need forcewake. We borrow
     656                 :            :          * uncore lock to prevent concurrent access to range reg.
     657                 :            :          */
     658                 :          0 :         lockdep_assert_held(&uncore->lock);
     659                 :            : 
     660                 :            :         /*
     661                 :            :          * vlv and chv residency counters are 40 bits in width.
     662                 :            :          * With a control bit, we can choose between upper or lower
     663                 :            :          * 32bit window into this counter.
     664                 :            :          *
     665                 :            :          * Although we always use the counter in high-range mode elsewhere,
     666                 :            :          * userspace may attempt to read the value before rc6 is initialised,
     667                 :            :          * before we have set the default VLV_COUNTER_CONTROL value. So always
     668                 :            :          * set the high bit to be safe.
     669                 :            :          */
     670                 :          0 :         set(uncore, VLV_COUNTER_CONTROL,
     671                 :          0 :             _MASKED_BIT_ENABLE(VLV_COUNT_RANGE_HIGH));
     672                 :          0 :         upper = intel_uncore_read_fw(uncore, reg);
     673                 :          0 :         do {
     674                 :          0 :                 tmp = upper;
     675                 :            : 
     676                 :          0 :                 set(uncore, VLV_COUNTER_CONTROL,
     677                 :          0 :                     _MASKED_BIT_DISABLE(VLV_COUNT_RANGE_HIGH));
     678                 :          0 :                 lower = intel_uncore_read_fw(uncore, reg);
     679                 :            : 
     680                 :          0 :                 set(uncore, VLV_COUNTER_CONTROL,
     681                 :          0 :                     _MASKED_BIT_ENABLE(VLV_COUNT_RANGE_HIGH));
     682                 :          0 :                 upper = intel_uncore_read_fw(uncore, reg);
     683   [ #  #  #  # ]:          0 :         } while (upper != tmp && --loop);
     684                 :            : 
     685                 :            :         /*
     686                 :            :          * Everywhere else we always use VLV_COUNTER_CONTROL with the
     687                 :            :          * VLV_COUNT_RANGE_HIGH bit set - so it is safe to leave it set
     688                 :            :          * now.
     689                 :            :          */
     690                 :            : 
     691                 :          0 :         return lower | (u64)upper << 8;
     692                 :            : }
     693                 :            : 
     694                 :          0 : u64 intel_rc6_residency_ns(struct intel_rc6 *rc6, const i915_reg_t reg)
     695                 :            : {
     696                 :          0 :         struct drm_i915_private *i915 = rc6_to_i915(rc6);
     697                 :          0 :         struct intel_uncore *uncore = rc6_to_uncore(rc6);
     698                 :          0 :         u64 time_hw, prev_hw, overflow_hw;
     699                 :          0 :         unsigned int fw_domains;
     700                 :          0 :         unsigned long flags;
     701                 :          0 :         unsigned int i;
     702                 :          0 :         u32 mul, div;
     703                 :            : 
     704         [ #  # ]:          0 :         if (!rc6->supported)
     705                 :            :                 return 0;
     706                 :            : 
     707                 :            :         /*
     708                 :            :          * Store previous hw counter values for counter wrap-around handling.
     709                 :            :          *
     710                 :            :          * There are only four interesting registers and they live next to each
     711                 :            :          * other so we can use the relative address, compared to the smallest
     712                 :            :          * one as the index into driver storage.
     713                 :            :          */
     714         [ #  # ]:          0 :         i = (i915_mmio_reg_offset(reg) -
     715                 :            :              i915_mmio_reg_offset(GEN6_GT_GFX_RC6_LOCKED)) / sizeof(u32);
     716   [ #  #  #  #  :          0 :         if (WARN_ON_ONCE(i >= ARRAY_SIZE(rc6->cur_residency)))
                   #  # ]
     717                 :            :                 return 0;
     718                 :            : 
     719                 :          0 :         fw_domains = intel_uncore_forcewake_for_reg(uncore, reg, FW_REG_READ);
     720                 :            : 
     721                 :          0 :         spin_lock_irqsave(&uncore->lock, flags);
     722                 :          0 :         intel_uncore_forcewake_get__locked(uncore, fw_domains);
     723                 :            : 
     724                 :            :         /* On VLV and CHV, residency time is in CZ units rather than 1.28us */
     725   [ #  #  #  # ]:          0 :         if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
     726                 :          0 :                 mul = 1000000;
     727                 :          0 :                 div = i915->czclk_freq;
     728                 :          0 :                 overflow_hw = BIT_ULL(40);
     729                 :          0 :                 time_hw = vlv_residency_raw(uncore, reg);
     730                 :            :         } else {
     731                 :            :                 /* 833.33ns units on Gen9LP, 1.28us elsewhere. */
     732   [ #  #  #  # ]:          0 :                 if (IS_GEN9_LP(i915)) {
     733                 :            :                         mul = 10000;
     734                 :            :                         div = 12;
     735                 :            :                 } else {
     736                 :          0 :                         mul = 1280;
     737                 :          0 :                         div = 1;
     738                 :            :                 }
     739                 :            : 
     740                 :          0 :                 overflow_hw = BIT_ULL(32);
     741                 :          0 :                 time_hw = intel_uncore_read_fw(uncore, reg);
     742                 :            :         }
     743                 :            : 
     744                 :            :         /*
     745                 :            :          * Counter wrap handling.
     746                 :            :          *
     747                 :            :          * But relying on a sufficient frequency of queries otherwise counters
     748                 :            :          * can still wrap.
     749                 :            :          */
     750                 :          0 :         prev_hw = rc6->prev_hw_residency[i];
     751                 :          0 :         rc6->prev_hw_residency[i] = time_hw;
     752                 :            : 
     753                 :            :         /* RC6 delta from last sample. */
     754         [ #  # ]:          0 :         if (time_hw >= prev_hw)
     755                 :          0 :                 time_hw -= prev_hw;
     756                 :            :         else
     757                 :          0 :                 time_hw += overflow_hw - prev_hw;
     758                 :            : 
     759                 :            :         /* Add delta to RC6 extended raw driver copy. */
     760                 :          0 :         time_hw += rc6->cur_residency[i];
     761                 :          0 :         rc6->cur_residency[i] = time_hw;
     762                 :            : 
     763                 :          0 :         intel_uncore_forcewake_put__locked(uncore, fw_domains);
     764                 :          0 :         spin_unlock_irqrestore(&uncore->lock, flags);
     765                 :            : 
     766                 :          0 :         return mul_u64_u32_div(time_hw, mul, div);
     767                 :            : }
     768                 :            : 
     769                 :          0 : u64 intel_rc6_residency_us(struct intel_rc6 *rc6, i915_reg_t reg)
     770                 :            : {
     771                 :          0 :         return DIV_ROUND_UP_ULL(intel_rc6_residency_ns(rc6, reg), 1000);
     772                 :            : }
     773                 :            : 
     774                 :            : #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
     775                 :            : #include "selftest_rc6.c"
     776                 :            : #endif

Generated by: LCOV version 1.14