Backmerge tag 'v4.14-rc7' into drm-next
authorDave Airlie <airlied@redhat.com>
Thu, 2 Nov 2017 02:40:41 +0000 (12:40 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 2 Nov 2017 02:40:41 +0000 (12:40 +1000)
Linux 4.14-rc7

Requested by Ben Skeggs for nouveau to avoid major conflicts,
and things were getting a bit conflicty already, esp around amdgpu
reverts.

18 files changed:
1  2 
MAINTAINERS
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/gvt/execlist.c
drivers/gpu/drm/i915/gvt/scheduler.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_engine_cs.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/msm/dsi/dsi_host.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_rd.c

diff --combined MAINTAINERS
index fe121ea1ab99ed2ceb4f38d34122cd5e6d8a8cc5,af0cb69f6a3edf8a483b9091c23dfbc6f54b6503..0525701befd03d78f94b6fc3bc5548dad9a5e252
@@@ -4366,12 -4366,6 +4366,12 @@@ T:    git git://anongit.freedesktop.org/dr
  S:    Maintained
  F:    drivers/gpu/drm/bochs/
  
 +DRM DRIVER FOR FARADAY TVE200 TV ENCODER
 +M:    Linus Walleij <linus.walleij@linaro.org>
 +T:    git git://anongit.freedesktop.org/drm/drm-misc
 +S:    Maintained
 +F:    drivers/gpu/drm/tve200/
 +
  DRM DRIVER FOR INTEL I810 VIDEO CARDS
  S:    Orphan / Obsolete
  F:    drivers/gpu/drm/i810/
@@@ -4515,7 -4509,7 +4515,7 @@@ L:      dri-devel@lists.freedesktop.or
  S:    Supported
  F:    drivers/gpu/drm/sun4i/
  F:    Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git
 +T:    git git://anongit.freedesktop.org/drm/drm-misc
  
  DRM DRIVERS FOR AMLOGIC SOCS
  M:    Neil Armstrong <narmstrong@baylibre.com>
@@@ -4699,7 -4693,7 +4699,7 @@@ T:      git git://anongit.freedesktop.org/dr
  DRM PANEL DRIVERS
  M:    Thierry Reding <thierry.reding@gmail.com>
  L:    dri-devel@lists.freedesktop.org
 -T:    git git://anongit.freedesktop.org/tegra/linux.git
 +T:    git git://anongit.freedesktop.org/drm/drm-misc
  S:    Maintained
  F:    drivers/gpu/drm/drm_panel.c
  F:    drivers/gpu/drm/panel/
@@@ -5265,7 -5259,8 +5265,8 @@@ S:      Maintaine
  F:    drivers/iommu/exynos-iommu.c
  
  EZchip NPS platform support
- M:    Noam Camus <noamc@ezchip.com>
+ M:    Elad Kanfi <eladkan@mellanox.com>
+ M:    Vineet Gupta <vgupta@synopsys.com>
  S:    Supported
  F:    arch/arc/plat-eznps
  F:    arch/arc/boot/dts/eznps.dts
@@@ -5351,9 -5346,7 +5352,7 @@@ M:      "J. Bruce Fields" <bfields@fieldses.
  L:    linux-fsdevel@vger.kernel.org
  S:    Maintained
  F:    include/linux/fcntl.h
- F:    include/linux/fs.h
  F:    include/uapi/linux/fcntl.h
- F:    include/uapi/linux/fs.h
  F:    fs/fcntl.c
  F:    fs/locks.c
  
@@@ -5362,6 -5355,8 +5361,8 @@@ M:      Alexander Viro <viro@zeniv.linux.org
  L:    linux-fsdevel@vger.kernel.org
  S:    Maintained
  F:    fs/*
+ F:    include/linux/fs.h
+ F:    include/uapi/linux/fs.h
  
  FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
  M:    Riku Voipio <riku.voipio@iki.fi>
@@@ -5461,7 -5456,6 +5462,7 @@@ F:      drivers/net/wan/sdla.
  
  FRAMEBUFFER LAYER
  M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
 +L:    dri-devel@lists.freedesktop.org
  L:    linux-fbdev@vger.kernel.org
  T:    git git://github.com/bzolnier/linux.git
  Q:    http://patchwork.kernel.org/project/linux-fbdev/list/
@@@ -6745,7 -6739,7 +6746,7 @@@ F:      Documentation/devicetree/bindings/au
  F:    drivers/auxdisplay/img-ascii-lcd.c
  
  IMGTEC IR DECODER DRIVER
- M:    James Hogan <james.hogan@imgtec.com>
+ M:    James Hogan <jhogan@kernel.org>
  S:    Maintained
  F:    drivers/media/rc/img-ir/
  
@@@ -7569,7 -7563,7 +7570,7 @@@ F:      arch/arm64/include/asm/kvm
  F:    arch/arm64/kvm/
  
  KERNEL VIRTUAL MACHINE FOR MIPS (KVM/mips)
- M:    James Hogan <james.hogan@imgtec.com>
+ M:    James Hogan <jhogan@kernel.org>
  L:    linux-mips@linux-mips.org
  S:    Supported
  F:    arch/mips/include/uapi/asm/kvm*
@@@ -7577,7 -7571,7 +7578,7 @@@ F:      arch/mips/include/asm/kvm
  F:    arch/mips/kvm/
  
  KERNEL VIRTUAL MACHINE FOR POWERPC (KVM/powerpc)
- M:    Alexander Graf <agraf@suse.com>
+ M:    Paul Mackerras <paulus@ozlabs.org>
  L:    kvm-ppc@vger.kernel.org
  W:    http://www.linux-kvm.org/
  T:    git git://github.com/agraf/linux-2.6.git
@@@ -8271,6 -8265,12 +8272,12 @@@ L:    libertas-dev@lists.infradead.or
  S:    Orphan
  F:    drivers/net/wireless/marvell/libertas/
  
+ MARVELL MACCHIATOBIN SUPPORT
+ M:    Russell King <rmk@armlinux.org.uk>
+ L:    linux-arm-kernel@lists.infradead.org
+ S:    Maintained
+ F:    arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
  MARVELL MV643XX ETHERNET DRIVER
  M:    Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  L:    netdev@vger.kernel.org
@@@ -8892,7 -8892,7 +8899,7 @@@ F:      Documentation/devicetree/bindings/me
  T:    git git://linuxtv.org/media_tree.git
  
  METAG ARCHITECTURE
- M:    James Hogan <james.hogan@imgtec.com>
+ M:    James Hogan <jhogan@kernel.org>
  L:    linux-metag@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jhogan/metag.git
  S:    Odd Fixes
@@@ -9213,7 -9213,6 +9220,6 @@@ F:      include/linux/isicom.
  MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
  M:    Bin Liu <b-liu@ti.com>
  L:    linux-usb@vger.kernel.org
- T:    git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
  S:    Maintained
  F:    drivers/usb/musb/
  
@@@ -9361,7 -9360,7 +9367,7 @@@ NETWORK BLOCK DEVICE (NBD
  M:    Josef Bacik <jbacik@fb.com>
  S:    Maintained
  L:    linux-block@vger.kernel.org
- L:    nbd-general@lists.sourceforge.net
+ L:    nbd@other.debian.org
  F:    Documentation/blockdev/nbd.txt
  F:    drivers/block/nbd.c
  F:    include/uapi/linux/nbd.h
@@@ -10180,7 -10179,6 +10186,6 @@@ F:   Documentation/parport*.tx
  
  PARAVIRT_OPS INTERFACE
  M:    Juergen Gross <jgross@suse.com>
- M:    Chris Wright <chrisw@sous-sol.org>
  M:    Alok Kataria <akataria@vmware.com>
  M:    Rusty Russell <rusty@rustcorp.com.au>
  L:    virtualization@lists.linux-foundation.org
@@@ -10560,6 -10558,8 +10565,8 @@@ M:   Peter Zijlstra <peterz@infradead.org
  M:    Ingo Molnar <mingo@redhat.com>
  M:    Arnaldo Carvalho de Melo <acme@kernel.org>
  R:    Alexander Shishkin <alexander.shishkin@linux.intel.com>
+ R:    Jiri Olsa <jolsa@redhat.com>
+ R:    Namhyung Kim <namhyung@kernel.org>
  L:    linux-kernel@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
  S:    Supported
@@@ -12938,9 -12938,9 +12945,9 @@@ F:   drivers/mmc/host/dw_mmc
  SYNOPSYS HSDK RESET CONTROLLER DRIVER
  M:    Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
  S:    Supported
- F:    drivers/reset/reset-hsdk-v1.c
- F:    include/dt-bindings/reset/snps,hsdk-v1-reset.h
- F:    Documentation/devicetree/bindings/reset/snps,hsdk-v1-reset.txt
+ F:    drivers/reset/reset-hsdk.c
+ F:    include/dt-bindings/reset/snps,hsdk-reset.h
+ F:    Documentation/devicetree/bindings/reset/snps,hsdk-reset.txt
  
  SYSTEM CONFIGURATION (SYSCON)
  M:    Lee Jones <lee.jones@linaro.org>
index 71299c67c517a1e4a753c1e2bb0216c7c8857f8b,430a6b4dfac972f7780e04ac3fc8b1303086878e..2581543b35a79318ded40c3171b93183c0d4492d
@@@ -38,8 -38,6 +38,8 @@@
  #include "vi.h"
  
  static void uvd_v6_0_set_ring_funcs(struct amdgpu_device *adev);
 +static void uvd_v6_0_set_enc_ring_funcs(struct amdgpu_device *adev);
 +
  static void uvd_v6_0_set_irq_funcs(struct amdgpu_device *adev);
  static int uvd_v6_0_start(struct amdgpu_device *adev);
  static void uvd_v6_0_stop(struct amdgpu_device *adev);
@@@ -49,18 -47,6 +49,18 @@@ static int uvd_v6_0_set_clockgating_sta
  static void uvd_v6_0_enable_mgcg(struct amdgpu_device *adev,
                                 bool enable);
  
 +/**
 +* uvd_v6_0_enc_support - get encode support status
 +*
 +* @adev: amdgpu_device pointer
 +*
 +* Returns the current hardware encode support status
 +*/
 +static inline bool uvd_v6_0_enc_support(struct amdgpu_device *adev)
 +{
 +      return ((adev->asic_type >= CHIP_POLARIS10) && (adev->asic_type <= CHIP_POLARIS12));
 +}
 +
  /**
   * uvd_v6_0_ring_get_rptr - get read pointer
   *
@@@ -75,22 -61,6 +75,22 @@@ static uint64_t uvd_v6_0_ring_get_rptr(
        return RREG32(mmUVD_RBC_RB_RPTR);
  }
  
 +/**
 + * uvd_v6_0_enc_ring_get_rptr - get enc read pointer
 + *
 + * @ring: amdgpu_ring pointer
 + *
 + * Returns the current hardware enc read pointer
 + */
 +static uint64_t uvd_v6_0_enc_ring_get_rptr(struct amdgpu_ring *ring)
 +{
 +      struct amdgpu_device *adev = ring->adev;
 +
 +      if (ring == &adev->uvd.ring_enc[0])
 +              return RREG32(mmUVD_RB_RPTR);
 +      else
 +              return RREG32(mmUVD_RB_RPTR2);
 +}
  /**
   * uvd_v6_0_ring_get_wptr - get write pointer
   *
@@@ -105,23 -75,6 +105,23 @@@ static uint64_t uvd_v6_0_ring_get_wptr(
        return RREG32(mmUVD_RBC_RB_WPTR);
  }
  
 +/**
 + * uvd_v6_0_enc_ring_get_wptr - get enc write pointer
 + *
 + * @ring: amdgpu_ring pointer
 + *
 + * Returns the current hardware enc write pointer
 + */
 +static uint64_t uvd_v6_0_enc_ring_get_wptr(struct amdgpu_ring *ring)
 +{
 +      struct amdgpu_device *adev = ring->adev;
 +
 +      if (ring == &adev->uvd.ring_enc[0])
 +              return RREG32(mmUVD_RB_WPTR);
 +      else
 +              return RREG32(mmUVD_RB_WPTR2);
 +}
 +
  /**
   * uvd_v6_0_ring_set_wptr - set write pointer
   *
@@@ -136,248 -89,11 +136,248 @@@ static void uvd_v6_0_ring_set_wptr(stru
        WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr));
  }
  
 +/**
 + * uvd_v6_0_enc_ring_set_wptr - set enc write pointer
 + *
 + * @ring: amdgpu_ring pointer
 + *
 + * Commits the enc write pointer to the hardware
 + */
 +static void uvd_v6_0_enc_ring_set_wptr(struct amdgpu_ring *ring)
 +{
 +      struct amdgpu_device *adev = ring->adev;
 +
 +      if (ring == &adev->uvd.ring_enc[0])
 +              WREG32(mmUVD_RB_WPTR,
 +                      lower_32_bits(ring->wptr));
 +      else
 +              WREG32(mmUVD_RB_WPTR2,
 +                      lower_32_bits(ring->wptr));
 +}
 +
 +/**
 + * uvd_v6_0_enc_ring_test_ring - test if UVD ENC ring is working
 + *
 + * @ring: the engine to test on
 + *
 + */
 +static int uvd_v6_0_enc_ring_test_ring(struct amdgpu_ring *ring)
 +{
 +      struct amdgpu_device *adev = ring->adev;
 +      uint32_t rptr = amdgpu_ring_get_rptr(ring);
 +      unsigned i;
 +      int r;
 +
 +      r = amdgpu_ring_alloc(ring, 16);
 +      if (r) {
 +              DRM_ERROR("amdgpu: uvd enc failed to lock ring %d (%d).\n",
 +                        ring->idx, r);
 +              return r;
 +      }
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_END);
 +      amdgpu_ring_commit(ring);
 +
 +      for (i = 0; i < adev->usec_timeout; i++) {
 +              if (amdgpu_ring_get_rptr(ring) != rptr)
 +                      break;
 +              DRM_UDELAY(1);
 +      }
 +
 +      if (i < adev->usec_timeout) {
 +              DRM_INFO("ring test on %d succeeded in %d usecs\n",
 +                       ring->idx, i);
 +      } else {
 +              DRM_ERROR("amdgpu: ring %d test failed\n",
 +                        ring->idx);
 +              r = -ETIMEDOUT;
 +      }
 +
 +      return r;
 +}
 +
 +/**
 + * uvd_v6_0_enc_get_create_msg - generate a UVD ENC create msg
 + *
 + * @adev: amdgpu_device pointer
 + * @ring: ring we should submit the msg to
 + * @handle: session handle to use
 + * @fence: optional fence to return
 + *
 + * Open up a stream for HW test
 + */
 +static int uvd_v6_0_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
 +                                     struct dma_fence **fence)
 +{
 +      const unsigned ib_size_dw = 16;
 +      struct amdgpu_job *job;
 +      struct amdgpu_ib *ib;
 +      struct dma_fence *f = NULL;
 +      uint64_t dummy;
 +      int i, r;
 +
 +      r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job);
 +      if (r)
 +              return r;
 +
 +      ib = &job->ibs[0];
 +      dummy = ib->gpu_addr + 1024;
 +
 +      ib->length_dw = 0;
 +      ib->ptr[ib->length_dw++] = 0x00000018;
 +      ib->ptr[ib->length_dw++] = 0x00000001; /* session info */
 +      ib->ptr[ib->length_dw++] = handle;
 +      ib->ptr[ib->length_dw++] = 0x00010000;
 +      ib->ptr[ib->length_dw++] = upper_32_bits(dummy);
 +      ib->ptr[ib->length_dw++] = dummy;
 +
 +      ib->ptr[ib->length_dw++] = 0x00000014;
 +      ib->ptr[ib->length_dw++] = 0x00000002; /* task info */
 +      ib->ptr[ib->length_dw++] = 0x0000001c;
 +      ib->ptr[ib->length_dw++] = 0x00000001;
 +      ib->ptr[ib->length_dw++] = 0x00000000;
 +
 +      ib->ptr[ib->length_dw++] = 0x00000008;
 +      ib->ptr[ib->length_dw++] = 0x08000001; /* op initialize */
 +
 +      for (i = ib->length_dw; i < ib_size_dw; ++i)
 +              ib->ptr[i] = 0x0;
 +
 +      r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
 +      job->fence = dma_fence_get(f);
 +      if (r)
 +              goto err;
 +
 +      amdgpu_job_free(job);
 +      if (fence)
 +              *fence = dma_fence_get(f);
 +      dma_fence_put(f);
 +      return 0;
 +
 +err:
 +      amdgpu_job_free(job);
 +      return r;
 +}
 +
 +/**
 + * uvd_v6_0_enc_get_destroy_msg - generate a UVD ENC destroy msg
 + *
 + * @adev: amdgpu_device pointer
 + * @ring: ring we should submit the msg to
 + * @handle: session handle to use
 + * @fence: optional fence to return
 + *
 + * Close up a stream for HW test or if userspace failed to do so
 + */
 +static int uvd_v6_0_enc_get_destroy_msg(struct amdgpu_ring *ring,
 +                                      uint32_t handle,
 +                                      bool direct, struct dma_fence **fence)
 +{
 +      const unsigned ib_size_dw = 16;
 +      struct amdgpu_job *job;
 +      struct amdgpu_ib *ib;
 +      struct dma_fence *f = NULL;
 +      uint64_t dummy;
 +      int i, r;
 +
 +      r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job);
 +      if (r)
 +              return r;
 +
 +      ib = &job->ibs[0];
 +      dummy = ib->gpu_addr + 1024;
 +
 +      ib->length_dw = 0;
 +      ib->ptr[ib->length_dw++] = 0x00000018;
 +      ib->ptr[ib->length_dw++] = 0x00000001; /* session info */
 +      ib->ptr[ib->length_dw++] = handle;
 +      ib->ptr[ib->length_dw++] = 0x00010000;
 +      ib->ptr[ib->length_dw++] = upper_32_bits(dummy);
 +      ib->ptr[ib->length_dw++] = dummy;
 +
 +      ib->ptr[ib->length_dw++] = 0x00000014;
 +      ib->ptr[ib->length_dw++] = 0x00000002; /* task info */
 +      ib->ptr[ib->length_dw++] = 0x0000001c;
 +      ib->ptr[ib->length_dw++] = 0x00000001;
 +      ib->ptr[ib->length_dw++] = 0x00000000;
 +
 +      ib->ptr[ib->length_dw++] = 0x00000008;
 +      ib->ptr[ib->length_dw++] = 0x08000002; /* op close session */
 +
 +      for (i = ib->length_dw; i < ib_size_dw; ++i)
 +              ib->ptr[i] = 0x0;
 +
 +      if (direct) {
 +              r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f);
 +              job->fence = dma_fence_get(f);
 +              if (r)
 +                      goto err;
 +
 +              amdgpu_job_free(job);
 +      } else {
 +              r = amdgpu_job_submit(job, ring, &ring->adev->vce.entity,
 +                                    AMDGPU_FENCE_OWNER_UNDEFINED, &f);
 +              if (r)
 +                      goto err;
 +      }
 +
 +      if (fence)
 +              *fence = dma_fence_get(f);
 +      dma_fence_put(f);
 +      return 0;
 +
 +err:
 +      amdgpu_job_free(job);
 +      return r;
 +}
 +
 +/**
 + * uvd_v6_0_enc_ring_test_ib - test if UVD ENC IBs are working
 + *
 + * @ring: the engine to test on
 + *
 + */
 +static int uvd_v6_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 +{
 +      struct dma_fence *fence = NULL;
 +      long r;
 +
 +      r = uvd_v6_0_enc_get_create_msg(ring, 1, NULL);
 +      if (r) {
 +              DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
 +              goto error;
 +      }
 +
 +      r = uvd_v6_0_enc_get_destroy_msg(ring, 1, true, &fence);
 +      if (r) {
 +              DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
 +              goto error;
 +      }
 +
 +      r = dma_fence_wait_timeout(fence, false, timeout);
 +      if (r == 0) {
 +              DRM_ERROR("amdgpu: IB test timed out.\n");
 +              r = -ETIMEDOUT;
 +      } else if (r < 0) {
 +              DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
 +      } else {
 +              DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
 +              r = 0;
 +      }
 +error:
 +      dma_fence_put(fence);
 +      return r;
 +}
  static int uvd_v6_0_early_init(void *handle)
  {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
  
        uvd_v6_0_set_ring_funcs(adev);
 +
 +      if (uvd_v6_0_enc_support(adev)) {
 +              adev->uvd.num_enc_rings = 2;
 +              uvd_v6_0_set_enc_ring_funcs(adev);
 +      }
 +
        uvd_v6_0_set_irq_funcs(adev);
  
        return 0;
  static int uvd_v6_0_sw_init(void *handle)
  {
        struct amdgpu_ring *ring;
 -      int r;
 +      int i, r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
  
        /* UVD TRAP */
        if (r)
                return r;
  
 +      /* UVD ENC TRAP */
 +      if (uvd_v6_0_enc_support(adev)) {
 +              for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
 +                      r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, i + 119, &adev->uvd.irq);
 +                      if (r)
 +                              return r;
 +              }
 +      }
 +
        r = amdgpu_uvd_sw_init(adev);
        if (r)
                return r;
  
 +      if (uvd_v6_0_enc_support(adev)) {
 +              struct amd_sched_rq *rq;
 +              ring = &adev->uvd.ring_enc[0];
 +              rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_NORMAL];
 +              r = amd_sched_entity_init(&ring->sched, &adev->uvd.entity_enc,
 +                                        rq, amdgpu_sched_jobs);
 +              if (r) {
 +                      DRM_ERROR("Failed setting up UVD ENC run queue.\n");
 +                      return r;
 +              }
 +      }
 +
        r = amdgpu_uvd_resume(adev);
        if (r)
                return r;
        ring = &adev->uvd.ring;
        sprintf(ring->name, "uvd");
        r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.irq, 0);
 +      if (r)
 +              return r;
 +
 +      if (uvd_v6_0_enc_support(adev)) {
 +              for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
 +                      ring = &adev->uvd.ring_enc[i];
 +                      sprintf(ring->name, "uvd_enc%d", i);
 +                      r = amdgpu_ring_init(adev, ring, 512, &adev->uvd.irq, 0);
 +                      if (r)
 +                              return r;
 +              }
 +      }
  
        return r;
  }
  
  static int uvd_v6_0_sw_fini(void *handle)
  {
 -      int r;
 +      int i, r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
  
        r = amdgpu_uvd_suspend(adev);
        if (r)
                return r;
  
 +      if (uvd_v6_0_enc_support(adev)) {
 +              amd_sched_entity_fini(&adev->uvd.ring_enc[0].sched, &adev->uvd.entity_enc);
 +
 +              for (i = 0; i < adev->uvd.num_enc_rings; ++i)
 +                      amdgpu_ring_fini(&adev->uvd.ring_enc[i]);
 +      }
 +
        return amdgpu_uvd_sw_fini(adev);
  }
  
@@@ -473,7 -149,7 +473,7 @@@ static int uvd_v6_0_hw_init(void *handl
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        struct amdgpu_ring *ring = &adev->uvd.ring;
        uint32_t tmp;
 -      int r;
 +      int i, r;
  
        amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
        uvd_v6_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE);
  
        amdgpu_ring_commit(ring);
  
 +      if (uvd_v6_0_enc_support(adev)) {
 +              for (i = 0; i < adev->uvd.num_enc_rings; ++i) {
 +                      ring = &adev->uvd.ring_enc[i];
 +                      ring->ready = true;
 +                      r = amdgpu_ring_test_ring(ring);
 +                      if (r) {
 +                              ring->ready = false;
 +                              goto done;
 +                      }
 +              }
 +      }
 +
  done:
 -      if (!r)
 -              DRM_INFO("UVD initialized successfully.\n");
 +      if (!r) {
 +              if (uvd_v6_0_enc_support(adev))
 +                      DRM_INFO("UVD and UVD ENC initialized successfully.\n");
 +              else
 +                      DRM_INFO("UVD initialized successfully.\n");
 +      }
  
        return r;
  }
@@@ -565,11 -225,7 +565,7 @@@ static int uvd_v6_0_suspend(void *handl
        if (r)
                return r;
  
-       /* Skip this for APU for now */
-       if (!(adev->flags & AMD_IS_APU))
-               r = amdgpu_uvd_suspend(adev);
-       return r;
+       return amdgpu_uvd_suspend(adev);
  }
  
  static int uvd_v6_0_resume(void *handle)
        int r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
  
-       /* Skip this for APU for now */
-       if (!(adev->flags & AMD_IS_APU)) {
-               r = amdgpu_uvd_resume(adev);
-               if (r)
-                       return r;
-       }
+       r = amdgpu_uvd_resume(adev);
+       if (r)
+               return r;
        return uvd_v6_0_hw_init(adev);
  }
  
@@@ -854,22 -508,6 +848,22 @@@ static int uvd_v6_0_start(struct amdgpu
  
        WREG32_FIELD(UVD_RBC_RB_CNTL, RB_NO_FETCH, 0);
  
 +      if (uvd_v6_0_enc_support(adev)) {
 +              ring = &adev->uvd.ring_enc[0];
 +              WREG32(mmUVD_RB_RPTR, lower_32_bits(ring->wptr));
 +              WREG32(mmUVD_RB_WPTR, lower_32_bits(ring->wptr));
 +              WREG32(mmUVD_RB_BASE_LO, ring->gpu_addr);
 +              WREG32(mmUVD_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
 +              WREG32(mmUVD_RB_SIZE, ring->ring_size / 4);
 +
 +              ring = &adev->uvd.ring_enc[1];
 +              WREG32(mmUVD_RB_RPTR2, lower_32_bits(ring->wptr));
 +              WREG32(mmUVD_RB_WPTR2, lower_32_bits(ring->wptr));
 +              WREG32(mmUVD_RB_BASE_LO2, ring->gpu_addr);
 +              WREG32(mmUVD_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
 +              WREG32(mmUVD_RB_SIZE2, ring->ring_size / 4);
 +      }
 +
        return 0;
  }
  
@@@ -932,26 -570,6 +926,26 @@@ static void uvd_v6_0_ring_emit_fence(st
        amdgpu_ring_write(ring, 2);
  }
  
 +/**
 + * uvd_v6_0_enc_ring_emit_fence - emit an enc fence & trap command
 + *
 + * @ring: amdgpu_ring pointer
 + * @fence: fence to emit
 + *
 + * Write enc a fence and a trap command to the ring.
 + */
 +static void uvd_v6_0_enc_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
 +                      u64 seq, unsigned flags)
 +{
 +      WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
 +
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_FENCE);
 +      amdgpu_ring_write(ring, addr);
 +      amdgpu_ring_write(ring, upper_32_bits(addr));
 +      amdgpu_ring_write(ring, seq);
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_TRAP);
 +}
 +
  /**
   * uvd_v6_0_ring_emit_hdp_flush - emit an hdp flush
   *
@@@ -1043,24 -661,6 +1037,24 @@@ static void uvd_v6_0_ring_emit_ib(struc
        amdgpu_ring_write(ring, ib->length_dw);
  }
  
 +/**
 + * uvd_v6_0_enc_ring_emit_ib - enc execute indirect buffer
 + *
 + * @ring: amdgpu_ring pointer
 + * @ib: indirect buffer to execute
 + *
 + * Write enc ring commands to execute the indirect buffer
 + */
 +static void uvd_v6_0_enc_ring_emit_ib(struct amdgpu_ring *ring,
 +              struct amdgpu_ib *ib, unsigned int vm_id, bool ctx_switch)
 +{
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_IB_VM);
 +      amdgpu_ring_write(ring, vm_id);
 +      amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
 +      amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
 +      amdgpu_ring_write(ring, ib->length_dw);
 +}
 +
  static void uvd_v6_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
                                         unsigned vm_id, uint64_t pd_addr)
  {
@@@ -1112,33 -712,6 +1106,33 @@@ static void uvd_v6_0_ring_emit_pipeline
        amdgpu_ring_write(ring, 0xE);
  }
  
 +static void uvd_v6_0_enc_ring_emit_pipeline_sync(struct amdgpu_ring *ring)
 +{
 +      uint32_t seq = ring->fence_drv.sync_seq;
 +      uint64_t addr = ring->fence_drv.gpu_addr;
 +
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_WAIT_GE);
 +      amdgpu_ring_write(ring, lower_32_bits(addr));
 +      amdgpu_ring_write(ring, upper_32_bits(addr));
 +      amdgpu_ring_write(ring, seq);
 +}
 +
 +static void uvd_v6_0_enc_ring_insert_end(struct amdgpu_ring *ring)
 +{
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_END);
 +}
 +
 +static void uvd_v6_0_enc_ring_emit_vm_flush(struct amdgpu_ring *ring,
 +        unsigned int vm_id, uint64_t pd_addr)
 +{
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_UPDATE_PTB);
 +      amdgpu_ring_write(ring, vm_id);
 +      amdgpu_ring_write(ring, pd_addr >> 12);
 +
 +      amdgpu_ring_write(ring, HEVC_ENC_CMD_FLUSH_TLB);
 +      amdgpu_ring_write(ring, vm_id);
 +}
 +
  static bool uvd_v6_0_is_idle(void *handle)
  {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@@ -1246,31 -819,8 +1240,31 @@@ static int uvd_v6_0_process_interrupt(s
                                      struct amdgpu_irq_src *source,
                                      struct amdgpu_iv_entry *entry)
  {
 +      bool int_handled = true;
        DRM_DEBUG("IH: UVD TRAP\n");
 -      amdgpu_fence_process(&adev->uvd.ring);
 +
 +      switch (entry->src_id) {
 +      case 124:
 +              amdgpu_fence_process(&adev->uvd.ring);
 +              break;
 +      case 119:
 +              if (likely(uvd_v6_0_enc_support(adev)))
 +                      amdgpu_fence_process(&adev->uvd.ring_enc[0]);
 +              else
 +                      int_handled = false;
 +              break;
 +      case 120:
 +              if (likely(uvd_v6_0_enc_support(adev)))
 +                      amdgpu_fence_process(&adev->uvd.ring_enc[1]);
 +              else
 +                      int_handled = false;
 +              break;
 +      }
 +
 +      if (false == int_handled)
 +                      DRM_ERROR("Unhandled interrupt: %d %d\n",
 +                        entry->src_id, entry->src_data[0]);
 +
        return 0;
  }
  
@@@ -1597,33 -1147,6 +1591,33 @@@ static const struct amdgpu_ring_funcs u
        .end_use = amdgpu_uvd_ring_end_use,
  };
  
 +static const struct amdgpu_ring_funcs uvd_v6_0_enc_ring_vm_funcs = {
 +      .type = AMDGPU_RING_TYPE_UVD_ENC,
 +      .align_mask = 0x3f,
 +      .nop = HEVC_ENC_CMD_NO_OP,
 +      .support_64bit_ptrs = false,
 +      .get_rptr = uvd_v6_0_enc_ring_get_rptr,
 +      .get_wptr = uvd_v6_0_enc_ring_get_wptr,
 +      .set_wptr = uvd_v6_0_enc_ring_set_wptr,
 +      .emit_frame_size =
 +              4 + /* uvd_v6_0_enc_ring_emit_pipeline_sync */
 +              6 + /* uvd_v6_0_enc_ring_emit_vm_flush */
 +              5 + 5 + /* uvd_v6_0_enc_ring_emit_fence x2 vm fence */
 +              1, /* uvd_v6_0_enc_ring_insert_end */
 +      .emit_ib_size = 5, /* uvd_v6_0_enc_ring_emit_ib */
 +      .emit_ib = uvd_v6_0_enc_ring_emit_ib,
 +      .emit_fence = uvd_v6_0_enc_ring_emit_fence,
 +      .emit_vm_flush = uvd_v6_0_enc_ring_emit_vm_flush,
 +      .emit_pipeline_sync = uvd_v6_0_enc_ring_emit_pipeline_sync,
 +      .test_ring = uvd_v6_0_enc_ring_test_ring,
 +      .test_ib = uvd_v6_0_enc_ring_test_ib,
 +      .insert_nop = amdgpu_ring_insert_nop,
 +      .insert_end = uvd_v6_0_enc_ring_insert_end,
 +      .pad_ib = amdgpu_ring_generic_pad_ib,
 +      .begin_use = amdgpu_uvd_ring_begin_use,
 +      .end_use = amdgpu_uvd_ring_end_use,
 +};
 +
  static void uvd_v6_0_set_ring_funcs(struct amdgpu_device *adev)
  {
        if (adev->asic_type >= CHIP_POLARIS10) {
        }
  }
  
 +static void uvd_v6_0_set_enc_ring_funcs(struct amdgpu_device *adev)
 +{
 +      int i;
 +
 +      for (i = 0; i < adev->uvd.num_enc_rings; ++i)
 +              adev->uvd.ring_enc[i].funcs = &uvd_v6_0_enc_ring_vm_funcs;
 +
 +      DRM_INFO("UVD ENC is enabled in VM mode\n");
 +}
 +
  static const struct amdgpu_irq_src_funcs uvd_v6_0_irq_funcs = {
        .set = uvd_v6_0_set_interrupt_state,
        .process = uvd_v6_0_process_interrupt,
  
  static void uvd_v6_0_set_irq_funcs(struct amdgpu_device *adev)
  {
 -      adev->uvd.irq.num_types = 1;
 +      if (uvd_v6_0_enc_support(adev))
 +              adev->uvd.irq.num_types = adev->uvd.num_enc_rings + 1;
 +      else
 +              adev->uvd.irq.num_types = 1;
 +
        adev->uvd.irq.funcs = &uvd_v6_0_irq_funcs;
  }
  
index e32f18a9907463d9e186645890f74e5589635fc4,b526f49be65d066d5eb49d7339ebe3e089c08877..4466469cf8ab816d8d5e0eca6a4ec29358e6cfe4
@@@ -26,7 -26,6 +26,7 @@@
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <asm/div64.h>
 +#include <drm/amdgpu_drm.h>
  #include "pp_acpi.h"
  #include "ppatomctrl.h"
  #include "atombios.h"
@@@ -164,7 -163,7 +164,7 @@@ static int smu7_get_current_pcie_lane_n
  static int smu7_enable_smc_voltage_controller(struct pp_hwmgr *hwmgr)
  {
        if (hwmgr->feature_mask & PP_SMC_VOLTAGE_CONTROL_MASK)
 -              smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Voltage_Cntl_Enable);
 +              smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Voltage_Cntl_Enable);
  
        return 0;
  }
@@@ -301,28 -300,28 +301,28 @@@ static int smu7_construct_voltage_table
                        "Failed to retrieve SVI2 VDDC table from dependancy table.", return result;);
        }
  
 -      tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDC);
 +      tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDC);
        PP_ASSERT_WITH_CODE(
                        (data->vddc_voltage_table.count <= tmp),
                "Too many voltage values for VDDC. Trimming to fit state table.",
                        phm_trim_voltage_table_to_fit_state_table(tmp,
                                                &(data->vddc_voltage_table)));
  
 -      tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDGFX);
 +      tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDGFX);
        PP_ASSERT_WITH_CODE(
                        (data->vddgfx_voltage_table.count <= tmp),
                "Too many voltage values for VDDC. Trimming to fit state table.",
                        phm_trim_voltage_table_to_fit_state_table(tmp,
                                                &(data->vddgfx_voltage_table)));
  
 -      tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDCI);
 +      tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDCI);
        PP_ASSERT_WITH_CODE(
                        (data->vddci_voltage_table.count <= tmp),
                "Too many voltage values for VDDCI. Trimming to fit state table.",
                        phm_trim_voltage_table_to_fit_state_table(tmp,
                                        &(data->vddci_voltage_table)));
  
 -      tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_MVDD);
 +      tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_MVDD);
        PP_ASSERT_WITH_CODE(
                        (data->mvdd_voltage_table.count <= tmp),
                "Too many voltage values for MVDD. Trimming to fit state table.",
@@@ -388,7 -387,6 +388,7 @@@ static int smu7_enable_display_gap(stru
  static int smu7_program_voting_clients(struct pp_hwmgr *hwmgr)
  {
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 +      int i;
  
        /* Clear reset for voting clients before enabling DPM */
        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
                        SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 0);
  
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_0, data->voting_rights_clients0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_1, data->voting_rights_clients1);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_2, data->voting_rights_clients2);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_3, data->voting_rights_clients3);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_4, data->voting_rights_clients4);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_5, data->voting_rights_clients5);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_6, data->voting_rights_clients6);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_7, data->voting_rights_clients7);
 -
 +      for (i = 0; i < 8; i++)
 +              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 +                                      ixCG_FREQ_TRAN_VOTING_0 + i * 4,
 +                                      data->voting_rights_clients[i]);
        return 0;
  }
  
  static int smu7_clear_voting_clients(struct pp_hwmgr *hwmgr)
  {
 +      int i;
 +
        /* Reset voting clients before disabling DPM */
        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
                        SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
                        SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
  
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_0, 0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_1, 0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_2, 0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_3, 0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_4, 0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_5, 0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_6, 0);
 -      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      ixCG_FREQ_TRAN_VOTING_7, 0);
 +      for (i = 0; i < 8; i++)
 +              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 +                              ixCG_FREQ_TRAN_VOTING_0 + i * 4, 0);
  
        return 0;
  }
@@@ -471,7 -493,7 +471,7 @@@ static int smu7_copy_and_switch_arb_set
  
  static int smu7_reset_to_default(struct pp_hwmgr *hwmgr)
  {
 -      return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults);
 +      return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ResetToDefaults);
  }
  
  /**
@@@ -529,7 -551,7 +529,7 @@@ static int smu7_setup_default_pcie_tabl
                data->pcie_gen_performance = data->pcie_gen_power_saving;
                data->pcie_lane_performance = data->pcie_lane_power_saving;
        }
 -      tmp = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_LINK);
 +      tmp = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_LINK);
        phm_reset_single_dpm_table(&data->dpm_table.pcie_speed_table,
                                        tmp,
                                        MAX_REGULAR_DPM_NUMBER);
                data->dpm_table.pcie_speed_table.count = 6;
        }
        /* Populate last level for boot PCIE level, but do not increment count. */
 -      phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
 +      if (hwmgr->chip_family == AMDGPU_FAMILY_CI) {
 +              for (i = 0; i <= data->dpm_table.pcie_speed_table.count; i++)
 +                      phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table, i,
 +                              get_pcie_gen_support(data->pcie_gen_cap,
 +                                              PP_Max_PCIEGen),
 +                              data->vbios_boot_state.pcie_lane_bootup_value);
 +      } else {
 +              phm_setup_pcie_table_entry(&data->dpm_table.pcie_speed_table,
                        data->dpm_table.pcie_speed_table.count,
                        get_pcie_gen_support(data->pcie_gen_cap,
                                        PP_Min_PCIEGen),
                        get_pcie_lane_support(data->pcie_lane_cap,
                                        PP_Max_PCIELane));
 -
 +      }
        return 0;
  }
  
@@@ -610,27 -625,27 +610,27 @@@ static int smu7_reset_dpm_tables(struc
  
        phm_reset_single_dpm_table(
                        &data->dpm_table.sclk_table,
 -                              smum_get_mac_definition(hwmgr->smumgr,
 +                              smum_get_mac_definition(hwmgr,
                                        SMU_MAX_LEVELS_GRAPHICS),
                                        MAX_REGULAR_DPM_NUMBER);
        phm_reset_single_dpm_table(
                        &data->dpm_table.mclk_table,
 -                      smum_get_mac_definition(hwmgr->smumgr,
 +                      smum_get_mac_definition(hwmgr,
                                SMU_MAX_LEVELS_MEMORY), MAX_REGULAR_DPM_NUMBER);
  
        phm_reset_single_dpm_table(
                        &data->dpm_table.vddc_table,
 -                              smum_get_mac_definition(hwmgr->smumgr,
 +                              smum_get_mac_definition(hwmgr,
                                        SMU_MAX_LEVELS_VDDC),
                                        MAX_REGULAR_DPM_NUMBER);
        phm_reset_single_dpm_table(
                        &data->dpm_table.vddci_table,
 -                      smum_get_mac_definition(hwmgr->smumgr,
 +                      smum_get_mac_definition(hwmgr,
                                SMU_MAX_LEVELS_VDDCI), MAX_REGULAR_DPM_NUMBER);
  
        phm_reset_single_dpm_table(
                        &data->dpm_table.mvdd_table,
 -                              smum_get_mac_definition(hwmgr->smumgr,
 +                              smum_get_mac_definition(hwmgr,
                                        SMU_MAX_LEVELS_MVDD),
                                        MAX_REGULAR_DPM_NUMBER);
        return 0;
@@@ -674,7 -689,7 +674,7 @@@ static int smu7_setup_dpm_tables_v0(str
                                allowed_vdd_sclk_table->entries[i].clk) {
                        data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
                                allowed_vdd_sclk_table->entries[i].clk;
 -                      data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; to do */
 +                      data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0;
                        data->dpm_table.sclk_table.count++;
                }
        }
                        allowed_vdd_mclk_table->entries[i].clk) {
                        data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].value =
                                allowed_vdd_mclk_table->entries[i].clk;
 -                      data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = 1; /*(i==0) ? 1 : 0; */
 +                      data->dpm_table.mclk_table.dpm_levels[data->dpm_table.mclk_table.count].enabled = (i == 0) ? 1 : 0;
                        data->dpm_table.mclk_table.count++;
                }
        }
@@@ -815,7 -830,7 +815,7 @@@ uint32_t smu7_get_xclk(struct pp_hwmgr 
  {
        uint32_t reference_clock, tmp;
        struct cgs_display_info info = {0};
-       struct cgs_mode_info mode_info;
+       struct cgs_mode_info mode_info = {0};
  
        info.mode_info = &mode_info;
  
@@@ -840,7 -855,7 +840,7 @@@ static int smu7_enable_vrhot_gpio_inter
  
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_RegulatorHot))
 -              return smum_send_msg_to_smc(hwmgr->smumgr,
 +              return smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_EnableVRHotGPIOInterrupt);
  
        return 0;
@@@ -858,7 -873,7 +858,7 @@@ static int smu7_enable_ulv(struct pp_hw
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
  
        if (data->ulv_supported)
 -              return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_EnableULV);
 +              return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_EnableULV);
  
        return 0;
  }
@@@ -868,7 -883,7 +868,7 @@@ static int smu7_disable_ulv(struct pp_h
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
  
        if (data->ulv_supported)
 -              return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableULV);
 +              return smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DisableULV);
  
        return 0;
  }
@@@ -877,12 -892,12 +877,12 @@@ static int smu7_enable_deep_sleep_maste
  {
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_SclkDeepSleep)) {
 -              if (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MASTER_DeepSleep_ON))
 +              if (smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MASTER_DeepSleep_ON))
                        PP_ASSERT_WITH_CODE(false,
                                        "Attempt to enable Master Deep Sleep switch failed!",
                                        return -EINVAL);
        } else {
 -              if (smum_send_msg_to_smc(hwmgr->smumgr,
 +              if (smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_MASTER_DeepSleep_OFF)) {
                        PP_ASSERT_WITH_CODE(false,
                                        "Attempt to disable Master Deep Sleep switch failed!",
@@@ -897,7 -912,7 +897,7 @@@ static int smu7_disable_deep_sleep_mast
  {
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_SclkDeepSleep)) {
 -              if (smum_send_msg_to_smc(hwmgr->smumgr,
 +              if (smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_MASTER_DeepSleep_OFF)) {
                        PP_ASSERT_WITH_CODE(false,
                                        "Attempt to disable Master Deep Sleep switch failed!",
@@@ -913,12 -928,12 +913,12 @@@ static int smu7_disable_handshake_uvd(s
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
        uint32_t soft_register_value = 0;
        uint32_t handshake_disables_offset = data->soft_regs_start
 -                              + smum_get_offsetof(hwmgr->smumgr,
 +                              + smum_get_offsetof(hwmgr,
                                        SMU_SoftRegisters, HandshakeDisables);
  
        soft_register_value = cgs_read_ind_register(hwmgr->device,
                                CGS_IND_REG__SMC, handshake_disables_offset);
 -      soft_register_value |= smum_get_mac_definition(hwmgr->smumgr,
 +      soft_register_value |= smum_get_mac_definition(hwmgr,
                                        SMU_UVD_MCLK_HANDSHAKE_DISABLE);
        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
                        handshake_disables_offset, soft_register_value);
@@@ -932,7 -947,7 +932,7 @@@ static int smu7_enable_sclk_mclk_dpm(st
        /* enable SCLK dpm */
        if (!data->sclk_dpm_key_disabled)
                PP_ASSERT_WITH_CODE(
 -              (0 == smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Enable)),
 +              (0 == smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DPM_Enable)),
                "Failed to enable SCLK DPM during DPM Start Function!",
                return -EINVAL);
  
                if (!(hwmgr->feature_mask & PP_UVD_HANDSHAKE_MASK))
                        smu7_disable_handshake_uvd(hwmgr);
                PP_ASSERT_WITH_CODE(
 -                              (0 == smum_send_msg_to_smc(hwmgr->smumgr,
 +                              (0 == smum_send_msg_to_smc(hwmgr,
                                                PPSMC_MSG_MCLKDPM_Enable)),
                                "Failed to enable MCLK DPM during DPM Start Function!",
                                return -EINVAL);
  
                PHM_WRITE_FIELD(hwmgr->device, MC_SEQ_CNTL_3, CAC_EN, 0x1);
  
 -              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x5);
 -              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x5);
 -              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x100005);
 -              udelay(10);
 -              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x400005);
 -              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x400005);
 -              cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x500005);
 +
 +              if (hwmgr->chip_family == AMDGPU_FAMILY_CI) {
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d30, 0x5);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d3c, 0x5);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d80, 0x100005);
 +                      udelay(10);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d30, 0x400005);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d3c, 0x400005);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, 0xc0400d80, 0x500005);
 +              } else {
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x5);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x5);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x100005);
 +                      udelay(10);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC0_CNTL, 0x400005);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_MC1_CNTL, 0x400005);
 +                      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixLCAC_CPL_CNTL, 0x500005);
 +              }
        }
  
        return 0;
@@@ -989,15 -993,11 +989,15 @@@ static int smu7_start_dpm(struct pp_hwm
  
        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
                        data->soft_regs_start +
 -                      smum_get_offsetof(hwmgr->smumgr, SMU_SoftRegisters,
 +                      smum_get_offsetof(hwmgr, SMU_SoftRegisters,
                                                VoltageChangeTimeout), 0x1000);
        PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__PCIE,
                        SWRST_COMMAND_1, RESETLC, 0x0);
  
 +      if (hwmgr->chip_family == AMDGPU_FAMILY_CI)
 +              cgs_write_register(hwmgr->device, 0x1488,
 +                      (cgs_read_register(hwmgr->device, 0x1488) & ~0x1));
 +
        if (smu7_enable_sclk_mclk_dpm(hwmgr)) {
                pr_err("Failed to enable Sclk DPM and Mclk DPM!");
                return -EINVAL;
        /* enable PCIE dpm */
        if (0 == data->pcie_dpm_key_disabled) {
                PP_ASSERT_WITH_CODE(
 -                              (0 == smum_send_msg_to_smc(hwmgr->smumgr,
 +                              (0 == smum_send_msg_to_smc(hwmgr,
                                                PPSMC_MSG_PCIeDPM_Enable)),
                                "Failed to enable pcie DPM during DPM Start Function!",
                                return -EINVAL);
  
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                                PHM_PlatformCaps_Falcon_QuickTransition)) {
 -              PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr->smumgr,
 +              PP_ASSERT_WITH_CODE((0 == smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_EnableACDCGPIOInterrupt)),
                                "Failed to enable AC DC GPIO Interrupt!",
                                );
@@@ -1032,7 -1032,7 +1032,7 @@@ static int smu7_disable_sclk_mclk_dpm(s
                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
                                "Trying to disable SCLK DPM when DPM is disabled",
                                return 0);
 -              smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DPM_Disable);
 +              smum_send_msg_to_smc(hwmgr, PPSMC_MSG_DPM_Disable);
        }
  
        /* disable MCLK dpm */
                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
                                "Trying to disable MCLK DPM when DPM is disabled",
                                return 0);
 -              smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_MCLKDPM_Disable);
 +              smum_send_msg_to_smc(hwmgr, PPSMC_MSG_MCLKDPM_Disable);
        }
  
        return 0;
@@@ -1060,7 -1060,7 +1060,7 @@@ static int smu7_stop_dpm(struct pp_hwmg
        /* disable PCIE dpm */
        if (!data->pcie_dpm_key_disabled) {
                PP_ASSERT_WITH_CODE(
 -                              (smum_send_msg_to_smc(hwmgr->smumgr,
 +                              (smum_send_msg_to_smc(hwmgr,
                                                PPSMC_MSG_PCIeDPM_Disable) == 0),
                                "Failed to disable pcie DPM during DPM Stop Function!",
                                return -EINVAL);
                        "Trying to disable voltage DPM when DPM is disabled",
                        return 0);
  
 -      smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Voltage_Cntl_Disable);
 +      smum_send_msg_to_smc(hwmgr, PPSMC_MSG_Voltage_Cntl_Disable);
  
        return 0;
  }
@@@ -1226,7 -1226,7 +1226,7 @@@ static int smu7_enable_dpm_tasks(struc
        PP_ASSERT_WITH_CODE((0 == tmp_result),
                        "Failed to enable VR hot GPIO interrupt!", result = tmp_result);
  
 -      smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_NoDisplay);
 +      smum_send_msg_to_smc(hwmgr, (PPSMC_Msg)PPSMC_NoDisplay);
  
        tmp_result = smu7_enable_sclk_control(hwmgr);
        PP_ASSERT_WITH_CODE((0 == tmp_result),
@@@ -1361,14 -1361,14 +1361,14 @@@ static void smu7_init_dpm_defaults(stru
        data->vddc_vddgfx_delta = 300;
        data->static_screen_threshold = SMU7_STATICSCREENTHRESHOLD_DFLT;
        data->static_screen_threshold_unit = SMU7_STATICSCREENTHRESHOLDUNIT_DFLT;
 -      data->voting_rights_clients0 = SMU7_VOTINGRIGHTSCLIENTS_DFLT0;
 -      data->voting_rights_clients= SMU7_VOTINGRIGHTSCLIENTS_DFLT1;
 -      data->voting_rights_clients2 = SMU7_VOTINGRIGHTSCLIENTS_DFLT2;
 -      data->voting_rights_clients= SMU7_VOTINGRIGHTSCLIENTS_DFLT3;
 -      data->voting_rights_clients= SMU7_VOTINGRIGHTSCLIENTS_DFLT4;
 -      data->voting_rights_clients= SMU7_VOTINGRIGHTSCLIENTS_DFLT5;
 -      data->voting_rights_clients= SMU7_VOTINGRIGHTSCLIENTS_DFLT6;
 -      data->voting_rights_clients= SMU7_VOTINGRIGHTSCLIENTS_DFLT7;
 +      data->voting_rights_clients[0] = SMU7_VOTINGRIGHTSCLIENTS_DFLT0;
 +      data->voting_rights_clients[1]= SMU7_VOTINGRIGHTSCLIENTS_DFLT1;
 +      data->voting_rights_clients[2] = SMU7_VOTINGRIGHTSCLIENTS_DFLT2;
 +      data->voting_rights_clients[3]= SMU7_VOTINGRIGHTSCLIENTS_DFLT3;
 +      data->voting_rights_clients[4]= SMU7_VOTINGRIGHTSCLIENTS_DFLT4;
 +      data->voting_rights_clients[5]= SMU7_VOTINGRIGHTSCLIENTS_DFLT5;
 +      data->voting_rights_clients[6]= SMU7_VOTINGRIGHTSCLIENTS_DFLT6;
 +      data->voting_rights_clients[7]= SMU7_VOTINGRIGHTSCLIENTS_DFLT7;
  
        data->mclk_dpm_key_disabled = hwmgr->feature_mask & PP_MCLK_DPM_MASK ? false : true;
        data->sclk_dpm_key_disabled = hwmgr->feature_mask & PP_SCLK_DPM_MASK ? false : true;
        data->force_pcie_gen = PP_PCIEGenInvalid;
        data->ulv_supported = hwmgr->feature_mask & PP_ULV_MASK ? true : false;
  
 -      if (hwmgr->chip_id == CHIP_POLARIS12 || hwmgr->smumgr->is_kicker) {
 +      if (hwmgr->chip_id == CHIP_POLARIS12 || hwmgr->is_kicker) {
                uint8_t tmp1, tmp2;
                uint16_t tmp3 = 0;
                atomctrl_get_svi2_info(hwmgr, VOLTAGE_TYPE_VDDC, &tmp1, &tmp2,
                                                &tmp3);
                tmp3 = (tmp3 >> 5) & 0x3;
                data->vddc_phase_shed_control = ((tmp3 << 1) | (tmp3 >> 1)) & 0x3;
 +      } else if (hwmgr->chip_family == AMDGPU_FAMILY_CI) {
 +              data->vddc_phase_shed_control = 1;
 +      } else {
 +              data->vddc_phase_shed_control = 0;
 +      }
 +
 +      if (hwmgr->chip_id  == CHIP_HAWAII) {
 +              data->thermal_temp_setting.temperature_low = 94500;
 +              data->thermal_temp_setting.temperature_high = 95000;
 +              data->thermal_temp_setting.temperature_shutdown = 104000;
 +      } else {
 +              data->thermal_temp_setting.temperature_low = 99500;
 +              data->thermal_temp_setting.temperature_high = 100000;
 +              data->thermal_temp_setting.temperature_shutdown = 104000;
        }
  
        data->fast_watermark_threshold = 100;
 -      if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 +      if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
                        VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_SVID2))
                data->voltage_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
 +      else if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
 +                      VOLTAGE_TYPE_VDDC, VOLTAGE_OBJ_GPIO_LUT))
 +              data->voltage_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
  
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_ControlVDDGFX)) {
 -              if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 +              if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
                        VOLTAGE_TYPE_VDDGFX, VOLTAGE_OBJ_SVID2)) {
                        data->vdd_gfx_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
                }
  
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_EnableMVDDControl)) {
 -              if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 +              if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
                                VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_GPIO_LUT))
                        data->mvdd_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
 -              else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 +              else if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
                                VOLTAGE_TYPE_MVDDC, VOLTAGE_OBJ_SVID2))
                        data->mvdd_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
        }
  
 -      if (SMU7_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control) {
 +      if (SMU7_VOLTAGE_CONTROL_NONE == data->vdd_gfx_control)
                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_ControlVDDGFX);
 -      }
  
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_ControlVDDCI)) {
 -              if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 +              if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_GPIO_LUT))
                        data->vddci_control = SMU7_VOLTAGE_CONTROL_BY_GPIO;
 -              else if (atomctrl_is_voltage_controled_by_gpio_v3(hwmgr,
 +              else if (atomctrl_is_voltage_controlled_by_gpio_v3(hwmgr,
                                VOLTAGE_TYPE_VDDCI, VOLTAGE_OBJ_SVID2))
                        data->vddci_control = SMU7_VOLTAGE_CONTROL_BY_SVID2;
        }
@@@ -1559,7 -1543,7 +1559,7 @@@ static int smu7_get_evv_voltages(struc
                                        if (vddc >= 2000 || vddc == 0)
                                                return -EINVAL;
                                } else {
 -                                      pr_warn("failed to retrieving EVV voltage!\n");
 +                                      pr_debug("failed to retrieving EVV voltage!\n");
                                        continue;
                                }
  
@@@ -1692,7 -1676,7 +1692,7 @@@ static int phm_add_voltage(struct pp_hw
        PP_ASSERT_WITH_CODE((0 != look_up_table->count),
                "Lookup Table empty.", return -EINVAL);
  
 -      i = smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_VDDGFX);
 +      i = smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_VDDGFX);
        PP_ASSERT_WITH_CODE((i >= look_up_table->count),
                "Lookup Table is full.", return -EINVAL);
  
@@@ -2290,7 -2274,7 +2290,7 @@@ static int smu7_set_private_data_based_
                data->max_vddci_in_pptable = (uint16_t)allowed_mclk_vddci_table->entries[allowed_mclk_vddci_table->count - 1].v;
        }
  
 -      if (hwmgr->dyn_state.vddci_dependency_on_mclk != NULL && hwmgr->dyn_state.vddci_dependency_on_mclk->count > 1)
 +      if (hwmgr->dyn_state.vddci_dependency_on_mclk != NULL && hwmgr->dyn_state.vddci_dependency_on_mclk->count >= 1)
                hwmgr->dyn_state.max_clock_voltage_on_ac.vddci = hwmgr->dyn_state.vddci_dependency_on_mclk->entries[hwmgr->dyn_state.vddci_dependency_on_mclk->count - 1].v;
  
        return 0;
  
  static int smu7_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
  {
 -      if (NULL != hwmgr->dyn_state.vddc_dep_on_dal_pwrl) {
 -              kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
 -              hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
 -      }
 -      pp_smu7_thermal_fini(hwmgr);
 -      if (NULL != hwmgr->backend) {
 -              kfree(hwmgr->backend);
 -              hwmgr->backend = NULL;
 -      }
 +      kfree(hwmgr->dyn_state.vddc_dep_on_dal_pwrl);
 +      hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
 +      kfree(hwmgr->backend);
 +      hwmgr->backend = NULL;
 +
 +      return 0;
 +}
 +
 +static int smu7_get_elb_voltages(struct pp_hwmgr *hwmgr)
 +{
 +      uint16_t virtual_voltage_id, vddc, vddci, efuse_voltage_id;
 +      struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 +      int i;
  
 +      if (atomctrl_get_leakage_id_from_efuse(hwmgr, &efuse_voltage_id) == 0) {
 +              for (i = 0; i < SMU7_MAX_LEAKAGE_COUNT; i++) {
 +                      virtual_voltage_id = ATOM_VIRTUAL_VOLTAGE_ID0 + i;
 +                      if (atomctrl_get_leakage_vddc_base_on_leakage(hwmgr, &vddc, &vddci,
 +                                                              virtual_voltage_id,
 +                                                              efuse_voltage_id) == 0) {
 +                              if (vddc != 0 && vddc != virtual_voltage_id) {
 +                                      data->vddc_leakage.actual_voltage[data->vddc_leakage.count] = vddc;
 +                                      data->vddc_leakage.leakage_id[data->vddc_leakage.count] = virtual_voltage_id;
 +                                      data->vddc_leakage.count++;
 +                              }
 +                              if (vddci != 0 && vddci != virtual_voltage_id) {
 +                                      data->vddci_leakage.actual_voltage[data->vddci_leakage.count] = vddci;
 +                                      data->vddci_leakage.leakage_id[data->vddci_leakage.count] = virtual_voltage_id;
 +                                      data->vddci_leakage.count++;
 +                              }
 +                      }
 +              }
 +      }
        return 0;
  }
  
  static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
  {
        struct smu7_hwmgr *data;
 -      int result;
 +      int result = 0;
  
        data = kzalloc(sizeof(struct smu7_hwmgr), GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
  
        hwmgr->backend = data;
 -      pp_smu7_thermal_initialize(hwmgr);
 -
        smu7_patch_voltage_workaround(hwmgr);
        smu7_init_dpm_defaults(hwmgr);
  
        /* Get leakage voltage based on leakage ID. */
 -      result = smu7_get_evv_voltages(hwmgr);
 -
 -      if (result) {
 -              pr_info("Get EVV Voltage Failed.  Abort Driver loading!\n");
 -              return -EINVAL;
 +      if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
 +                      PHM_PlatformCaps_EVV)) {
 +              result = smu7_get_evv_voltages(hwmgr);
 +              if (result) {
 +                      pr_info("Get EVV Voltage Failed.  Abort Driver loading!\n");
 +                      return -EINVAL;
 +              }
 +      } else {
 +              smu7_get_elb_voltages(hwmgr);
        }
  
        if (hwmgr->pp_table_version == PP_TABLE_V1) {
@@@ -2423,7 -2382,7 +2423,7 @@@ static int smu7_force_dpm_highest(struc
                                level++;
  
                        if (level)
 -                              smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                              smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_PCIeDPM_ForceLevel, level);
                }
        }
                                level++;
  
                        if (level)
 -                              smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                              smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_SCLKDPM_SetEnabledMask,
                                                (1 << level));
                }
                                level++;
  
                        if (level)
 -                              smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                              smum_send_msg_to_smc_with_parameter(hwmgr,
                                                PPSMC_MSG_MCLKDPM_SetEnabledMask,
                                                (1 << level));
                }
@@@ -2469,14 -2428,14 +2469,14 @@@ static int smu7_upload_dpm_level_enable
  
        if (!data->sclk_dpm_key_disabled) {
                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask)
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_SCLKDPM_SetEnabledMask,
                                        data->dpm_level_enable_mask.sclk_dpm_enable_mask);
        }
  
        if (!data->mclk_dpm_key_disabled) {
                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask)
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_MCLKDPM_SetEnabledMask,
                                        data->dpm_level_enable_mask.mclk_dpm_enable_mask);
        }
@@@ -2492,7 -2451,7 +2492,7 @@@ static int smu7_unforce_dpm_levels(stru
                return -EINVAL;
  
        if (!data->pcie_dpm_key_disabled) {
 -              smum_send_msg_to_smc(hwmgr->smumgr,
 +              smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_PCIeDPM_UnForceLevel);
        }
  
@@@ -2509,7 -2468,7 +2509,7 @@@ static int smu7_force_dpm_lowest(struc
                if (data->dpm_level_enable_mask.sclk_dpm_enable_mask) {
                        level = phm_get_lowest_enabled_level(hwmgr,
                                                              data->dpm_level_enable_mask.sclk_dpm_enable_mask);
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                                            PPSMC_MSG_SCLKDPM_SetEnabledMask,
                                                            (1 << level));
  
                if (data->dpm_level_enable_mask.mclk_dpm_enable_mask) {
                        level = phm_get_lowest_enabled_level(hwmgr,
                                                              data->dpm_level_enable_mask.mclk_dpm_enable_mask);
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                                            PPSMC_MSG_MCLKDPM_SetEnabledMask,
                                                            (1 << level));
                }
                if (data->dpm_level_enable_mask.pcie_dpm_enable_mask) {
                        level = phm_get_lowest_enabled_level(hwmgr,
                                                              data->dpm_level_enable_mask.pcie_dpm_enable_mask);
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                                            PPSMC_MSG_PCIeDPM_ForceLevel,
                                                            (level));
                }
@@@ -2613,16 -2572,51 +2613,16 @@@ static int smu7_force_dpm_level(struct 
        uint32_t sclk_mask = 0;
        uint32_t mclk_mask = 0;
        uint32_t pcie_mask = 0;
 -      uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
 -                                      AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
 -                                      AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
 -                                      AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
 -
 -      if (level == hwmgr->dpm_level)
 -              return ret;
 -
 -      if (!(hwmgr->dpm_level & profile_mode_mask)) {
 -              /* enter profile mode, save current level, disable gfx cg*/
 -              if (level & profile_mode_mask) {
 -                      hwmgr->saved_dpm_level = hwmgr->dpm_level;
 -                      cgs_set_clockgating_state(hwmgr->device,
 -                                              AMD_IP_BLOCK_TYPE_GFX,
 -                                              AMD_CG_STATE_UNGATE);
 -              }
 -      } else {
 -              /* exit profile mode, restore level, enable gfx cg*/
 -              if (!(level & profile_mode_mask)) {
 -                      if (level == AMD_DPM_FORCED_LEVEL_PROFILE_EXIT)
 -                              level = hwmgr->saved_dpm_level;
 -                      cgs_set_clockgating_state(hwmgr->device,
 -                                      AMD_IP_BLOCK_TYPE_GFX,
 -                                      AMD_CG_STATE_GATE);
 -              }
 -      }
  
        switch (level) {
        case AMD_DPM_FORCED_LEVEL_HIGH:
                ret = smu7_force_dpm_highest(hwmgr);
 -              if (ret)
 -                      return ret;
 -              hwmgr->dpm_level = level;
                break;
        case AMD_DPM_FORCED_LEVEL_LOW:
                ret = smu7_force_dpm_lowest(hwmgr);
 -              if (ret)
 -                      return ret;
 -              hwmgr->dpm_level = level;
                break;
        case AMD_DPM_FORCED_LEVEL_AUTO:
                ret = smu7_unforce_dpm_levels(hwmgr);
 -              if (ret)
 -                      return ret;
 -              hwmgr->dpm_level = level;
                break;
        case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
        case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
                ret = smu7_get_profiling_clk(hwmgr, level, &sclk_mask, &mclk_mask, &pcie_mask);
                if (ret)
                        return ret;
 -              hwmgr->dpm_level = level;
                smu7_force_clock_level(hwmgr, PP_SCLK, 1<<sclk_mask);
                smu7_force_clock_level(hwmgr, PP_MCLK, 1<<mclk_mask);
                smu7_force_clock_level(hwmgr, PP_PCIE, 1<<pcie_mask);
 -
                break;
        case AMD_DPM_FORCED_LEVEL_MANUAL:
 -              hwmgr->dpm_level = level;
 -              break;
        case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
        default:
                break;
        }
  
 -      if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->saved_dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
 -              smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
 -      else if (level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->saved_dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
 -              smu7_fan_ctrl_reset_fan_speed_to_default(hwmgr);
 -
 -      return 0;
 +      if (!ret) {
 +              if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
 +                      smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
 +              else if (level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)
 +                      smu7_fan_ctrl_reset_fan_speed_to_default(hwmgr);
 +      }
 +      return ret;
  }
  
  static int smu7_get_power_state_size(struct pp_hwmgr *hwmgr)
@@@ -2846,7 -2843,7 +2846,7 @@@ static int smu7_apply_state_adjust_rule
  }
  
  
 -static int smu7_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
 +static uint32_t smu7_dpm_get_mclk(struct pp_hwmgr *hwmgr, bool low)
  {
        struct pp_power_state  *ps;
        struct smu7_power_state  *smu7_ps;
                                [smu7_ps->performance_level_count-1].memory_clock;
  }
  
 -static int smu7_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
 +static uint32_t smu7_dpm_get_sclk(struct pp_hwmgr *hwmgr, bool low)
  {
        struct pp_power_state  *ps;
        struct smu7_power_state  *smu7_ps;
@@@ -3005,7 -3002,7 +3005,7 @@@ static int smu7_get_pp_table_entry_call
                        [smu7_power_state->performance_level_count++]);
  
        PP_ASSERT_WITH_CODE(
 -                      (smu7_power_state->performance_level_count < smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_GRAPHICS)),
 +                      (smu7_power_state->performance_level_count < smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_GRAPHICS)),
                        "Performance levels exceeds SMC limit!",
                        return -EINVAL);
  
@@@ -3074,11 -3071,11 +3074,11 @@@ static int smu7_get_pp_table_entry_v1(s
        if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
                if (dep_mclk_table->entries[0].clk !=
                                data->vbios_boot_state.mclk_bootup_value)
 -                      pr_err("Single MCLK entry VDDCI/MCLK dependency table "
 +                      pr_debug("Single MCLK entry VDDCI/MCLK dependency table "
                                        "does not match VBIOS boot MCLK level");
                if (dep_mclk_table->entries[0].vddci !=
                                data->vbios_boot_state.vddci_bootup_value)
 -                      pr_err("Single VDDCI entry VDDCI/MCLK dependency table "
 +                      pr_debug("Single VDDCI entry VDDCI/MCLK dependency table "
                                        "does not match VBIOS boot VDDCI level");
        }
  
@@@ -3169,7 -3166,7 +3169,7 @@@ static int smu7_get_pp_table_entry_call
                data->highest_mclk = memory_clock;
  
        PP_ASSERT_WITH_CODE(
 -                      (ps->performance_level_count < smum_get_mac_definition(hwmgr->smumgr, SMU_MAX_LEVELS_GRAPHICS)),
 +                      (ps->performance_level_count < smum_get_mac_definition(hwmgr, SMU_MAX_LEVELS_GRAPHICS)),
                        "Performance levels exceeds SMC limit!",
                        return -EINVAL);
  
@@@ -3222,11 -3219,11 +3222,11 @@@ static int smu7_get_pp_table_entry_v0(s
        if (dep_mclk_table != NULL && dep_mclk_table->count == 1) {
                if (dep_mclk_table->entries[0].clk !=
                                data->vbios_boot_state.mclk_bootup_value)
 -                      pr_err("Single MCLK entry VDDCI/MCLK dependency table "
 +                      pr_debug("Single MCLK entry VDDCI/MCLK dependency table "
                                        "does not match VBIOS boot MCLK level");
                if (dep_mclk_table->entries[0].v !=
                                data->vbios_boot_state.vddci_bootup_value)
 -                      pr_err("Single VDDCI entry VDDCI/MCLK dependency table "
 +                      pr_debug("Single VDDCI entry VDDCI/MCLK dependency table "
                                        "does not match VBIOS boot VDDCI level");
        }
  
@@@ -3315,14 -3312,14 +3315,14 @@@ static int smu7_get_pp_table_entry(stru
  static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr,
                struct pp_gpu_power *query)
  {
 -      PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr,
 +      PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr,
                        PPSMC_MSG_PmStatusLogStart),
                        "Failed to start pm status log!",
                        return -1);
  
        msleep_interruptible(20);
  
 -      PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr->smumgr,
 +      PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(hwmgr,
                        PPSMC_MSG_PmStatusLogSample),
                        "Failed to sample pm status log!",
                        return -1);
@@@ -3356,19 -3353,19 +3356,19 @@@ static int smu7_read_sensor(struct pp_h
  
        switch (idx) {
        case AMDGPU_PP_SENSOR_GFX_SCLK:
 -              smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
 +              smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetSclkFrequency);
                sclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
                *((uint32_t *)value) = sclk;
                *size = 4;
                return 0;
        case AMDGPU_PP_SENSOR_GFX_MCLK:
 -              smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
 +              smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetMclkFrequency);
                mclk = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
                *((uint32_t *)value) = mclk;
                *size = 4;
                return 0;
        case AMDGPU_PP_SENSOR_GPU_LOAD:
 -              offset = data->soft_regs_start + smum_get_offsetof(hwmgr->smumgr,
 +              offset = data->soft_regs_start + smum_get_offsetof(hwmgr,
                                                                SMU_SoftRegisters,
                                                                AverageGraphicsActivity);
  
@@@ -3535,7 -3532,7 +3535,7 @@@ static int smu7_freeze_sclk_mclk_dpm(st
                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
                                "Trying to freeze SCLK DPM when DPM is disabled",
                                );
 -              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
 +              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_SCLKDPM_FreezeLevel),
                                "Failed to freeze SCLK DPM during FreezeSclkMclkDPM Function!",
                                return -EINVAL);
                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
                                "Trying to freeze MCLK DPM when DPM is disabled",
                                );
 -              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
 +              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_MCLKDPM_FreezeLevel),
                                "Failed to freeze MCLK DPM during FreezeSclkMclkDPM Function!",
                                return -EINVAL);
@@@ -3765,7 -3762,7 +3765,7 @@@ static int smu7_unfreeze_sclk_mclk_dpm(
                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
                                "Trying to Unfreeze SCLK DPM when DPM is disabled",
                                );
 -              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
 +              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_SCLKDPM_UnfreezeLevel),
                        "Failed to unfreeze SCLK DPM during UnFreezeSclkMclkDPM Function!",
                        return -EINVAL);
                PP_ASSERT_WITH_CODE(true == smum_is_dpm_running(hwmgr),
                                "Trying to Unfreeze MCLK DPM when DPM is disabled",
                                );
 -              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr->smumgr,
 +              PP_ASSERT_WITH_CODE(0 == smum_send_msg_to_smc(hwmgr,
                                PPSMC_MSG_SCLKDPM_UnfreezeLevel),
                    "Failed to unfreeze MCLK DPM during UnFreezeSclkMclkDPM Function!",
                    return -EINVAL);
@@@ -3827,9 -3824,9 +3827,9 @@@ static int smu7_notify_smc_display(stru
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
  
        if (hwmgr->feature_mask & PP_VBI_TIME_SUPPORT_MASK)
 -              smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +              smum_send_msg_to_smc_with_parameter(hwmgr,
                        (PPSMC_Msg)PPSMC_MSG_SetVBITimeout, data->frame_time_x2);
 -      return (smum_send_msg_to_smc(hwmgr->smumgr, (PPSMC_Msg)PPSMC_HasDisplay) == 0) ?  0 : -EINVAL;
 +      return (smum_send_msg_to_smc(hwmgr, (PPSMC_Msg)PPSMC_HasDisplay) == 0) ?  0 : -EINVAL;
  }
  
  static int smu7_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input)
@@@ -3902,7 -3899,10 +3902,7 @@@ static int smu7_set_max_fan_pwm_output(
        hwmgr->thermal_controller.
        advanceFanControlParameters.usMaxFanPWM = us_max_fan_pwm;
  
 -      if (phm_is_hw_access_blocked(hwmgr))
 -              return 0;
 -
 -      return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +      return smum_send_msg_to_smc_with_parameter(hwmgr,
                        PPSMC_MSG_SetFanPwmMax, us_max_fan_pwm);
  }
  
@@@ -3911,7 -3911,7 +3911,7 @@@ smu7_notify_smc_display_change(struct p
  {
        PPSMC_Msg msg = has_display ? (PPSMC_Msg)PPSMC_HasDisplay : (PPSMC_Msg)PPSMC_NoDisplay;
  
 -      return (smum_send_msg_to_smc(hwmgr->smumgr, msg) == 0) ?  0 : -1;
 +      return (smum_send_msg_to_smc(hwmgr, msg) == 0) ?  0 : -1;
  }
  
  static int
@@@ -3948,10 -3948,9 +3948,9 @@@ static int smu7_program_display_gap(str
        uint32_t ref_clock;
        uint32_t refresh_rate = 0;
        struct cgs_display_info info = {0};
-       struct cgs_mode_info mode_info;
+       struct cgs_mode_info mode_info = {0};
  
        info.mode_info = &mode_info;
        cgs_get_active_displays_info(hwmgr->device, &info);
        num_active_displays = info.display_count;
  
        frame_time_in_us = 1000000 / refresh_rate;
  
        pre_vbi_time_in_us = frame_time_in_us - 200 - mode_info.vblank_time_us;
        data->frame_time_x2 = frame_time_in_us * 2 / 100;
  
        display_gap2 = pre_vbi_time_in_us * (ref_clock / 100);
        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2);
  
        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      data->soft_regs_start + smum_get_offsetof(hwmgr->smumgr,
 +                      data->soft_regs_start + smum_get_offsetof(hwmgr,
                                                        SMU_SoftRegisters,
                                                        PreVBlankGap), 0x64);
  
        cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 -                      data->soft_regs_start + smum_get_offsetof(hwmgr->smumgr,
 +                      data->soft_regs_start + smum_get_offsetof(hwmgr,
                                                        SMU_SoftRegisters,
                                                        VBlankTimeout),
                                        (frame_time_in_us - pre_vbi_time_in_us));
@@@ -4004,7 -4004,10 +4004,7 @@@ static int smu7_set_max_fan_rpm_output(
        hwmgr->thermal_controller.
        advanceFanControlParameters.usMaxFanRPM = us_max_fan_rpm;
  
 -      if (phm_is_hw_access_blocked(hwmgr))
 -              return 0;
 -
 -      return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +      return smum_send_msg_to_smc_with_parameter(hwmgr,
                        PPSMC_MSG_SetFanRpmMax, us_max_fan_rpm);
  }
  
@@@ -4246,21 -4249,21 +4246,21 @@@ static int smu7_force_clock_level(struc
  {
        struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
  
 -      if (hwmgr->dpm_level & (AMD_DPM_FORCED_LEVEL_AUTO |
 -                              AMD_DPM_FORCED_LEVEL_LOW |
 -                              AMD_DPM_FORCED_LEVEL_HIGH))
 +      if (hwmgr->request_dpm_level & (AMD_DPM_FORCED_LEVEL_AUTO |
 +                                      AMD_DPM_FORCED_LEVEL_LOW |
 +                                      AMD_DPM_FORCED_LEVEL_HIGH))
                return -EINVAL;
  
        switch (type) {
        case PP_SCLK:
                if (!data->sclk_dpm_key_disabled)
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_SCLKDPM_SetEnabledMask,
                                        data->dpm_level_enable_mask.sclk_dpm_enable_mask & mask);
                break;
        case PP_MCLK:
                if (!data->mclk_dpm_key_disabled)
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_MCLKDPM_SetEnabledMask,
                                        data->dpm_level_enable_mask.mclk_dpm_enable_mask & mask);
                break;
                        level++;
  
                if (!data->pcie_dpm_key_disabled)
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                        PPSMC_MSG_PCIeDPM_ForceLevel,
                                        level);
                break;
@@@ -4297,7 -4300,7 +4297,7 @@@ static int smu7_print_clock_levels(stru
  
        switch (type) {
        case PP_SCLK:
 -              smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetSclkFrequency);
 +              smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetSclkFrequency);
                clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
  
                for (i = 0; i < sclk_table->count; i++) {
                                        (i == now) ? "*" : "");
                break;
        case PP_MCLK:
 -              smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_API_GetMclkFrequency);
 +              smum_send_msg_to_smc(hwmgr, PPSMC_MSG_API_GetMclkFrequency);
                clock = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0);
  
                for (i = 0; i < mclk_table->count; i++) {
        return size;
  }
  
 -static int smu7_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
 +static void smu7_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
  {
 -      int result = 0;
 -
        switch (mode) {
        case AMD_FAN_CTRL_NONE:
 -              result = smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
 +              smu7_fan_ctrl_set_fan_speed_percent(hwmgr, 100);
                break;
        case AMD_FAN_CTRL_MANUAL:
                if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
                        PHM_PlatformCaps_MicrocodeFanControl))
 -                      result = smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
 +                      smu7_fan_ctrl_stop_smc_fan_control(hwmgr);
                break;
        case AMD_FAN_CTRL_AUTO:
 -              result = smu7_fan_ctrl_set_static_mode(hwmgr, mode);
 -              if (!result)
 -                      result = smu7_fan_ctrl_start_smc_fan_control(hwmgr);
 +              if (!smu7_fan_ctrl_set_static_mode(hwmgr, mode))
 +                      smu7_fan_ctrl_start_smc_fan_control(hwmgr);
                break;
        default:
                break;
        }
 -      return result;
  }
  
 -static int smu7_get_fan_control_mode(struct pp_hwmgr *hwmgr)
 +static uint32_t smu7_get_fan_control_mode(struct pp_hwmgr *hwmgr)
  {
        return hwmgr->fan_ctrl_enabled ? AMD_FAN_CTRL_AUTO : AMD_FAN_CTRL_MANUAL;
  }
@@@ -4599,7 -4606,7 +4599,7 @@@ static int smu7_set_power_profile_state
  
        if (sclk_mask) {
                if (!data->sclk_dpm_key_disabled)
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                PPSMC_MSG_SCLKDPM_SetEnabledMask,
                                data->dpm_level_enable_mask.
                                sclk_dpm_enable_mask &
  
        if (mclk_mask) {
                if (!data->mclk_dpm_key_disabled)
 -                      smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
 +                      smum_send_msg_to_smc_with_parameter(hwmgr,
                                PPSMC_MSG_MCLKDPM_SetEnabledMask,
                                data->dpm_level_enable_mask.
                                mclk_dpm_enable_mask &
  
  static int smu7_avfs_control(struct pp_hwmgr *hwmgr, bool enable)
  {
 -      struct pp_smumgr *smumgr = (struct pp_smumgr *)(hwmgr->smumgr);
 -      struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(smumgr->backend);
 +      struct smu7_smumgr *smu_data = (struct smu7_smumgr *)(hwmgr->smu_backend);
  
        if (smu_data == NULL)
                return -EINVAL;
                if (!PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
                                CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON))
                        PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(
 -                                      hwmgr->smumgr, PPSMC_MSG_EnableAvfs),
 +                                      hwmgr, PPSMC_MSG_EnableAvfs),
                                        "Failed to enable AVFS!",
                                        return -EINVAL);
        } else if (PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device,
                        CGS_IND_REG__SMC, FEATURE_STATUS, AVS_ON))
                PP_ASSERT_WITH_CODE(!smum_send_msg_to_smc(
 -                              hwmgr->smumgr, PPSMC_MSG_DisableAvfs),
 +                              hwmgr, PPSMC_MSG_DisableAvfs),
                                "Failed to disable AVFS!",
                                return -EINVAL);
  
        return 0;
  }
  
 +static int smu7_notify_cac_buffer_info(struct pp_hwmgr *hwmgr,
 +                                      uint32_t virtual_addr_low,
 +                                      uint32_t virtual_addr_hi,
 +                                      uint32_t mc_addr_low,
 +                                      uint32_t mc_addr_hi,
 +                                      uint32_t size)
 +{
 +      struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
 +
 +      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 +                                      data->soft_regs_start +
 +                                      smum_get_offsetof(hwmgr,
 +                                      SMU_SoftRegisters, DRAM_LOG_ADDR_H),
 +                                      mc_addr_hi);
 +
 +      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 +                                      data->soft_regs_start +
 +                                      smum_get_offsetof(hwmgr,
 +                                      SMU_SoftRegisters, DRAM_LOG_ADDR_L),
 +                                      mc_addr_low);
 +
 +      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 +                                      data->soft_regs_start +
 +                                      smum_get_offsetof(hwmgr,
 +                                      SMU_SoftRegisters, DRAM_LOG_PHY_ADDR_H),
 +                                      virtual_addr_hi);
 +
 +      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 +                                      data->soft_regs_start +
 +                                      smum_get_offsetof(hwmgr,
 +                                      SMU_SoftRegisters, DRAM_LOG_PHY_ADDR_L),
 +                                      virtual_addr_low);
 +
 +      cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
 +                                      data->soft_regs_start +
 +                                      smum_get_offsetof(hwmgr,
 +                                      SMU_SoftRegisters, DRAM_LOG_BUFF_SIZE),
 +                                      size);
 +      return 0;
 +}
 +
  static const struct pp_hwmgr_func smu7_hwmgr_funcs = {
        .backend_init = &smu7_hwmgr_backend_init,
        .backend_fini = &smu7_hwmgr_backend_fini,
        .set_power_profile_state = smu7_set_power_profile_state,
        .avfs_control = smu7_avfs_control,
        .disable_smc_firmware_ctf = smu7_thermal_disable_alert,
 +      .start_thermal_controller = smu7_start_thermal_controller,
 +      .notify_cac_buffer_info = smu7_notify_cac_buffer_info,
  };
  
  uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock,
index 2c0ccbb817dcff539b0523e0c25df9daaa870884,d4726a3358a4a5b241ff50af1efb9ddcd64f4fbf..701a3c6f16696f9615ff52d7d81b2589d31bb99f
@@@ -1576,11 -1576,11 +1576,11 @@@ static int batch_buffer_needs_scan(stru
        return 1;
  }
  
 -static uint32_t find_bb_size(struct parser_exec_state *s)
 +static int find_bb_size(struct parser_exec_state *s)
  {
        unsigned long gma = 0;
        struct cmd_info *info;
 -      uint32_t bb_size = 0;
 +      int bb_size = 0;
        uint32_t cmd_len = 0;
        bool met_bb_end = false;
        struct intel_vgpu *vgpu = s->vgpu;
@@@ -1637,8 -1637,6 +1637,8 @@@ static int perform_bb_shadow(struct par
  
        /* get the size of the batch buffer */
        bb_size = find_bb_size(s);
 +      if (bb_size < 0)
 +              return -EINVAL;
  
        /* allocate shadow batch buffer */
        entry_obj = kmalloc(sizeof(*entry_obj), GFP_KERNEL);
@@@ -2605,8 -2603,7 +2605,8 @@@ static int shadow_workload_ring_buffer(
  {
        struct intel_vgpu *vgpu = workload->vgpu;
        unsigned long gma_head, gma_tail, gma_top, guest_rb_size;
 -      u32 *cs;
 +      void *shadow_ring_buffer_va;
 +      int ring_id = workload->ring_id;
        int ret;
  
        guest_rb_size = _RING_CTL_BUF_SIZE(workload->rb_ctl);
        gma_tail = workload->rb_start + workload->rb_tail;
        gma_top = workload->rb_start + guest_rb_size;
  
 -      /* allocate shadow ring buffer */
 -      cs = intel_ring_begin(workload->req, workload->rb_len / sizeof(u32));
 -      if (IS_ERR(cs))
 -              return PTR_ERR(cs);
 +      if (workload->rb_len > vgpu->reserve_ring_buffer_size[ring_id]) {
 +              void *va = vgpu->reserve_ring_buffer_va[ring_id];
 +              /* realloc the new ring buffer if needed */
 +              vgpu->reserve_ring_buffer_va[ring_id] =
 +                      krealloc(va, workload->rb_len, GFP_KERNEL);
 +              if (!vgpu->reserve_ring_buffer_va[ring_id]) {
 +                      gvt_vgpu_err("fail to alloc reserve ring buffer\n");
 +                      return -ENOMEM;
 +              }
 +              vgpu->reserve_ring_buffer_size[ring_id] = workload->rb_len;
 +      }
 +
 +      shadow_ring_buffer_va = vgpu->reserve_ring_buffer_va[ring_id];
  
        /* get shadow ring buffer va */
 -      workload->shadow_ring_buffer_va = cs;
 +      workload->shadow_ring_buffer_va = shadow_ring_buffer_va;
  
        /* head > tail --> copy head <-> top */
        if (gma_head > gma_tail) {
                ret = copy_gma_to_hva(vgpu, vgpu->gtt.ggtt_mm,
 -                                    gma_head, gma_top, cs);
 +                                    gma_head, gma_top, shadow_ring_buffer_va);
                if (ret < 0) {
                        gvt_vgpu_err("fail to copy guest ring buffer\n");
                        return ret;
                }
 -              cs += ret / sizeof(u32);
 +              shadow_ring_buffer_va += ret;
                gma_head = workload->rb_start;
        }
  
        /* copy head or start <-> tail */
 -      ret = copy_gma_to_hva(vgpu, vgpu->gtt.ggtt_mm, gma_head, gma_tail, cs);
 +      ret = copy_gma_to_hva(vgpu, vgpu->gtt.ggtt_mm, gma_head, gma_tail,
 +                              shadow_ring_buffer_va);
        if (ret < 0) {
                gvt_vgpu_err("fail to copy guest ring buffer\n");
                return ret;
        }
 -      cs += ret / sizeof(u32);
 -      intel_ring_advance(workload->req, cs);
        return 0;
  }
  
@@@ -2734,6 -2723,9 +2734,9 @@@ static int combine_wa_ctx(struct intel_
        uint32_t per_ctx_start[CACHELINE_DWORDS] = {0};
        unsigned char *bb_start_sva;
  
+       if (!wa_ctx->per_ctx.valid)
+               return 0;
        per_ctx_start[0] = 0x18800001;
        per_ctx_start[1] = wa_ctx->per_ctx.guest_gma;
  
index 5ec07ecf33ad106a96391a8adc6e749fe6158d8b,e5320b4eb698e9793ab1d6d8284935422b706a89..4427be18e4a93c72eaccae1fc263b044279c5fe8
@@@ -368,7 -368,7 +368,7 @@@ static void free_workload(struct intel_
  #define get_desc_from_elsp_dwords(ed, i) \
        ((struct execlist_ctx_descriptor_format *)&((ed)->data[i * 2]))
  
 -static void prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
 +static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
  {
        const int gmadr_bytes = workload->vgpu->gvt->device_info.gmadr_bytes_in_cmd;
        struct intel_shadow_bb_entry *entry_obj;
  
                vma = i915_gem_object_ggtt_pin(entry_obj->obj, NULL, 0, 4, 0);
                if (IS_ERR(vma)) {
 -                      return;
 +                      return PTR_ERR(vma);
                }
  
                /* FIXME: we are not tracking our pinned VMA leaving it
                if (gmadr_bytes == 8)
                        entry_obj->bb_start_cmd_va[2] = 0;
        }
 +      return 0;
  }
  
  static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
        return 0;
  }
  
 -static void prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
 +static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
  {
        struct i915_vma *vma;
        unsigned char *per_ctx_va =
                wa_ctx->indirect_ctx.size;
  
        if (wa_ctx->indirect_ctx.size == 0)
 -              return;
 +              return 0;
  
        vma = i915_gem_object_ggtt_pin(wa_ctx->indirect_ctx.obj, NULL,
                                       0, CACHELINE_BYTES, 0);
        if (IS_ERR(vma)) {
 -              return;
 +              return PTR_ERR(vma);
        }
  
        /* FIXME: we are not tracking our pinned VMA leaving it
        memset(per_ctx_va, 0, CACHELINE_BYTES);
  
        update_wa_ctx_2_shadow_ctx(wa_ctx);
 -}
 -
 -static int prepare_execlist_workload(struct intel_vgpu_workload *workload)
 -{
 -      struct intel_vgpu *vgpu = workload->vgpu;
 -      struct execlist_ctx_descriptor_format ctx[2];
 -      int ring_id = workload->ring_id;
 -
 -      intel_vgpu_pin_mm(workload->shadow_mm);
 -      intel_vgpu_sync_oos_pages(workload->vgpu);
 -      intel_vgpu_flush_post_shadow(workload->vgpu);
 -      prepare_shadow_batch_buffer(workload);
 -      prepare_shadow_wa_ctx(&workload->wa_ctx);
 -      if (!workload->emulate_schedule_in)
 -              return 0;
 -
 -      ctx[0] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 1);
 -      ctx[1] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 0);
 -
 -      return emulate_execlist_schedule_in(&vgpu->execlist[ring_id], ctx);
 +      return 0;
  }
  
  static void release_shadow_batch_buffer(struct intel_vgpu_workload *workload)
        }
  }
  
 -static void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
 +static int prepare_execlist_workload(struct intel_vgpu_workload *workload)
  {
 -      if (!wa_ctx->indirect_ctx.obj)
 -              return;
 +      struct intel_vgpu *vgpu = workload->vgpu;
 +      struct execlist_ctx_descriptor_format ctx[2];
 +      int ring_id = workload->ring_id;
 +      int ret;
 +
 +      ret = intel_vgpu_pin_mm(workload->shadow_mm);
 +      if (ret) {
 +              gvt_vgpu_err("fail to vgpu pin mm\n");
 +              goto out;
 +      }
 +
 +      ret = intel_vgpu_sync_oos_pages(workload->vgpu);
 +      if (ret) {
 +              gvt_vgpu_err("fail to vgpu sync oos pages\n");
 +              goto err_unpin_mm;
 +      }
  
 -      i915_gem_object_unpin_map(wa_ctx->indirect_ctx.obj);
 -      i915_gem_object_put(wa_ctx->indirect_ctx.obj);
 +      ret = intel_vgpu_flush_post_shadow(workload->vgpu);
 +      if (ret) {
 +              gvt_vgpu_err("fail to flush post shadow\n");
 +              goto err_unpin_mm;
 +      }
 +
 +      ret = prepare_shadow_batch_buffer(workload);
 +      if (ret) {
 +              gvt_vgpu_err("fail to prepare_shadow_batch_buffer\n");
 +              goto err_unpin_mm;
 +      }
 +
 +      ret = prepare_shadow_wa_ctx(&workload->wa_ctx);
 +      if (ret) {
 +              gvt_vgpu_err("fail to prepare_shadow_wa_ctx\n");
 +              goto err_shadow_batch;
 +      }
 +
 +      if (!workload->emulate_schedule_in)
 +              return 0;
 +
 +      ctx[0] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 1);
 +      ctx[1] = *get_desc_from_elsp_dwords(&workload->elsp_dwords, 0);
 +
 +      ret = emulate_execlist_schedule_in(&vgpu->execlist[ring_id], ctx);
 +      if (!ret)
 +              goto out;
 +      else
 +              gvt_vgpu_err("fail to emulate execlist schedule in\n");
 +
 +      release_shadow_wa_ctx(&workload->wa_ctx);
 +err_shadow_batch:
 +      release_shadow_batch_buffer(workload);
 +err_unpin_mm:
 +      intel_vgpu_unpin_mm(workload->shadow_mm);
 +out:
 +      return ret;
  }
  
  static int complete_execlist_workload(struct intel_vgpu_workload *workload)
        gvt_dbg_el("complete workload %p status %d\n", workload,
                        workload->status);
  
 -      release_shadow_batch_buffer(workload);
 -      release_shadow_wa_ctx(&workload->wa_ctx);
 +      if (!workload->status) {
 +              release_shadow_batch_buffer(workload);
 +              release_shadow_wa_ctx(&workload->wa_ctx);
 +      }
  
        if (workload->status || (vgpu->resetting_eng & ENGINE_MASK(ring_id))) {
                /* if workload->status is not successful means HW GPU
@@@ -734,8 -701,7 +734,7 @@@ static int submit_context(struct intel_
                        CACHELINE_BYTES;
                workload->wa_ctx.per_ctx.guest_gma =
                        per_ctx & PER_CTX_ADDR_MASK;
-               WARN_ON(workload->wa_ctx.indirect_ctx.size && !(per_ctx & 0x1));
+               workload->wa_ctx.per_ctx.valid = per_ctx & 1;
        }
  
        if (emulate_schedule_in)
@@@ -853,21 -819,10 +852,21 @@@ static void clean_workloads(struct inte
  
  void intel_vgpu_clean_execlist(struct intel_vgpu *vgpu)
  {
 +      enum intel_engine_id i;
 +      struct intel_engine_cs *engine;
 +
        clean_workloads(vgpu, ALL_ENGINES);
        kmem_cache_destroy(vgpu->workloads);
 +
 +      for_each_engine(engine, vgpu->gvt->dev_priv, i) {
 +              kfree(vgpu->reserve_ring_buffer_va[i]);
 +              vgpu->reserve_ring_buffer_va[i] = NULL;
 +              vgpu->reserve_ring_buffer_size[i] = 0;
 +      }
 +
  }
  
 +#define RESERVE_RING_BUFFER_SIZE              ((1 * PAGE_SIZE)/8)
  int intel_vgpu_init_execlist(struct intel_vgpu *vgpu)
  {
        enum intel_engine_id i;
        if (!vgpu->workloads)
                return -ENOMEM;
  
 +      /* each ring has a shadow ring buffer until vgpu destroyed */
 +      for_each_engine(engine, vgpu->gvt->dev_priv, i) {
 +              vgpu->reserve_ring_buffer_va[i] =
 +                      kmalloc(RESERVE_RING_BUFFER_SIZE, GFP_KERNEL);
 +              if (!vgpu->reserve_ring_buffer_va[i]) {
 +                      gvt_vgpu_err("fail to alloc reserve ring buffer\n");
 +                      goto out;
 +              }
 +              vgpu->reserve_ring_buffer_size[i] = RESERVE_RING_BUFFER_SIZE;
 +      }
        return 0;
 +out:
 +      for_each_engine(engine, vgpu->gvt->dev_priv, i) {
 +              if (vgpu->reserve_ring_buffer_size[i]) {
 +                      kfree(vgpu->reserve_ring_buffer_va[i]);
 +                      vgpu->reserve_ring_buffer_va[i] = NULL;
 +                      vgpu->reserve_ring_buffer_size[i] = 0;
 +              }
 +      }
 +      return -ENOMEM;
  }
  
  void intel_vgpu_reset_execlist(struct intel_vgpu *vgpu,
index f36b85fd6d0195088a2d0d79dae95fc97fc03786,93a49eb0209ee645818a673a07d8a31291840ce7..2d694f6c09076a31efc3165dc074312527450345
@@@ -68,6 -68,7 +68,7 @@@ struct shadow_indirect_ctx 
  struct shadow_per_ctx {
        unsigned long guest_gma;
        unsigned long shadow_gma;
+       unsigned valid;
  };
  
  struct intel_shadow_wa_ctx {
@@@ -140,5 -141,4 +141,5 @@@ int intel_vgpu_init_gvt_context(struct 
  
  void intel_vgpu_clean_gvt_context(struct intel_vgpu *vgpu);
  
 +void release_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx);
  #endif
index 20fcac37c85a0f2332a84c8d4922e26dc88b7466,32e857dc507cf9b1a9247f3bab497616d82e60a9..49762bc21ed64388226d7d7c62cdce0047ab69f7
@@@ -35,7 -35,6 +35,7 @@@
  #include "intel_drv.h"
  #include "intel_frontbuffer.h"
  #include "intel_mocs.h"
 +#include "i915_gemfs.h"
  #include <linux/dma-fence-array.h>
  #include <linux/kthread.h>
  #include <linux/reservation.h>
@@@ -162,7 -161,8 +162,7 @@@ i915_gem_get_aperture_ioctl(struct drm_
        return 0;
  }
  
 -static struct sg_table *
 -i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
 +static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
  {
        struct address_space *mapping = obj->base.filp->f_mapping;
        drm_dma_handle_t *phys;
        struct scatterlist *sg;
        char *vaddr;
        int i;
 +      int err;
  
        if (WARN_ON(i915_gem_object_needs_bit17_swizzle(obj)))
 -              return ERR_PTR(-EINVAL);
 +              return -EINVAL;
  
        /* Always aligning to the object size, allows a single allocation
         * to handle all possible callers, and given typical object sizes,
         * the alignment of the buddy allocation will naturally match.
         */
        phys = drm_pci_alloc(obj->base.dev,
 -                           obj->base.size,
 +                           roundup_pow_of_two(obj->base.size),
                             roundup_pow_of_two(obj->base.size));
        if (!phys)
 -              return ERR_PTR(-ENOMEM);
 +              return -ENOMEM;
  
        vaddr = phys->vaddr;
        for (i = 0; i < obj->base.size / PAGE_SIZE; i++) {
  
                page = shmem_read_mapping_page(mapping, i);
                if (IS_ERR(page)) {
 -                      st = ERR_CAST(page);
 +                      err = PTR_ERR(page);
                        goto err_phys;
                }
  
  
        st = kmalloc(sizeof(*st), GFP_KERNEL);
        if (!st) {
 -              st = ERR_PTR(-ENOMEM);
 +              err = -ENOMEM;
                goto err_phys;
        }
  
        if (sg_alloc_table(st, 1, GFP_KERNEL)) {
                kfree(st);
 -              st = ERR_PTR(-ENOMEM);
 +              err = -ENOMEM;
                goto err_phys;
        }
  
        sg_dma_len(sg) = obj->base.size;
  
        obj->phys_handle = phys;
 -      return st;
 +
 +      __i915_gem_object_set_pages(obj, st, sg->length);
 +
 +      return 0;
  
  err_phys:
        drm_pci_free(obj->base.dev, phys);
 -      return st;
 +
 +      return err;
  }
  
  static void __start_cpu_write(struct drm_i915_gem_object *obj)
@@@ -358,7 -353,7 +358,7 @@@ static lon
  i915_gem_object_wait_fence(struct dma_fence *fence,
                           unsigned int flags,
                           long timeout,
 -                         struct intel_rps_client *rps)
 +                         struct intel_rps_client *rps_client)
  {
        struct drm_i915_gem_request *rq;
  
         * forcing the clocks too high for the whole system, we only allow
         * each client to waitboost once in a busy period.
         */
 -      if (rps) {
 +      if (rps_client) {
                if (INTEL_GEN(rq->i915) >= 6)
 -                      gen6_rps_boost(rq, rps);
 +                      gen6_rps_boost(rq, rps_client);
                else
 -                      rps = NULL;
 +                      rps_client = NULL;
        }
  
        timeout = i915_wait_request(rq, flags, timeout);
@@@ -411,7 -406,7 +411,7 @@@ static lon
  i915_gem_object_wait_reservation(struct reservation_object *resv,
                                 unsigned int flags,
                                 long timeout,
 -                               struct intel_rps_client *rps)
 +                               struct intel_rps_client *rps_client)
  {
        unsigned int seq = __read_seqcount_begin(&resv->seq);
        struct dma_fence *excl;
                for (i = 0; i < count; i++) {
                        timeout = i915_gem_object_wait_fence(shared[i],
                                                             flags, timeout,
 -                                                           rps);
 +                                                           rps_client);
                        if (timeout < 0)
                                break;
  
        }
  
        if (excl && timeout >= 0) {
 -              timeout = i915_gem_object_wait_fence(excl, flags, timeout, rps);
 +              timeout = i915_gem_object_wait_fence(excl, flags, timeout,
 +                                                   rps_client);
                prune_fences = timeout >= 0;
        }
  
@@@ -544,7 -538,7 +544,7 @@@ in
  i915_gem_object_wait(struct drm_i915_gem_object *obj,
                     unsigned int flags,
                     long timeout,
 -                   struct intel_rps_client *rps)
 +                   struct intel_rps_client *rps_client)
  {
        might_sleep();
  #if IS_ENABLED(CONFIG_LOCKDEP)
  
        timeout = i915_gem_object_wait_reservation(obj->resv,
                                                   flags, timeout,
 -                                                 rps);
 +                                                 rps_client);
        return timeout < 0 ? timeout : 0;
  }
  
@@@ -564,7 -558,7 +564,7 @@@ static struct intel_rps_client *to_rps_
  {
        struct drm_i915_file_private *fpriv = file->driver_priv;
  
 -      return &fpriv->rps;
 +      return &fpriv->rps_client;
  }
  
  static int
@@@ -700,10 -694,10 +700,10 @@@ flush_write_domain(struct drm_i915_gem_
  
        switch (obj->base.write_domain) {
        case I915_GEM_DOMAIN_GTT:
 -              if (INTEL_GEN(dev_priv) >= 6 && !HAS_LLC(dev_priv)) {
 +              if (!HAS_LLC(dev_priv)) {
                        intel_runtime_pm_get(dev_priv);
                        spin_lock_irq(&dev_priv->uncore.lock);
 -                      POSTING_READ_FW(RING_ACTHD(dev_priv->engine[RCS]->mmio_base));
 +                      POSTING_READ_FW(RING_HEAD(dev_priv->engine[RCS]->mmio_base));
                        spin_unlock_irq(&dev_priv->uncore.lock);
                        intel_runtime_pm_put(dev_priv);
                }
@@@ -1019,20 -1013,17 +1019,20 @@@ gtt_user_read(struct io_mapping *mappin
              loff_t base, int offset,
              char __user *user_data, int length)
  {
 -      void *vaddr;
 +      void __iomem *vaddr;
        unsigned long unwritten;
  
        /* We can use the cpu mem copy function because this is X86. */
 -      vaddr = (void __force *)io_mapping_map_atomic_wc(mapping, base);
 -      unwritten = __copy_to_user_inatomic(user_data, vaddr + offset, length);
 +      vaddr = io_mapping_map_atomic_wc(mapping, base);
 +      unwritten = __copy_to_user_inatomic(user_data,
 +                                          (void __force *)vaddr + offset,
 +                                          length);
        io_mapping_unmap_atomic(vaddr);
        if (unwritten) {
 -              vaddr = (void __force *)
 -                      io_mapping_map_wc(mapping, base, PAGE_SIZE);
 -              unwritten = copy_to_user(user_data, vaddr + offset, length);
 +              vaddr = io_mapping_map_wc(mapping, base, PAGE_SIZE);
 +              unwritten = copy_to_user(user_data,
 +                                       (void __force *)vaddr + offset,
 +                                       length);
                io_mapping_unmap(vaddr);
        }
        return unwritten;
@@@ -1056,9 -1047,7 +1056,9 @@@ i915_gem_gtt_pread(struct drm_i915_gem_
  
        intel_runtime_pm_get(i915);
        vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
 -                                     PIN_MAPPABLE | PIN_NONBLOCK);
 +                                     PIN_MAPPABLE |
 +                                     PIN_NONFAULT |
 +                                     PIN_NONBLOCK);
        if (!IS_ERR(vma)) {
                node.start = i915_ggtt_offset(vma);
                node.allocated = false;
@@@ -1200,18 -1189,18 +1200,18 @@@ ggtt_write(struct io_mapping *mapping
           loff_t base, int offset,
           char __user *user_data, int length)
  {
 -      void *vaddr;
 +      void __iomem *vaddr;
        unsigned long unwritten;
  
        /* We can use the cpu mem copy function because this is X86. */
 -      vaddr = (void __force *)io_mapping_map_atomic_wc(mapping, base);
 -      unwritten = __copy_from_user_inatomic_nocache(vaddr + offset,
 +      vaddr = io_mapping_map_atomic_wc(mapping, base);
 +      unwritten = __copy_from_user_inatomic_nocache((void __force *)vaddr + offset,
                                                      user_data, length);
        io_mapping_unmap_atomic(vaddr);
        if (unwritten) {
 -              vaddr = (void __force *)
 -                      io_mapping_map_wc(mapping, base, PAGE_SIZE);
 -              unwritten = copy_from_user(vaddr + offset, user_data, length);
 +              vaddr = io_mapping_map_wc(mapping, base, PAGE_SIZE);
 +              unwritten = copy_from_user((void __force *)vaddr + offset,
 +                                         user_data, length);
                io_mapping_unmap(vaddr);
        }
  
@@@ -1242,9 -1231,7 +1242,9 @@@ i915_gem_gtt_pwrite_fast(struct drm_i91
  
        intel_runtime_pm_get(i915);
        vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
 -                                     PIN_MAPPABLE | PIN_NONBLOCK);
 +                                     PIN_MAPPABLE |
 +                                     PIN_NONFAULT |
 +                                     PIN_NONBLOCK);
        if (!IS_ERR(vma)) {
                node.start = i915_ggtt_offset(vma);
                node.allocated = false;
@@@ -1915,27 -1902,22 +1915,27 @@@ int i915_gem_fault(struct vm_fault *vmf
        if (ret)
                goto err_unpin;
  
 -      ret = i915_vma_get_fence(vma);
 +      ret = i915_vma_pin_fence(vma);
        if (ret)
                goto err_unpin;
  
 -      /* Mark as being mmapped into userspace for later revocation */
 -      assert_rpm_wakelock_held(dev_priv);
 -      if (list_empty(&obj->userfault_link))
 -              list_add(&obj->userfault_link, &dev_priv->mm.userfault_list);
 -
        /* Finally, remap it using the new GTT offset */
        ret = remap_io_mapping(area,
                               area->vm_start + (vma->ggtt_view.partial.offset << PAGE_SHIFT),
                               (ggtt->mappable_base + vma->node.start) >> PAGE_SHIFT,
                               min_t(u64, vma->size, area->vm_end - area->vm_start),
                               &ggtt->mappable);
 +      if (ret)
 +              goto err_fence;
 +
 +      /* Mark as being mmapped into userspace for later revocation */
 +      assert_rpm_wakelock_held(dev_priv);
 +      if (!i915_vma_set_userfault(vma) && !obj->userfault_count++)
 +              list_add(&obj->userfault_link, &dev_priv->mm.userfault_list);
 +      GEM_BUG_ON(!obj->userfault_count);
  
 +err_fence:
 +      i915_vma_unpin_fence(vma);
  err_unpin:
        __i915_vma_unpin(vma);
  err_unlock:
        return ret;
  }
  
 +static void __i915_gem_object_release_mmap(struct drm_i915_gem_object *obj)
 +{
 +      struct i915_vma *vma;
 +
 +      GEM_BUG_ON(!obj->userfault_count);
 +
 +      obj->userfault_count = 0;
 +      list_del(&obj->userfault_link);
 +      drm_vma_node_unmap(&obj->base.vma_node,
 +                         obj->base.dev->anon_inode->i_mapping);
 +
 +      list_for_each_entry(vma, &obj->vma_list, obj_link) {
 +              if (!i915_vma_is_ggtt(vma))
 +                      break;
 +
 +              i915_vma_unset_userfault(vma);
 +      }
 +}
 +
  /**
   * i915_gem_release_mmap - remove physical page mappings
   * @obj: obj in question
@@@ -2036,10 -1999,12 +2036,10 @@@ i915_gem_release_mmap(struct drm_i915_g
        lockdep_assert_held(&i915->drm.struct_mutex);
        intel_runtime_pm_get(i915);
  
 -      if (list_empty(&obj->userfault_link))
 +      if (!obj->userfault_count)
                goto out;
  
 -      list_del_init(&obj->userfault_link);
 -      drm_vma_node_unmap(&obj->base.vma_node,
 -                         obj->base.dev->anon_inode->i_mapping);
 +      __i915_gem_object_release_mmap(obj);
  
        /* Ensure that the CPU's PTE are revoked and there are not outstanding
         * memory transactions from userspace before we return. The TLB
@@@ -2067,8 -2032,11 +2067,8 @@@ void i915_gem_runtime_suspend(struct dr
         */
  
        list_for_each_entry_safe(obj, on,
 -                               &dev_priv->mm.userfault_list, userfault_link) {
 -              list_del_init(&obj->userfault_link);
 -              drm_vma_node_unmap(&obj->base.vma_node,
 -                                 obj->base.dev->anon_inode->i_mapping);
 -      }
 +                               &dev_priv->mm.userfault_list, userfault_link)
 +              __i915_gem_object_release_mmap(obj);
  
        /* The fence will be lost when the device powers down. If any were
         * in use by hardware (i.e. they are pinned), we should not be powering
                if (!reg->vma)
                        continue;
  
 -              GEM_BUG_ON(!list_empty(&reg->vma->obj->userfault_link));
 +              GEM_BUG_ON(i915_vma_has_userfault(reg->vma));
                reg->dirty = true;
        }
  }
@@@ -2290,8 -2258,6 +2290,8 @@@ void __i915_gem_object_put_pages(struc
        if (!IS_ERR(pages))
                obj->ops->put_pages(obj, pages);
  
 +      obj->mm.page_sizes.phys = obj->mm.page_sizes.sg = 0;
 +
  unlock:
        mutex_unlock(&obj->mm.lock);
  }
@@@ -2322,7 -2288,8 +2322,7 @@@ static bool i915_sg_trim(struct sg_tabl
        return true;
  }
  
 -static struct sg_table *
 -i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 +static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
  {
        struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
        const unsigned long page_count = obj->base.size / PAGE_SIZE;
        struct sgt_iter sgt_iter;
        struct page *page;
        unsigned long last_pfn = 0;     /* suppress gcc warning */
 -      unsigned int max_segment;
 +      unsigned int max_segment = i915_sg_segment_size();
 +      unsigned int sg_page_sizes;
        gfp_t noreclaim;
        int ret;
  
        GEM_BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS);
        GEM_BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS);
  
 -      max_segment = swiotlb_max_segment();
 -      if (!max_segment)
 -              max_segment = rounddown(UINT_MAX, PAGE_SIZE);
 -
        st = kmalloc(sizeof(*st), GFP_KERNEL);
        if (st == NULL)
 -              return ERR_PTR(-ENOMEM);
 +              return -ENOMEM;
  
  rebuild_st:
        if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
                kfree(st);
 -              return ERR_PTR(-ENOMEM);
 +              return -ENOMEM;
        }
  
        /* Get the list of pages out of our struct file.  They'll be pinned
  
        sg = st->sgl;
        st->nents = 0;
 +      sg_page_sizes = 0;
        for (i = 0; i < page_count; i++) {
                const unsigned int shrink[] = {
                        I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | I915_SHRINK_PURGEABLE,
                if (!i ||
                    sg->length >= max_segment ||
                    page_to_pfn(page) != last_pfn + 1) {
 -                      if (i)
 +                      if (i) {
 +                              sg_page_sizes |= sg->length;
                                sg = sg_next(sg);
 +                      }
                        st->nents++;
                        sg_set_page(sg, page, PAGE_SIZE, 0);
                } else {
                /* Check that the i965g/gm workaround works. */
                WARN_ON((gfp & __GFP_DMA32) && (last_pfn >= 0x00100000UL));
        }
 -      if (sg) /* loop terminated early; short sg table */
 +      if (sg) { /* loop terminated early; short sg table */
 +              sg_page_sizes |= sg->length;
                sg_mark_end(sg);
 +      }
  
        /* Trim unused sg entries to avoid wasting memory. */
        i915_sg_trim(st);
        if (i915_gem_object_needs_bit17_swizzle(obj))
                i915_gem_object_do_bit_17_swizzle(obj, st);
  
 -      return st;
 +      __i915_gem_object_set_pages(obj, st, sg_page_sizes);
 +
 +      return 0;
  
  err_sg:
        sg_mark_end(sg);
@@@ -2488,17 -2451,12 +2488,17 @@@ err_pages
        if (ret == -ENOSPC)
                ret = -ENOMEM;
  
 -      return ERR_PTR(ret);
 +      return ret;
  }
  
  void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
 -                               struct sg_table *pages)
 +                               struct sg_table *pages,
 +                               unsigned int sg_page_sizes)
  {
 +      struct drm_i915_private *i915 = to_i915(obj->base.dev);
 +      unsigned long supported = INTEL_INFO(i915)->page_sizes;
 +      int i;
 +
        lockdep_assert_held(&obj->mm.lock);
  
        obj->mm.get_page.sg_pos = pages->sgl;
                __i915_gem_object_pin_pages(obj);
                obj->mm.quirked = true;
        }
 +
 +      GEM_BUG_ON(!sg_page_sizes);
 +      obj->mm.page_sizes.phys = sg_page_sizes;
 +
 +      /*
 +       * Calculate the supported page-sizes which fit into the given
 +       * sg_page_sizes. This will give us the page-sizes which we may be able
 +       * to use opportunistically when later inserting into the GTT. For
 +       * example if phys=2G, then in theory we should be able to use 1G, 2M,
 +       * 64K or 4K pages, although in practice this will depend on a number of
 +       * other factors.
 +       */
 +      obj->mm.page_sizes.sg = 0;
 +      for_each_set_bit(i, &supported, ilog2(I915_GTT_MAX_PAGE_SIZE) + 1) {
 +              if (obj->mm.page_sizes.phys & ~0u << i)
 +                      obj->mm.page_sizes.sg |= BIT(i);
 +      }
 +
 +      GEM_BUG_ON(!HAS_PAGE_SIZES(i915, obj->mm.page_sizes.sg));
  }
  
  static int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
  {
 -      struct sg_table *pages;
 -
 -      GEM_BUG_ON(i915_gem_object_has_pinned_pages(obj));
 +      int err;
  
        if (unlikely(obj->mm.madv != I915_MADV_WILLNEED)) {
                DRM_DEBUG("Attempting to obtain a purgeable object\n");
                return -EFAULT;
        }
  
 -      pages = obj->ops->get_pages(obj);
 -      if (unlikely(IS_ERR(pages)))
 -              return PTR_ERR(pages);
 +      err = obj->ops->get_pages(obj);
 +      GEM_BUG_ON(!err && IS_ERR_OR_NULL(obj->mm.pages));
  
 -      __i915_gem_object_set_pages(obj, pages);
 -      return 0;
 +      return err;
  }
  
  /* Ensure that the associated pages are gathered from the backing storage
@@@ -2564,8 -2507,6 +2564,8 @@@ int __i915_gem_object_get_pages(struct 
                return err;
  
        if (unlikely(IS_ERR_OR_NULL(obj->mm.pages))) {
 +              GEM_BUG_ON(i915_gem_object_has_pinned_pages(obj));
 +
                err = ____i915_gem_object_get_pages(obj);
                if (err)
                        goto unlock;
@@@ -2649,8 -2590,6 +2649,8 @@@ void *i915_gem_object_pin_map(struct dr
  
        if (!atomic_inc_not_zero(&obj->mm.pages_pin_count)) {
                if (unlikely(IS_ERR_OR_NULL(obj->mm.pages))) {
 +                      GEM_BUG_ON(i915_gem_object_has_pinned_pages(obj));
 +
                        ret = ____i915_gem_object_get_pages(obj);
                        if (ret)
                                goto err_unlock;
@@@ -2718,6 -2657,9 +2718,9 @@@ i915_gem_object_pwrite_gtt(struct drm_i
        if (READ_ONCE(obj->mm.pages))
                return -ENODEV;
  
+       if (obj->mm.madv != I915_MADV_WILLNEED)
+               return -EFAULT;
        /* Before the pages are instantiated the object is treated as being
         * in the CPU domain. The pages will be clflushed as required before
         * use, and we can freely write into the pages directly. If userspace
@@@ -2856,17 -2798,7 +2859,17 @@@ i915_gem_reset_prepare_engine(struct in
  {
        struct drm_i915_gem_request *request = NULL;
  
 -      /* Prevent the signaler thread from updating the request
 +      /*
 +       * During the reset sequence, we must prevent the engine from
 +       * entering RC6. As the context state is undefined until we restart
 +       * the engine, if it does enter RC6 during the reset, the state
 +       * written to the powercontext is undefined and so we may lose
 +       * GPU state upon resume, i.e. fail to restart after a reset.
 +       */
 +      intel_uncore_forcewake_get(engine->i915, FORCEWAKE_ALL);
 +
 +      /*
 +       * Prevent the signaler thread from updating the request
         * state (by calling dma_fence_signal) as we are processing
         * the reset. The write from the GPU of the seqno is
         * asynchronous and the signaler thread may see a different
         */
        kthread_park(engine->breadcrumbs.signaler);
  
 -      /* Prevent request submission to the hardware until we have
 +      /*
 +       * Prevent request submission to the hardware until we have
         * completed the reset in i915_gem_reset_finish(). If a request
         * is completed by one engine, it may then queue a request
         * to a second via its engine->irq_tasklet *just* as we are
         * Turning off the engine->irq_tasklet until the reset is over
         * prevents the race.
         */
 -      tasklet_kill(&engine->irq_tasklet);
 -      tasklet_disable(&engine->irq_tasklet);
 +      tasklet_kill(&engine->execlists.irq_tasklet);
 +      tasklet_disable(&engine->execlists.irq_tasklet);
  
        if (engine->irq_seqno_barrier)
                engine->irq_seqno_barrier(engine);
@@@ -3066,10 -2997,8 +3069,10 @@@ void i915_gem_reset(struct drm_i915_pri
  
  void i915_gem_reset_finish_engine(struct intel_engine_cs *engine)
  {
 -      tasklet_enable(&engine->irq_tasklet);
 +      tasklet_enable(&engine->execlists.irq_tasklet);
        kthread_unpark(engine->breadcrumbs.signaler);
 +
 +      intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL);
  }
  
  void i915_gem_reset_finish(struct drm_i915_private *dev_priv)
  }
  
  static void nop_submit_request(struct drm_i915_gem_request *request)
 +{
 +      GEM_BUG_ON(!i915_terminally_wedged(&request->i915->gpu_error));
 +      dma_fence_set_error(&request->fence, -EIO);
 +
 +      i915_gem_request_submit(request);
 +}
 +
 +static void nop_complete_submit_request(struct drm_i915_gem_request *request)
  {
        unsigned long flags;
  
        spin_unlock_irqrestore(&request->engine->timeline->lock, flags);
  }
  
 -static void engine_set_wedged(struct intel_engine_cs *engine)
 +void i915_gem_set_wedged(struct drm_i915_private *i915)
  {
 -      struct drm_i915_gem_request *request;
 -      unsigned long flags;
 +      struct intel_engine_cs *engine;
 +      enum intel_engine_id id;
  
 -      /* We need to be sure that no thread is running the old callback as
 -       * we install the nop handler (otherwise we would submit a request
 -       * to hardware that will never complete). In order to prevent this
 -       * race, we wait until the machine is idle before making the swap
 -       * (using stop_machine()).
 +      /*
 +       * First, stop submission to hw, but do not yet complete requests by
 +       * rolling the global seqno forward (since this would complete requests
 +       * for which we haven't set the fence error to EIO yet).
         */
 -      engine->submit_request = nop_submit_request;
 -
 -      /* Mark all executing requests as skipped */
 -      spin_lock_irqsave(&engine->timeline->lock, flags);
 -      list_for_each_entry(request, &engine->timeline->requests, link)
 -              if (!i915_gem_request_completed(request))
 -                      dma_fence_set_error(&request->fence, -EIO);
 -      spin_unlock_irqrestore(&engine->timeline->lock, flags);
 +      for_each_engine(engine, i915, id)
 +              engine->submit_request = nop_submit_request;
  
        /*
 -       * Clear the execlists queue up before freeing the requests, as those
 -       * are the ones that keep the context and ringbuffer backing objects
 -       * pinned in place.
 +       * Make sure no one is running the old callback before we proceed with
 +       * cancelling requests and resetting the completion tracking. Otherwise
 +       * we might submit a request to the hardware which never completes.
         */
 +      synchronize_rcu();
  
 -      if (i915.enable_execlists) {
 -              struct execlist_port *port = engine->execlist_port;
 -              unsigned long flags;
 -              unsigned int n;
 -
 -              spin_lock_irqsave(&engine->timeline->lock, flags);
 -
 -              for (n = 0; n < ARRAY_SIZE(engine->execlist_port); n++)
 -                      i915_gem_request_put(port_request(&port[n]));
 -              memset(engine->execlist_port, 0, sizeof(engine->execlist_port));
 -              engine->execlist_queue = RB_ROOT;
 -              engine->execlist_first = NULL;
 -
 -              spin_unlock_irqrestore(&engine->timeline->lock, flags);
 +      for_each_engine(engine, i915, id) {
 +              /* Mark all executing requests as skipped */
 +              engine->cancel_requests(engine);
  
 -              /* The port is checked prior to scheduling a tasklet, but
 -               * just in case we have suspended the tasklet to do the
 -               * wedging make sure that when it wakes, it decides there
 -               * is no work to do by clearing the irq_posted bit.
 +              /*
 +               * Only once we've force-cancelled all in-flight requests can we
 +               * start to complete all requests.
                 */
 -              clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
 +              engine->submit_request = nop_complete_submit_request;
        }
  
 -      /* Mark all pending requests as complete so that any concurrent
 -       * (lockless) lookup doesn't try and wait upon the request as we
 -       * reset it.
 +      /*
 +       * Make sure no request can slip through without getting completed by
 +       * either this call here to intel_engine_init_global_seqno, or the one
 +       * in nop_complete_submit_request.
         */
 -      intel_engine_init_global_seqno(engine,
 -                                     intel_engine_last_submit(engine));
 -}
 +      synchronize_rcu();
  
 -static int __i915_gem_set_wedged_BKL(void *data)
 -{
 -      struct drm_i915_private *i915 = data;
 -      struct intel_engine_cs *engine;
 -      enum intel_engine_id id;
 +      for_each_engine(engine, i915, id) {
 +              unsigned long flags;
  
 -      for_each_engine(engine, i915, id)
 -              engine_set_wedged(engine);
 +              /* Mark all pending requests as complete so that any concurrent
 +               * (lockless) lookup doesn't try and wait upon the request as we
 +               * reset it.
 +               */
 +              spin_lock_irqsave(&engine->timeline->lock, flags);
 +              intel_engine_init_global_seqno(engine,
 +                                             intel_engine_last_submit(engine));
 +              spin_unlock_irqrestore(&engine->timeline->lock, flags);
 +      }
  
        set_bit(I915_WEDGED, &i915->gpu_error.flags);
        wake_up_all(&i915->gpu_error.reset_queue);
 -
 -      return 0;
 -}
 -
 -void i915_gem_set_wedged(struct drm_i915_private *dev_priv)
 -{
 -      stop_machine(__i915_gem_set_wedged_BKL, dev_priv, NULL);
  }
  
  bool i915_gem_unset_wedged(struct drm_i915_private *i915)
@@@ -3322,11 -3265,11 +3325,11 @@@ void i915_gem_close_object(struct drm_g
                struct i915_gem_context *ctx = lut->ctx;
                struct i915_vma *vma;
  
 +              GEM_BUG_ON(ctx->file_priv == ERR_PTR(-EBADF));
                if (ctx->file_priv != fpriv)
                        continue;
  
                vma = radix_tree_delete(&ctx->handles_vma, lut->handle);
 -
                GEM_BUG_ON(vma->obj != obj);
  
                /* We allow the process to have multiple handles to the same
@@@ -3440,12 -3383,24 +3443,12 @@@ static int wait_for_timeline(struct i91
        return 0;
  }
  
 -static int wait_for_engine(struct intel_engine_cs *engine, int timeout_ms)
 -{
 -      return wait_for(intel_engine_is_idle(engine), timeout_ms);
 -}
 -
  static int wait_for_engines(struct drm_i915_private *i915)
  {
 -      struct intel_engine_cs *engine;
 -      enum intel_engine_id id;
 -
 -      for_each_engine(engine, i915, id) {
 -              if (GEM_WARN_ON(wait_for_engine(engine, 50))) {
 -                      i915_gem_set_wedged(i915);
 -                      return -EIO;
 -              }
 -
 -              GEM_BUG_ON(intel_engine_get_seqno(engine) !=
 -                         intel_engine_last_submit(engine));
 +      if (wait_for(intel_engines_are_idle(i915), 50)) {
 +              DRM_ERROR("Failed to idle engines, declaring wedged!\n");
 +              i915_gem_set_wedged(i915);
 +              return -EIO;
        }
  
        return 0;
@@@ -4059,47 -4014,42 +4062,47 @@@ i915_gem_object_ggtt_pin(struct drm_i91
  
        lockdep_assert_held(&obj->base.dev->struct_mutex);
  
 +      if (!view && flags & PIN_MAPPABLE) {
 +              /* If the required space is larger than the available
 +               * aperture, we will not able to find a slot for the
 +               * object and unbinding the object now will be in
 +               * vain. Worse, doing so may cause us to ping-pong
 +               * the object in and out of the Global GTT and
 +               * waste a lot of cycles under the mutex.
 +               */
 +              if (obj->base.size > dev_priv->ggtt.mappable_end)
 +                      return ERR_PTR(-E2BIG);
 +
 +              /* If NONBLOCK is set the caller is optimistically
 +               * trying to cache the full object within the mappable
 +               * aperture, and *must* have a fallback in place for
 +               * situations where we cannot bind the object. We
 +               * can be a little more lax here and use the fallback
 +               * more often to avoid costly migrations of ourselves
 +               * and other objects within the aperture.
 +               *
 +               * Half-the-aperture is used as a simple heuristic.
 +               * More interesting would to do search for a free
 +               * block prior to making the commitment to unbind.
 +               * That caters for the self-harm case, and with a
 +               * little more heuristics (e.g. NOFAULT, NOEVICT)
 +               * we could try to minimise harm to others.
 +               */
 +              if (flags & PIN_NONBLOCK &&
 +                  obj->base.size > dev_priv->ggtt.mappable_end / 2)
 +                      return ERR_PTR(-ENOSPC);
 +      }
 +
        vma = i915_vma_instance(obj, vm, view);
        if (unlikely(IS_ERR(vma)))
                return vma;
  
        if (i915_vma_misplaced(vma, size, alignment, flags)) {
 -              if (flags & PIN_NONBLOCK &&
 -                  (i915_vma_is_pinned(vma) || i915_vma_is_active(vma)))
 -                      return ERR_PTR(-ENOSPC);
 +              if (flags & PIN_NONBLOCK) {
 +                      if (i915_vma_is_pinned(vma) || i915_vma_is_active(vma))
 +                              return ERR_PTR(-ENOSPC);
  
 -              if (flags & PIN_MAPPABLE) {
 -                      /* If the required space is larger than the available
 -                       * aperture, we will not able to find a slot for the
 -                       * object and unbinding the object now will be in
 -                       * vain. Worse, doing so may cause us to ping-pong
 -                       * the object in and out of the Global GTT and
 -                       * waste a lot of cycles under the mutex.
 -                       */
 -                      if (vma->fence_size > dev_priv->ggtt.mappable_end)
 -                              return ERR_PTR(-E2BIG);
 -
 -                      /* If NONBLOCK is set the caller is optimistically
 -                       * trying to cache the full object within the mappable
 -                       * aperture, and *must* have a fallback in place for
 -                       * situations where we cannot bind the object. We
 -                       * can be a little more lax here and use the fallback
 -                       * more often to avoid costly migrations of ourselves
 -                       * and other objects within the aperture.
 -                       *
 -                       * Half-the-aperture is used as a simple heuristic.
 -                       * More interesting would to do search for a free
 -                       * block prior to making the commitment to unbind.
 -                       * That caters for the self-harm case, and with a
 -                       * little more heuristics (e.g. NOFAULT, NOEVICT)
 -                       * we could try to minimise harm to others.
 -                       */
 -                      if (flags & PIN_NONBLOCK &&
 +                      if (flags & PIN_MAPPABLE &&
                            vma->fence_size > dev_priv->ggtt.mappable_end / 2)
                                return ERR_PTR(-ENOSPC);
                }
@@@ -4326,6 -4276,7 +4329,6 @@@ void i915_gem_object_init(struct drm_i9
        mutex_init(&obj->mm.lock);
  
        INIT_LIST_HEAD(&obj->global_link);
 -      INIT_LIST_HEAD(&obj->userfault_link);
        INIT_LIST_HEAD(&obj->vma_list);
        INIT_LIST_HEAD(&obj->lut_list);
        INIT_LIST_HEAD(&obj->batch_pool_link);
@@@ -4355,30 -4306,6 +4358,30 @@@ static const struct drm_i915_gem_object
        .pwrite = i915_gem_object_pwrite_gtt,
  };
  
 +static int i915_gem_object_create_shmem(struct drm_device *dev,
 +                                      struct drm_gem_object *obj,
 +                                      size_t size)
 +{
 +      struct drm_i915_private *i915 = to_i915(dev);
 +      unsigned long flags = VM_NORESERVE;
 +      struct file *filp;
 +
 +      drm_gem_private_object_init(dev, obj, size);
 +
 +      if (i915->mm.gemfs)
 +              filp = shmem_file_setup_with_mnt(i915->mm.gemfs, "i915", size,
 +                                               flags);
 +      else
 +              filp = shmem_file_setup("i915", size, flags);
 +
 +      if (IS_ERR(filp))
 +              return PTR_ERR(filp);
 +
 +      obj->filp = filp;
 +
 +      return 0;
 +}
 +
  struct drm_i915_gem_object *
  i915_gem_object_create(struct drm_i915_private *dev_priv, u64 size)
  {
        if (obj == NULL)
                return ERR_PTR(-ENOMEM);
  
 -      ret = drm_gem_object_init(&dev_priv->drm, &obj->base, size);
 +      ret = i915_gem_object_create_shmem(&dev_priv->drm, &obj->base, size);
        if (ret)
                goto fail;
  
@@@ -4506,9 -4433,7 +4509,9 @@@ static void __i915_gem_free_objects(str
  
        llist_for_each_entry_safe(obj, on, freed, freed) {
                GEM_BUG_ON(obj->bind_count);
 +              GEM_BUG_ON(obj->userfault_count);
                GEM_BUG_ON(atomic_read(&obj->frontbuffer_bits));
 +              GEM_BUG_ON(!list_empty(&obj->lut_list));
  
                if (obj->ops->release)
                        obj->ops->release(obj);
@@@ -4616,12 -4541,6 +4619,12 @@@ static void assert_kernel_context_is_cu
  
  void i915_gem_sanitize(struct drm_i915_private *i915)
  {
 +      if (i915_terminally_wedged(&i915->gpu_error)) {
 +              mutex_lock(&i915->drm.struct_mutex);
 +              i915_gem_unset_wedged(i915);
 +              mutex_unlock(&i915->drm.struct_mutex);
 +      }
 +
        /*
         * If we inherit context state from the BIOS or earlier occupants
         * of the GPU, the GPU may be in an inconsistent state when we
@@@ -4661,7 -4580,7 +4664,7 @@@ int i915_gem_suspend(struct drm_i915_pr
        ret = i915_gem_wait_for_idle(dev_priv,
                                     I915_WAIT_INTERRUPTIBLE |
                                     I915_WAIT_LOCKED);
 -      if (ret)
 +      if (ret && ret != -EIO)
                goto err_unlock;
  
        assert_kernel_context_is_current(dev_priv);
        /* As the idle_work is rearming if it detects a race, play safe and
         * repeat the flush until it is definitely idle.
         */
 -      while (flush_delayed_work(&dev_priv->gt.idle_work))
 -              ;
 +      drain_delayed_work(&dev_priv->gt.idle_work);
  
        /* Assert that we sucessfully flushed all the work and
         * reset the GPU back to its idle, low power state.
         */
        WARN_ON(dev_priv->gt.awake);
 -      WARN_ON(!intel_engines_are_idle(dev_priv));
 +      if (WARN_ON(!intel_engines_are_idle(dev_priv)))
 +              i915_gem_set_wedged(dev_priv); /* no hope, discard everything */
  
        /*
         * Neither the BIOS, ourselves or any other kernel
         * machine in an unusable condition.
         */
        i915_gem_sanitize(dev_priv);
 -      goto out_rpm_put;
 +
 +      intel_runtime_pm_put(dev_priv);
 +      return 0;
  
  err_unlock:
        mutex_unlock(&dev->struct_mutex);
 -out_rpm_put:
        intel_runtime_pm_put(dev_priv);
        return ret;
  }
@@@ -4723,7 -4641,6 +4726,7 @@@ void i915_gem_resume(struct drm_i915_pr
  
        mutex_lock(&dev->struct_mutex);
        i915_gem_restore_gtt_mappings(dev_priv);
 +      i915_gem_restore_fences(dev_priv);
  
        /* As we didn't flush the kernel context before suspend, we cannot
         * guarantee that the context image is complete. So let's just reset
@@@ -4867,7 -4784,7 +4870,7 @@@ bool intel_sanitize_semaphores(struct d
                return false;
  
        /* TODO: make semaphores and Execlists play nicely together */
 -      if (i915.enable_execlists)
 +      if (i915_modparams.enable_execlists)
                return false;
  
        if (value >= 0)
@@@ -4886,18 -4803,9 +4889,18 @@@ int i915_gem_init(struct drm_i915_priva
  
        mutex_lock(&dev_priv->drm.struct_mutex);
  
 +      /*
 +       * We need to fallback to 4K pages since gvt gtt handling doesn't
 +       * support huge page entries - we will need to check either hypervisor
 +       * mm can support huge guest page or just do emulation in gvt.
 +       */
 +      if (intel_vgpu_active(dev_priv))
 +              mkwrite_device_info(dev_priv)->page_sizes =
 +                      I915_GTT_PAGE_SIZE_4K;
 +
        dev_priv->mm.unordered_timeline = dma_fence_context_alloc(1);
  
 -      if (!i915.enable_execlists) {
 +      if (!i915_modparams.enable_execlists) {
                dev_priv->gt.resume = intel_legacy_submission_resume;
                dev_priv->gt.cleanup_engine = intel_engine_cleanup;
        } else {
@@@ -5052,10 -4960,6 +5055,10 @@@ i915_gem_load_init(struct drm_i915_priv
  
        spin_lock_init(&dev_priv->fb_tracking.lock);
  
 +      err = i915_gemfs_init(dev_priv);
 +      if (err)
 +              DRM_NOTE("Unable to create a private tmpfs mount, hugepage support will be disabled(%d).\n", err);
 +
        return 0;
  
  err_priorities:
@@@ -5094,8 -4998,6 +5097,8 @@@ void i915_gem_load_cleanup(struct drm_i
  
        /* And ensure that our DESTROY_BY_RCU slabs are truly destroyed */
        rcu_barrier();
 +
 +      i915_gemfs_fini(dev_priv);
  }
  
  int i915_gem_freeze(struct drm_i915_private *dev_priv)
@@@ -5485,7 -5387,6 +5488,7 @@@ err_unlock
  #include "selftests/scatterlist.c"
  #include "selftests/mock_gem_device.c"
  #include "selftests/huge_gem_object.c"
 +#include "selftests/huge_pages.c"
  #include "selftests/i915_gem_object.c"
  #include "selftests/i915_gem_coherency.c"
  #endif
index a5a5b7e6daae355b9f5a80e39ea2cbaac9173e90,e161d383b526757a79097eadb9e65260392befe1..ee4811ffb7aafe619a83ee7b1aad1672cbd32ea5
  #include "intel_drv.h"
  #include "i915_trace.h"
  
- static bool ggtt_is_idle(struct drm_i915_private *dev_priv)
+ static bool ggtt_is_idle(struct drm_i915_private *i915)
  {
-       struct i915_ggtt *ggtt = &dev_priv->ggtt;
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
+        struct intel_engine_cs *engine;
+        enum intel_engine_id id;
  
-       for_each_engine(engine, dev_priv, id) {
-               struct intel_timeline *tl;
+        if (i915->gt.active_requests)
+              return false;
  
-               tl = &ggtt->base.timeline.engine[engine->id];
-               if (i915_gem_active_isset(&tl->last_request))
-                       return false;
-       }
+        for_each_engine(engine, i915, id) {
+              if (engine->last_retired_context != i915->kernel_context)
+                      return false;
+        }
  
-       return true;
+        return true;
  }
  
  static int ggtt_flush(struct drm_i915_private *i915)
@@@ -82,7 -81,7 +81,7 @@@ mark_free(struct drm_mm_scan *scan
        if (i915_vma_is_pinned(vma))
                return false;
  
 -      if (flags & PIN_NONFAULT && !list_empty(&vma->obj->userfault_link))
 +      if (flags & PIN_NONFAULT && i915_vma_has_userfault(vma))
                return false;
  
        list_add(&vma->evict_link, unwind);
@@@ -157,7 -156,8 +156,8 @@@ i915_gem_evict_something(struct i915_ad
                                    min_size, alignment, cache_level,
                                    start, end, mode);
  
-       /* Retire before we search the active list. Although we have
+       /*
+        * Retire before we search the active list. Although we have
         * reasonable accuracy in our retirement lists, we may have
         * a stray pin (preventing eviction) that can only be resolved by
         * retiring.
@@@ -182,7 -182,8 +182,8 @@@ search_again
                BUG_ON(ret);
        }
  
-       /* Can we unpin some objects such as idle hw contents,
+       /*
+        * Can we unpin some objects such as idle hw contents,
         * or pending flips? But since only the GGTT has global entries
         * such as scanouts, rinbuffers and contexts, we can skip the
         * purge when inspecting per-process local address spaces.
        if (!i915_is_ggtt(vm) || flags & PIN_NONBLOCK)
                return -ENOSPC;
  
-       if (ggtt_is_idle(dev_priv)) {
-               /* If we still have pending pageflip completions, drop
-                * back to userspace to give our workqueues time to
-                * acquire our locks and unpin the old scanouts.
-                */
-               return intel_has_pending_fb_unpin(dev_priv) ? -EAGAIN : -ENOSPC;
-       }
+       /*
+        * Not everything in the GGTT is tracked via VMA using
+        * i915_vma_move_to_active(), otherwise we could evict as required
+        * with minimal stalling. Instead we are forced to idle the GPU and
+        * explicitly retire outstanding requests which will then remove
+        * the pinning for active objects such as contexts and ring,
+        * enabling us to evict them on the next iteration.
+        *
+        * To ensure that all user contexts are evictable, we perform
+        * a switch to the perma-pinned kernel context. This all also gives
+        * us a termination condition, when the last retired context is
+        * the kernel's there is no more we can evict.
+        */
+       if (!ggtt_is_idle(dev_priv)) {
+               ret = ggtt_flush(dev_priv);
+               if (ret)
+                       return ret;
  
-       ret = ggtt_flush(dev_priv);
-       if (ret)
-               return ret;
+               goto search_again;
+       }
  
-       goto search_again;
+       /*
+        * If we still have pending pageflip completions, drop
+        * back to userspace to give our workqueues time to
+        * acquire our locks and unpin the old scanouts.
+        */
+       return intel_has_pending_fb_unpin(dev_priv) ? -EAGAIN : -ENOSPC;
  
  found:
        /* drm_mm doesn't allow any other other operations while
@@@ -315,11 -330,6 +330,11 @@@ int i915_gem_evict_for_node(struct i915
                        break;
                }
  
 +              if (flags & PIN_NONFAULT && i915_vma_has_userfault(vma)) {
 +                      ret = -ENOSPC;
 +                      break;
 +              }
 +
                /* Overlap of objects in the same batch? */
                if (i915_vma_is_pinned(vma)) {
                        ret = -ENOSPC;
index 1383a2995a698f6f589618e8e642fa8a88298631,370b9d248fed89abe2b3601063ddffd27661c76e..59ee808f8fd97122f361e67d65dabe187ee56f7b
  #include "i915_oa_kblgt2.h"
  #include "i915_oa_kblgt3.h"
  #include "i915_oa_glk.h"
 +#include "i915_oa_cflgt2.h"
  
  /* HW requires this to be a power of two, between 128k and 16M, though driver
   * is currently generally designed assuming the largest 16M size is used such
@@@ -1214,7 -1213,7 +1214,7 @@@ static int oa_get_render_ctx_id(struct 
  {
        struct drm_i915_private *dev_priv = stream->dev_priv;
  
 -      if (i915.enable_execlists)
 +      if (i915_modparams.enable_execlists)
                dev_priv->perf.oa.specific_ctx_id = stream->ctx->hw_id;
        else {
                struct intel_engine_cs *engine = dev_priv->engine[RCS];
@@@ -1260,7 -1259,7 +1260,7 @@@ static void oa_put_render_ctx_id(struc
  {
        struct drm_i915_private *dev_priv = stream->dev_priv;
  
 -      if (i915.enable_execlists) {
 +      if (i915_modparams.enable_execlists) {
                dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID;
        } else {
                struct intel_engine_cs *engine = dev_priv->engine[RCS];
@@@ -1851,7 -1850,8 +1851,7 @@@ static int gen8_enable_metric_set(struc
         * be read back from automatically triggered reports, as part of the
         * RPT_ID field.
         */
 -      if (IS_SKYLAKE(dev_priv) || IS_BROXTON(dev_priv) ||
 -          IS_KABYLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) {
 +      if (IS_GEN9(dev_priv)) {
                I915_WRITE(GEN8_OA_DEBUG,
                           _MASKED_BIT_ENABLE(GEN9_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS |
                                              GEN9_OA_DEBUG_INCLUDE_CLK_RATIO));
@@@ -2537,6 -2537,10 +2537,10 @@@ static const struct file_operations fop
        .poll           = i915_perf_poll,
        .read           = i915_perf_read,
        .unlocked_ioctl = i915_perf_ioctl,
+       /* Our ioctl have no arguments, so it's safe to use the same function
+        * to handle 32bits compatibility.
+        */
+       .compat_ioctl   = i915_perf_ioctl,
  };
  
  
@@@ -2927,9 -2931,6 +2931,9 @@@ void i915_perf_register(struct drm_i915
                        i915_perf_load_test_config_kblgt3(dev_priv);
        } else if (IS_GEMINILAKE(dev_priv)) {
                i915_perf_load_test_config_glk(dev_priv);
 +      } else if (IS_COFFEELAKE(dev_priv)) {
 +              if (IS_CFL_GT2(dev_priv))
 +                      i915_perf_load_test_config_cflgt2(dev_priv);
        }
  
        if (dev_priv->perf.oa.test_config.id == 0)
@@@ -3408,7 -3409,7 +3412,7 @@@ void i915_perf_init(struct drm_i915_pri
                dev_priv->perf.oa.timestamp_frequency = 12500000;
  
                dev_priv->perf.oa.oa_formats = hsw_oa_formats;
 -      } else if (i915.enable_execlists) {
 +      } else if (i915_modparams.enable_execlists) {
                /* Note: that although we could theoretically also support the
                 * legacy ringbuffer mode on BDW (and earlier iterations of
                 * this driver, before upstreaming did this) it didn't seem
                                break;
                        case INTEL_SKYLAKE:
                        case INTEL_KABYLAKE:
 +                      case INTEL_COFFEELAKE:
                                dev_priv->perf.oa.timestamp_frequency = 12000000;
                                break;
                        default:
index d2d0a83c09b6d185f82a5bdade51e13f30f30a93,c9bcc6c450126e7cf638ba1c872a55938660add8..628ccd9181bb4639b5b4125bf88b4ea4d95c4cdd
@@@ -2336,7 -2336,7 +2336,7 @@@ enum i915_power_well_id 
  #define DONE_REG              _MMIO(0x40b0)
  #define GEN8_PRIVATE_PAT_LO   _MMIO(0x40e0)
  #define GEN8_PRIVATE_PAT_HI   _MMIO(0x40e0 + 4)
 -#define GEN10_PAT_INDEX(index)        _MMIO(0x40e0 + index*4)
 +#define GEN10_PAT_INDEX(index)        _MMIO(0x40e0 + (index)*4)
  #define BSD_HWS_PGA_GEN7      _MMIO(0x04180)
  #define BLT_HWS_PGA_GEN7      _MMIO(0x04280)
  #define VEBOX_HWS_PGA_GEN7    _MMIO(0x04380)
  #define GEN9_GAMT_ECO_REG_RW_IA _MMIO(0x4ab0)
  #define   GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS (1<<18)
  
 +#define GEN8_GAMW_ECO_DEV_RW_IA _MMIO(0x4080)
 +#define   GAMW_ECO_ENABLE_64K_IPS_FIELD 0xF
 +
  #define GAMT_CHKN_BIT_REG     _MMIO(0x4ab8)
  #define   GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING    (1<<28)
 +#define   GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT      (1<<24)
  
  #if 0
  #define PRB0_TAIL     _MMIO(0x2030)
  # define _3D_CHICKEN2_WM_READ_PIPELINED                       (1 << 14)
  #define _3D_CHICKEN3  _MMIO(0x2090)
  #define  _3D_CHICKEN_SF_DISABLE_OBJEND_CULL           (1 << 10)
 +#define  _3D_CHICKEN3_AA_LINE_QUALITY_FIX_ENABLE      (1 << 5)
  #define  _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL                (1 << 5)
  #define  _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x)     ((x)<<1) /* gen8+ */
  #define  _3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH (1 << 1) /* gen6 */
  #define   GEN9_F2_SS_DIS_SHIFT                20
  #define   GEN9_F2_SS_DIS_MASK         (0xf << GEN9_F2_SS_DIS_SHIFT)
  
 +#define   GEN10_F2_S_ENA_SHIFT                22
 +#define   GEN10_F2_S_ENA_MASK         (0x3f << GEN10_F2_S_ENA_SHIFT)
 +#define   GEN10_F2_SS_DIS_SHIFT               18
 +#define   GEN10_F2_SS_DIS_MASK                (0xf << GEN10_F2_SS_DIS_SHIFT)
 +
  #define GEN8_EU_DISABLE0              _MMIO(0x9134)
  #define   GEN8_EU_DIS0_S0_MASK                0xffffff
  #define   GEN8_EU_DIS0_S1_SHIFT               24
  
  #define GEN9_EU_DISABLE(slice)                _MMIO(0x9134 + (slice)*0x4)
  
 +#define GEN10_EU_DISABLE3             _MMIO(0x9140)
 +#define   GEN10_EU_DIS_SS_MASK                0xff
 +
  #define GEN6_BSD_SLEEP_PSMI_CONTROL   _MMIO(0x12050)
  #define   GEN6_BSD_SLEEP_MSG_DISABLE  (1 << 0)
  #define   GEN6_BSD_SLEEP_FLUSH_DISABLE        (1 << 2)
  #define ILK_DPFC_CHICKEN      _MMIO(0x43224)
  #define   ILK_DPFC_DISABLE_DUMMY0 (1<<8)
  #define   ILK_DPFC_NUKE_ON_ANY_MODIFICATION   (1<<23)
 +#define   GLK_SKIP_SEG_EN             (1<<12)
 +#define   GLK_SKIP_SEG_COUNT_MASK     (3<<10)
 +#define   GLK_SKIP_SEG_COUNT(x)               ((x)<<10)
  #define ILK_FBC_RT_BASE               _MMIO(0x2128)
  #define   ILK_FBC_RT_VALID    (1<<0)
  #define   SNB_FBC_FRONT_BUFFER        (1<<1)
@@@ -3822,22 -3806,6 +3822,22 @@@ enum 
  #define   PWM2_GATING_DIS             (1 << 14)
  #define   PWM1_GATING_DIS             (1 << 13)
  
 +#define _CLKGATE_DIS_PSL_A            0x46520
 +#define _CLKGATE_DIS_PSL_B            0x46524
 +#define _CLKGATE_DIS_PSL_C            0x46528
 +#define   DPF_GATING_DIS              (1 << 10)
 +#define   DPF_RAM_GATING_DIS          (1 << 9)
 +#define   DPFR_GATING_DIS             (1 << 8)
 +
 +#define CLKGATE_DIS_PSL(pipe) \
 +      _MMIO_PIPE(pipe, _CLKGATE_DIS_PSL_A, _CLKGATE_DIS_PSL_B)
 +
 +/*
 + * GEN10 clock gating regs
 + */
 +#define SLICE_UNIT_LEVEL_CLKGATE      _MMIO(0x94d4)
 +#define  SARBUNIT_CLKGATE_DIS         (1 << 5)
 +
  /*
   * Display engine regs
   */
  #define   EDP_PSR2_FRAME_BEFORE_SU_SHIFT 4
  #define   EDP_PSR2_FRAME_BEFORE_SU_MASK       (0xf<<4)
  #define   EDP_PSR2_IDLE_MASK          0xf
 -#define   EDP_FRAMES_BEFORE_SU_ENTRY   (1<<4)
 +#define   EDP_PSR2_FRAME_BEFORE_SU(a) ((a)<<4)
  
  #define EDP_PSR2_STATUS_CTL            _MMIO(0x6f940)
  #define EDP_PSR2_STATUS_STATE_MASK     (0xf<<28)
  #define  CBR_PWM_CLOCK_MUX_SELECT     (1<<30)
  
  #define CBR4_VLV                      _MMIO(VLV_DISPLAY_BASE + 0x70450)
 -#define  CBR_DPLLBMD_PIPE_C           (1<<29)
 -#define  CBR_DPLLBMD_PIPE_B           (1<<18)
 +#define  CBR_DPLLBMD_PIPE(pipe)               (1<<(7+(pipe)*11)) /* pipes B and C */
  
  /* FIFO watermark sizes etc */
  #define G4X_FIFO_LINE_SIZE    64
  # define CHICKEN3_DGMG_DONE_FIX_DISABLE               (1 << 2)
  
  #define CHICKEN_PAR1_1                _MMIO(0x42080)
 -#define  SKL_RC_HASH_OUTSIDE  (1 << 15)
 +#define  SKL_DE_COMPRESSED_HASH_MODE  (1 << 15)
  #define  DPA_MASK_VBLANK_SRD  (1 << 15)
  #define  FORCE_ARB_IDLE_PLANES        (1 << 14)
  #define  SKL_EDP_PSR_FIX_RDWRAP       (1 << 3)
  #define  GLK_CL1_PWR_DOWN     (1 << 11)
  #define  GLK_CL0_PWR_DOWN     (1 << 10)
  
 +#define CHICKEN_MISC_4                _MMIO(0x4208c)
 +#define   FBC_STRIDE_OVERRIDE (1 << 13)
 +#define   FBC_STRIDE_MASK     0x1FFF
 +
  #define _CHICKEN_PIPESL_1_A   0x420b0
  #define _CHICKEN_PIPESL_1_B   0x420b4
  #define  HSW_FBCQ_DIS                 (1 << 22)
  #define  DISP_FBC_WM_DIS              (1<<15)
  #define DISP_ARB_CTL2 _MMIO(0x45004)
  #define  DISP_DATA_PARTITION_5_6      (1<<6)
 +#define  DISP_IPC_ENABLE              (1<<3)
  #define DBUF_CTL      _MMIO(0x45008)
  #define  DBUF_POWER_REQUEST           (1<<31)
  #define  DBUF_POWER_STATE             (1<<30)
  #define GEN9_CS_DEBUG_MODE1           _MMIO(0x20ec)
  #define GEN9_CTX_PREEMPT_REG          _MMIO(0x2248)
  #define GEN8_CS_CHICKEN1              _MMIO(0x2580)
 +#define GEN9_PREEMPT_3D_OBJECT_LEVEL          (1<<0)
 +#define GEN9_PREEMPT_GPGPU_LEVEL(hi, lo)      (((hi) << 2) | ((lo) << 1))
 +#define GEN9_PREEMPT_GPGPU_MID_THREAD_LEVEL   GEN9_PREEMPT_GPGPU_LEVEL(0, 0)
 +#define GEN9_PREEMPT_GPGPU_THREAD_GROUP_LEVEL GEN9_PREEMPT_GPGPU_LEVEL(0, 1)
 +#define GEN9_PREEMPT_GPGPU_COMMAND_LEVEL      GEN9_PREEMPT_GPGPU_LEVEL(1, 0)
 +#define GEN9_PREEMPT_GPGPU_LEVEL_MASK         GEN9_PREEMPT_GPGPU_LEVEL(1, 1)
  
  /* GEN7 chicken */
  #define GEN7_COMMON_SLICE_CHICKEN1            _MMIO(0x7010)
  # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC    ((1<<10) | (1<<26))
  # define GEN9_RHWO_OPTIMIZATION_DISABLE               (1<<14)
  #define COMMON_SLICE_CHICKEN2                 _MMIO(0x7014)
 +# define GEN9_PBE_COMPRESSED_HASH_SELECTION   (1<<13)
  # define GEN9_DISABLE_GATHER_AT_SET_SHADER_COMMON_SLICE (1<<12)
  # define GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION (1<<8)
  # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0)
   */
  #define  L3_GENERAL_PRIO_CREDITS(x)           (((x) >> 1) << 19)
  #define  L3_HIGH_PRIO_CREDITS(x)              (((x) >> 1) << 14)
+ #define  L3_PRIO_CREDITS_MASK                 ((0x1f << 19) | (0x1f << 14))
  
  #define GEN7_L3CNTLREG1                               _MMIO(0xB01C)
  #define  GEN7_WA_FOR_GEN7_L3_CONTROL                  0x3C47FF8C
  
  /* GEN8 chicken */
  #define HDC_CHICKEN0                          _MMIO(0x7300)
 +#define CNL_HDC_CHICKEN0                      _MMIO(0xE5F0)
  #define  HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE       (1<<15)
  #define  HDC_FENCE_DEST_SLM_DISABLE           (1<<14)
  #define  HDC_DONOT_FETCH_MEM_WHEN_MASKED      (1<<11)
  
  #define SERR_INT                      _MMIO(0xc4040)
  #define  SERR_INT_POISON              (1<<31)
 -#define  SERR_INT_TRANS_C_FIFO_UNDERRUN       (1<<6)
 -#define  SERR_INT_TRANS_B_FIFO_UNDERRUN       (1<<3)
 -#define  SERR_INT_TRANS_A_FIFO_UNDERRUN       (1<<0)
  #define  SERR_INT_TRANS_FIFO_UNDERRUN(pipe)   (1<<((pipe)*3))
  
  /* digital port hotplug */
  #define  FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2)))
  #define  FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2)))
  #define  FDI_BC_BIFURCATION_SELECT    (1 << 12)
 +#define  CHASSIS_CLK_REQ_DURATION_MASK        (0xf << 8)
 +#define  CHASSIS_CLK_REQ_DURATION(x)  ((x) << 8)
  #define  SPT_PWM_GRANULARITY          (1<<0)
  #define SOUTH_CHICKEN2                _MMIO(0xc2004)
  #define  FDI_MPHY_IOSFSB_RESET_STATUS (1<<13)
  #define  PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30)
  #define  PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
  #define  PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14)
 +#define  CNP_PWM_CGE_GATING_DISABLE (1<<13)
  #define  PCH_LP_PARTITION_LEVEL_DISABLE  (1<<12)
  
  /* CPU: FDI_TX */
  #define     GEN7_PCODE_TIMEOUT                        0x2
  #define     GEN7_PCODE_ILLEGAL_DATA           0x3
  #define     GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE 0x10
 -#define         GEN6_PCODE_WRITE_RC6VIDS              0x4
 -#define         GEN6_PCODE_READ_RC6VIDS               0x5
 +#define   GEN6_PCODE_WRITE_RC6VIDS            0x4
 +#define   GEN6_PCODE_READ_RC6VIDS             0x5
  #define     GEN6_ENCODE_RC6_VID(mv)           (((mv) - 245) / 5)
  #define     GEN6_DECODE_RC6_VID(vids)         (((vids) * 5) + 245)
  #define   BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ   0x18
  #define   GEN6_PCODE_WRITE_D_COMP             0x11
  #define   HSW_PCODE_DE_WRITE_FREQ_REQ         0x17
  #define   DISPLAY_IPS_CONTROL                 0x19
 -#define         HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL  0x1A
 +            /* See also IPS_CTL */
 +#define     IPS_PCODE_CONTROL                 (1 << 30)
 +#define   HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL        0x1A
  #define   GEN9_PCODE_SAGV_CONTROL             0x21
  #define     GEN9_SAGV_DISABLE                 0x0
  #define     GEN9_SAGV_IS_DISABLED             0x1
  #define   FLOW_CONTROL_ENABLE         (1<<15)
  #define   PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE       (1<<8)
  #define   STALL_DOP_GATING_DISABLE            (1<<5)
 +#define   THROTTLE_12_5                               (7<<2)
  
  #define GEN7_ROW_CHICKEN2             _MMIO(0xe4f4)
  #define GEN7_ROW_CHICKEN2_GT2         _MMIO(0xf4f4)
  #define   DOP_CLOCK_GATING_DISABLE    (1<<0)
 +#define   PUSH_CONSTANT_DEREF_DISABLE (1<<8)
  
  #define HSW_ROW_CHICKEN3              _MMIO(0xe49c)
  #define  HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE    (1 << 6)
  #define   HSW_SAMPLE_C_PERFORMANCE    (1<<9)
  #define   GEN8_CENTROID_PIXEL_OPT_DIS (1<<8)
  #define   GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1<<5)
 +#define   CNL_FAST_ANISO_L1_BANKING_FIX       (1<<4)
  #define   GEN8_SAMPLER_POWER_BYPASS_DIS       (1<<1)
  
  #define GEN9_HALF_SLICE_CHICKEN7      _MMIO(0xe194)
 +#define   GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR      (1<<8)
  #define   GEN9_ENABLE_YV12_BUGFIX     (1<<4)
  #define   GEN9_ENABLE_GPGPU_PREEMPTION        (1<<2)
  
@@@ -8624,7 -8575,7 +8625,7 @@@ enum skl_power_gate 
  #define  DPLL_CFGCR0_LINK_RATE_3240   (6 << 25)
  #define  DPLL_CFGCR0_LINK_RATE_4050   (7 << 25)
  #define  DPLL_CFGCR0_DCO_FRACTION_MASK        (0x7fff << 10)
 -#define  DPLL_CFGCR0_DCO_FRAC_SHIFT   (10)
 +#define  DPLL_CFGCR0_DCO_FRACTION_SHIFT       (10)
  #define  DPLL_CFGCR0_DCO_FRACTION(x)  ((x) << 10)
  #define  DPLL_CFGCR0_DCO_INTEGER_MASK (0x3ff)
  #define CNL_DPLL_CFGCR0(pll)          _MMIO_PLL(pll, _CNL_DPLL0_CFGCR0, _CNL_DPLL1_CFGCR0)
  #define MIPIO_TXESC_CLK_DIV2                  _MMIO(0x160008)
  #define  GLK_TX_ESC_CLK_DIV2_MASK                     0x3FF
  
 +/* Gen4+ Timestamp and Pipe Frame time stamp registers */
 +#define GEN4_TIMESTAMP                _MMIO(0x2358)
 +#define ILK_TIMESTAMP_HI      _MMIO(0x70070)
 +#define IVB_TIMESTAMP_CTR     _MMIO(0x44070)
 +
 +#define _PIPE_FRMTMSTMP_A             0x70048
 +#define PIPE_FRMTMSTMP(pipe)          \
 +                      _MMIO_PIPE2(pipe, _PIPE_FRMTMSTMP_A)
 +
  /* BXT MIPI clock controls */
  #define BXT_MAX_VAR_OUTPUT_KHZ                        39500
  
  #define   GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_SKL  0x67F1427F /*    "        " */
  #define   GEN9_L3_LRA_1_GPGPU_DEFAULT_VALUE_BXT  0x5FF101FF /*    "        " */
  
 +#define MMCD_MISC_CTRL                _MMIO(0x4ddc) /* skl+ */
 +#define  MMCD_PCLA            (1 << 31)
 +#define  MMCD_HOTSPOT_EN      (1 << 27)
 +
  #endif /* _I915_REG_H_ */
index 9d5b4295343618e82784f8e1f8cd2cb23fa00cfd,5d4cd3d00564ce7a95bd02a7a5f56fbcb191337d..e809a9c347d369778e0166172523890db4d1bd79
@@@ -356,7 -356,7 +356,7 @@@ parse_sdvo_panel_data(struct drm_i915_p
        struct drm_display_mode *panel_fixed_mode;
        int index;
  
 -      index = i915.vbt_sdvo_panel_type;
 +      index = i915_modparams.vbt_sdvo_panel_type;
        if (index == -2) {
                DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n");
                return;
@@@ -431,31 -431,70 +431,31 @@@ parse_general_features(struct drm_i915_
                      dev_priv->vbt.fdi_rx_polarity_inverted);
  }
  
 -static void
 -parse_general_definitions(struct drm_i915_private *dev_priv,
 -                        const struct bdb_header *bdb)
 -{
 -      const struct bdb_general_definitions *general;
 -
 -      general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 -      if (general) {
 -              u16 block_size = get_blocksize(general);
 -              if (block_size >= sizeof(*general)) {
 -                      int bus_pin = general->crt_ddc_gmbus_pin;
 -                      DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
 -                      if (intel_gmbus_is_valid_pin(dev_priv, bus_pin))
 -                              dev_priv->vbt.crt_ddc_pin = bus_pin;
 -              } else {
 -                      DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
 -                                    block_size);
 -              }
 -      }
 -}
 -
 -static const union child_device_config *
 -child_device_ptr(const struct bdb_general_definitions *p_defs, int i)
 +static const struct child_device_config *
 +child_device_ptr(const struct bdb_general_definitions *defs, int i)
  {
 -      return (const void *) &p_defs->devices[i * p_defs->child_dev_size];
 +      return (const void *) &defs->devices[i * defs->child_dev_size];
  }
  
  static void
 -parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
 -                        const struct bdb_header *bdb)
 +parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, u8 bdb_version)
  {
 -      struct sdvo_device_mapping *p_mapping;
 -      const struct bdb_general_definitions *p_defs;
 -      const struct old_child_dev_config *child; /* legacy */
 -      int i, child_device_num, count;
 -      u16     block_size;
 -
 -      p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 -      if (!p_defs) {
 -              DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
 -              return;
 -      }
 +      struct sdvo_device_mapping *mapping;
 +      const struct child_device_config *child;
 +      int i, count = 0;
  
        /*
 -       * Only parse SDVO mappings when the general definitions block child
 -       * device size matches that of the *legacy* child device config
 -       * struct. Thus, SDVO mapping will be skipped for newer VBT.
 +       * Only parse SDVO mappings on gens that could have SDVO. This isn't
 +       * accurate and doesn't have to be, as long as it's not too strict.
         */
 -      if (p_defs->child_dev_size != sizeof(*child)) {
 -              DRM_DEBUG_KMS("Unsupported child device size for SDVO mapping.\n");
 +      if (!IS_GEN(dev_priv, 3, 7)) {
 +              DRM_DEBUG_KMS("Skipping SDVO device mapping\n");
                return;
        }
 -      /* get the block size of general definitions */
 -      block_size = get_blocksize(p_defs);
 -      /* get the number of child device */
 -      child_device_num = (block_size - sizeof(*p_defs)) /
 -              p_defs->child_dev_size;
 -      count = 0;
 -      for (i = 0; i < child_device_num; i++) {
 -              child = &child_device_ptr(p_defs, i)->old;
 -              if (!child->device_type) {
 -                      /* skip the device block if device type is invalid */
 -                      continue;
 -              }
 +
 +      for (i = 0, count = 0; i < dev_priv->vbt.child_dev_num; i++) {
 +              child = dev_priv->vbt.child_dev + i;
 +
                if (child->slave_addr != SLAVE_ADDR1 &&
                    child->slave_addr != SLAVE_ADDR2) {
                        /*
                              child->slave_addr,
                              (child->dvo_port == DEVICE_PORT_DVOB) ?
                              "SDVOB" : "SDVOC");
 -              p_mapping = &dev_priv->vbt.sdvo_mappings[child->dvo_port - 1];
 -              if (!p_mapping->initialized) {
 -                      p_mapping->dvo_port = child->dvo_port;
 -                      p_mapping->slave_addr = child->slave_addr;
 -                      p_mapping->dvo_wiring = child->dvo_wiring;
 -                      p_mapping->ddc_pin = child->ddc_pin;
 -                      p_mapping->i2c_pin = child->i2c_pin;
 -                      p_mapping->initialized = 1;
 +              mapping = &dev_priv->vbt.sdvo_mappings[child->dvo_port - 1];
 +              if (!mapping->initialized) {
 +                      mapping->dvo_port = child->dvo_port;
 +                      mapping->slave_addr = child->slave_addr;
 +                      mapping->dvo_wiring = child->dvo_wiring;
 +                      mapping->ddc_pin = child->ddc_pin;
 +                      mapping->i2c_pin = child->i2c_pin;
 +                      mapping->initialized = 1;
                        DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n",
 -                                    p_mapping->dvo_port,
 -                                    p_mapping->slave_addr,
 -                                    p_mapping->dvo_wiring,
 -                                    p_mapping->ddc_pin,
 -                                    p_mapping->i2c_pin);
 +                                    mapping->dvo_port,
 +                                    mapping->slave_addr,
 +                                    mapping->dvo_wiring,
 +                                    mapping->ddc_pin,
 +                                    mapping->i2c_pin);
                } else {
                        DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
                                         "two SDVO device.\n");
                /* No SDVO device info is found */
                DRM_DEBUG_KMS("No SDVO device info is found in VBT\n");
        }
 -      return;
  }
  
  static void
@@@ -537,7 -577,7 +537,7 @@@ parse_edp(struct drm_i915_private *dev_
  {
        const struct bdb_edp *edp;
        const struct edp_power_seq *edp_pps;
 -      const struct edp_link_params *edp_link_params;
 +      const struct edp_fast_link_params *edp_link_params;
        int panel_type = dev_priv->vbt.panel_type;
  
        edp = find_section(bdb, BDB_EDP);
  
        /* Get the eDP sequencing and link info */
        edp_pps = &edp->power_seqs[panel_type];
 -      edp_link_params = &edp->link_params[panel_type];
 +      edp_link_params = &edp->fast_link_params[panel_type];
  
        dev_priv->vbt.edp.pps = *edp_pps;
  
                uint8_t vswing;
  
                /* Don't read from VBT if module parameter has valid value*/
 -              if (i915.edp_vswing) {
 -                      dev_priv->vbt.edp.low_vswing = i915.edp_vswing == 1;
 +              if (i915_modparams.edp_vswing) {
 +                      dev_priv->vbt.edp.low_vswing =
 +                              i915_modparams.edp_vswing == 1;
                } else {
                        vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF;
                        dev_priv->vbt.edp.low_vswing = vswing == 0;
@@@ -1072,9 -1111,9 +1072,9 @@@ static void sanitize_aux_ch(struct drm_
  }
  
  static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
 -                         const struct bdb_header *bdb)
 +                         u8 bdb_version)
  {
 -      union child_device_config *it, *child = NULL;
 +      struct child_device_config *it, *child = NULL;
        struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
        uint8_t hdmi_level_shift;
        int i, j;
                        if (dvo_ports[port][j] == -1)
                                break;
  
 -                      if (it->common.dvo_port == dvo_ports[port][j]) {
 +                      if (it->dvo_port == dvo_ports[port][j]) {
                                if (child) {
                                        DRM_DEBUG_KMS("More than one child device for port %c in VBT, using the first.\n",
                                                      port_name(port));
        if (!child)
                return;
  
 -      aux_channel = child->common.aux_channel;
 -      ddc_pin = child->common.ddc_pin;
 +      aux_channel = child->aux_channel;
 +      ddc_pin = child->ddc_pin;
  
 -      is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;
 -      is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT;
 -      is_crt = child->common.device_type & DEVICE_TYPE_ANALOG_OUTPUT;
 -      is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0;
 -      is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR);
 +      is_dvi = child->device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;
 +      is_dp = child->device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT;
 +      is_crt = child->device_type & DEVICE_TYPE_ANALOG_OUTPUT;
 +      is_hdmi = is_dvi && (child->device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0;
 +      is_edp = is_dp && (child->device_type & DEVICE_TYPE_INTERNAL_CONNECTOR);
 +
 +      if (port == PORT_A && is_dvi) {
 +              DRM_DEBUG_KMS("VBT claims port A supports DVI%s, ignoring\n",
 +                            is_hdmi ? "/HDMI" : "");
 +              is_dvi = false;
 +              is_hdmi = false;
 +      }
  
+       if (port == PORT_A && is_dvi) {
+               DRM_DEBUG_KMS("VBT claims port A supports DVI%s, ignoring\n",
+                             is_hdmi ? "/HDMI" : "");
+               is_dvi = false;
+               is_hdmi = false;
+       }
        info->supports_dvi = is_dvi;
        info->supports_hdmi = is_hdmi;
        info->supports_dp = is_dp;
                sanitize_aux_ch(dev_priv, port);
        }
  
 -      if (bdb->version >= 158) {
 +      if (bdb_version >= 158) {
                /* The VBT HDMI level shift values match the table we have. */
 -              hdmi_level_shift = child->raw[7] & 0xF;
 +              hdmi_level_shift = child->hdmi_level_shifter_value;
                DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n",
                              port_name(port),
                              hdmi_level_shift);
        }
  
        /* Parse the I_boost config for SKL and above */
 -      if (bdb->version >= 196 && child->common.iboost) {
 -              info->dp_boost_level = translate_iboost(child->common.iboost_level & 0xF);
 +      if (bdb_version >= 196 && child->iboost) {
 +              info->dp_boost_level = translate_iboost(child->dp_iboost_level);
                DRM_DEBUG_KMS("VBT (e)DP boost level for port %c: %d\n",
                              port_name(port), info->dp_boost_level);
 -              info->hdmi_boost_level = translate_iboost(child->common.iboost_level >> 4);
 +              info->hdmi_boost_level = translate_iboost(child->hdmi_iboost_level);
                DRM_DEBUG_KMS("VBT HDMI boost level for port %c: %d\n",
                              port_name(port), info->hdmi_boost_level);
        }
  }
  
 -static void parse_ddi_ports(struct drm_i915_private *dev_priv,
 -                          const struct bdb_header *bdb)
 +static void parse_ddi_ports(struct drm_i915_private *dev_priv, u8 bdb_version)
  {
        enum port port;
  
        if (!dev_priv->vbt.child_dev_num)
                return;
  
 -      if (bdb->version < 155)
 +      if (bdb_version < 155)
                return;
  
        for (port = PORT_A; port < I915_MAX_PORTS; port++)
 -              parse_ddi_port(dev_priv, port, bdb);
 +              parse_ddi_port(dev_priv, port, bdb_version);
  }
  
  static void
 -parse_device_mapping(struct drm_i915_private *dev_priv,
 -                   const struct bdb_header *bdb)
 +parse_general_definitions(struct drm_i915_private *dev_priv,
 +                        const struct bdb_header *bdb)
  {
 -      const struct bdb_general_definitions *p_defs;
 -      const union child_device_config *p_child;
 -      union child_device_config *child_dev_ptr;
 +      const struct bdb_general_definitions *defs;
 +      const struct child_device_config *child;
        int i, child_device_num, count;
        u8 expected_size;
        u16 block_size;
 +      int bus_pin;
  
 -      p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 -      if (!p_defs) {
 +      defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 +      if (!defs) {
                DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
                return;
        }
 +
 +      block_size = get_blocksize(defs);
 +      if (block_size < sizeof(*defs)) {
 +              DRM_DEBUG_KMS("General definitions block too small (%u)\n",
 +                            block_size);
 +              return;
 +      }
 +
 +      bus_pin = defs->crt_ddc_gmbus_pin;
 +      DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
 +      if (intel_gmbus_is_valid_pin(dev_priv, bus_pin))
 +              dev_priv->vbt.crt_ddc_pin = bus_pin;
 +
        if (bdb->version < 106) {
                expected_size = 22;
        } else if (bdb->version < 111) {
                expected_size = 27;
        } else if (bdb->version < 195) {
 -              BUILD_BUG_ON(sizeof(struct old_child_dev_config) != 33);
 -              expected_size = sizeof(struct old_child_dev_config);
 +              expected_size = LEGACY_CHILD_DEVICE_CONFIG_SIZE;
        } else if (bdb->version == 195) {
                expected_size = 37;
        } else if (bdb->version <= 197) {
                expected_size = 38;
        } else {
                expected_size = 38;
 -              BUILD_BUG_ON(sizeof(*p_child) < 38);
 +              BUILD_BUG_ON(sizeof(*child) < 38);
                DRM_DEBUG_DRIVER("Expected child device config size for VBT version %u not known; assuming %u\n",
                                 bdb->version, expected_size);
        }
  
        /* Flag an error for unexpected size, but continue anyway. */
 -      if (p_defs->child_dev_size != expected_size)
 +      if (defs->child_dev_size != expected_size)
                DRM_ERROR("Unexpected child device config size %u (expected %u for VBT version %u)\n",
 -                        p_defs->child_dev_size, expected_size, bdb->version);
 +                        defs->child_dev_size, expected_size, bdb->version);
  
        /* The legacy sized child device config is the minimum we need. */
 -      if (p_defs->child_dev_size < sizeof(struct old_child_dev_config)) {
 +      if (defs->child_dev_size < LEGACY_CHILD_DEVICE_CONFIG_SIZE) {
                DRM_DEBUG_KMS("Child device config size %u is too small.\n",
 -                            p_defs->child_dev_size);
 +                            defs->child_dev_size);
                return;
        }
  
 -      /* get the block size of general definitions */
 -      block_size = get_blocksize(p_defs);
        /* get the number of child device */
 -      child_device_num = (block_size - sizeof(*p_defs)) /
 -                              p_defs->child_dev_size;
 +      child_device_num = (block_size - sizeof(*defs)) / defs->child_dev_size;
        count = 0;
        /* get the number of child device that is present */
        for (i = 0; i < child_device_num; i++) {
 -              p_child = child_device_ptr(p_defs, i);
 -              if (!p_child->common.device_type) {
 -                      /* skip the device block if device type is invalid */
 +              child = child_device_ptr(defs, i);
 +              if (!child->device_type)
                        continue;
 -              }
                count++;
        }
        if (!count) {
                DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
                return;
        }
 -      dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
 +      dev_priv->vbt.child_dev = kcalloc(count, sizeof(*child), GFP_KERNEL);
        if (!dev_priv->vbt.child_dev) {
                DRM_DEBUG_KMS("No memory space for child device\n");
                return;
        dev_priv->vbt.child_dev_num = count;
        count = 0;
        for (i = 0; i < child_device_num; i++) {
 -              p_child = child_device_ptr(p_defs, i);
 -              if (!p_child->common.device_type) {
 -                      /* skip the device block if device type is invalid */
 +              child = child_device_ptr(defs, i);
 +              if (!child->device_type)
                        continue;
 -              }
 -
 -              child_dev_ptr = dev_priv->vbt.child_dev + count;
 -              count++;
  
                /*
                 * Copy as much as we know (sizeof) and is available
                 * (child_dev_size) of the child device. Accessing the data must
                 * depend on VBT version.
                 */
 -              memcpy(child_dev_ptr, p_child,
 -                     min_t(size_t, p_defs->child_dev_size, sizeof(*p_child)));
 -
 -              /*
 -               * copied full block, now init values when they are not
 -               * available in current version
 -               */
 -              if (bdb->version < 196) {
 -                      /* Set default values for bits added from v196 */
 -                      child_dev_ptr->common.iboost = 0;
 -                      child_dev_ptr->common.hpd_invert = 0;
 -              }
 -
 -              if (bdb->version < 192)
 -                      child_dev_ptr->common.lspcon = 0;
 +              memcpy(dev_priv->vbt.child_dev + count, child,
 +                     min_t(size_t, defs->child_dev_size, sizeof(*child)));
 +              count++;
        }
 -      return;
  }
  
  /* Common defaults which may be overridden by VBT. */
@@@ -1487,15 -1538,14 +1494,15 @@@ void intel_bios_init(struct drm_i915_pr
        parse_lfp_panel_data(dev_priv, bdb);
        parse_lfp_backlight(dev_priv, bdb);
        parse_sdvo_panel_data(dev_priv, bdb);
 -      parse_sdvo_device_mapping(dev_priv, bdb);
 -      parse_device_mapping(dev_priv, bdb);
        parse_driver_features(dev_priv, bdb);
        parse_edp(dev_priv, bdb);
        parse_psr(dev_priv, bdb);
        parse_mipi_config(dev_priv, bdb);
        parse_mipi_sequence(dev_priv, bdb);
 -      parse_ddi_ports(dev_priv, bdb);
 +
 +      /* Further processing on pre-parsed data */
 +      parse_sdvo_device_mapping(dev_priv, bdb->version);
 +      parse_ddi_ports(dev_priv, bdb->version);
  
  out:
        if (!vbt) {
   */
  bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv)
  {
 -      union child_device_config *p_child;
 +      const struct child_device_config *child;
        int i;
  
        if (!dev_priv->vbt.int_tv_support)
                return true;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              p_child = dev_priv->vbt.child_dev + i;
 +              child = dev_priv->vbt.child_dev + i;
                /*
                 * If the device type is not TV, continue.
                 */
 -              switch (p_child->old.device_type) {
 +              switch (child->device_type) {
                case DEVICE_TYPE_INT_TV:
                case DEVICE_TYPE_TV:
                case DEVICE_TYPE_TV_SVIDEO_COMPOSITE:
                /* Only when the addin_offset is non-zero, it is regarded
                 * as present.
                 */
 -              if (p_child->old.addin_offset)
 +              if (child->addin_offset)
                        return true;
        }
  
   */
  bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin)
  {
 +      const struct child_device_config *child;
        int i;
  
        if (!dev_priv->vbt.child_dev_num)
                return true;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              union child_device_config *uchild = dev_priv->vbt.child_dev + i;
 -              struct old_child_dev_config *child = &uchild->old;
 +              child = dev_priv->vbt.child_dev + i;
  
                /* If the device type is not LFP, continue.
                 * We have to check both the new identifiers as well as the
   */
  bool intel_bios_is_port_present(struct drm_i915_private *dev_priv, enum port port)
  {
 +      const struct child_device_config *child;
        static const struct {
                u16 dp, hdmi;
        } port_mapping[] = {
                return false;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              const union child_device_config *p_child =
 -                      &dev_priv->vbt.child_dev[i];
 -              if ((p_child->common.dvo_port == port_mapping[port].dp ||
 -                   p_child->common.dvo_port == port_mapping[port].hdmi) &&
 -                  (p_child->common.device_type & (DEVICE_TYPE_TMDS_DVI_SIGNALING |
 -                                                  DEVICE_TYPE_DISPLAYPORT_OUTPUT)))
 +              child = dev_priv->vbt.child_dev + i;
 +
 +              if ((child->dvo_port == port_mapping[port].dp ||
 +                   child->dvo_port == port_mapping[port].hdmi) &&
 +                  (child->device_type & (DEVICE_TYPE_TMDS_DVI_SIGNALING |
 +                                         DEVICE_TYPE_DISPLAYPORT_OUTPUT)))
                        return true;
        }
  
   */
  bool intel_bios_is_port_edp(struct drm_i915_private *dev_priv, enum port port)
  {
 -      union child_device_config *p_child;
 +      const struct child_device_config *child;
        static const short port_mapping[] = {
                [PORT_B] = DVO_PORT_DPB,
                [PORT_C] = DVO_PORT_DPC,
                return false;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              p_child = dev_priv->vbt.child_dev + i;
 +              child = dev_priv->vbt.child_dev + i;
  
 -              if (p_child->common.dvo_port == port_mapping[port] &&
 -                  (p_child->common.device_type & DEVICE_TYPE_eDP_BITS) ==
 +              if (child->dvo_port == port_mapping[port] &&
 +                  (child->device_type & DEVICE_TYPE_eDP_BITS) ==
                    (DEVICE_TYPE_eDP & DEVICE_TYPE_eDP_BITS))
                        return true;
        }
        return false;
  }
  
 -static bool child_dev_is_dp_dual_mode(const union child_device_config *p_child,
 +static bool child_dev_is_dp_dual_mode(const struct child_device_config *child,
                                      enum port port)
  {
        static const struct {
        if (port == PORT_A || port >= ARRAY_SIZE(port_mapping))
                return false;
  
 -      if ((p_child->common.device_type & DEVICE_TYPE_DP_DUAL_MODE_BITS) !=
 +      if ((child->device_type & DEVICE_TYPE_DP_DUAL_MODE_BITS) !=
            (DEVICE_TYPE_DP_DUAL_MODE & DEVICE_TYPE_DP_DUAL_MODE_BITS))
                return false;
  
 -      if (p_child->common.dvo_port == port_mapping[port].dp)
 +      if (child->dvo_port == port_mapping[port].dp)
                return true;
  
        /* Only accept a HDMI dvo_port as DP++ if it has an AUX channel */
 -      if (p_child->common.dvo_port == port_mapping[port].hdmi &&
 -          p_child->common.aux_channel != 0)
 +      if (child->dvo_port == port_mapping[port].hdmi &&
 +          child->aux_channel != 0)
                return true;
  
        return false;
  bool intel_bios_is_port_dp_dual_mode(struct drm_i915_private *dev_priv,
                                     enum port port)
  {
 +      const struct child_device_config *child;
        int i;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              const union child_device_config *p_child =
 -                      &dev_priv->vbt.child_dev[i];
 +              child = dev_priv->vbt.child_dev + i;
  
 -              if (child_dev_is_dp_dual_mode(p_child, port))
 +              if (child_dev_is_dp_dual_mode(child, port))
                        return true;
        }
  
  bool intel_bios_is_dsi_present(struct drm_i915_private *dev_priv,
                               enum port *port)
  {
 -      union child_device_config *p_child;
 +      const struct child_device_config *child;
        u8 dvo_port;
        int i;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              p_child = dev_priv->vbt.child_dev + i;
 +              child = dev_priv->vbt.child_dev + i;
  
 -              if (!(p_child->common.device_type & DEVICE_TYPE_MIPI_OUTPUT))
 +              if (!(child->device_type & DEVICE_TYPE_MIPI_OUTPUT))
                        continue;
  
 -              dvo_port = p_child->common.dvo_port;
 +              dvo_port = child->dvo_port;
  
                switch (dvo_port) {
                case DVO_PORT_MIPIA:
  intel_bios_is_port_hpd_inverted(struct drm_i915_private *dev_priv,
                                enum port port)
  {
 +      const struct child_device_config *child;
        int i;
  
        if (WARN_ON_ONCE(!IS_GEN9_LP(dev_priv)))
                return false;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              if (!dev_priv->vbt.child_dev[i].common.hpd_invert)
 +              child = dev_priv->vbt.child_dev + i;
 +
 +              if (!child->hpd_invert)
                        continue;
  
 -              switch (dev_priv->vbt.child_dev[i].common.dvo_port) {
 +              switch (child->dvo_port) {
                case DVO_PORT_DPA:
                case DVO_PORT_HDMIA:
                        if (port == PORT_A)
  intel_bios_is_lspcon_present(struct drm_i915_private *dev_priv,
                                enum port port)
  {
 +      const struct child_device_config *child;
        int i;
  
        if (!HAS_LSPCON(dev_priv))
                return false;
  
        for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
 -              if (!dev_priv->vbt.child_dev[i].common.lspcon)
 +              child = dev_priv->vbt.child_dev + i;
 +
 +              if (!child->lspcon)
                        continue;
  
 -              switch (dev_priv->vbt.child_dev[i].common.dvo_port) {
 +              switch (child->dvo_port) {
                case DVO_PORT_DPA:
                case DVO_PORT_HDMIA:
                        if (port == PORT_A)
index b307b6fe1ce385300627f080f773b4d9294a360c,5e5fe03b638cbf2ee17206ccd4c6ee985134645e..4da7f5c745b604599d8419dc1a2e8d6684426e35
@@@ -301,10 -301,10 +301,10 @@@ static const struct ddi_buf_trans skl_y
  };
  
  struct bxt_ddi_buf_trans {
 -      u32 margin;     /* swing value */
 -      u32 scale;      /* scale value */
 -      u32 enable;     /* scale enable */
 -      u32 deemphasis;
 +      u8 margin;      /* swing value */
 +      u8 scale;       /* scale value */
 +      u8 enable;      /* scale enable */
 +      u8 deemphasis;
        bool default_index; /* true if the entry represents default value */
  };
  
@@@ -354,11 -354,11 +354,11 @@@ static const struct bxt_ddi_buf_trans b
  };
  
  struct cnl_ddi_buf_trans {
 -      u32 dw2_swing_sel;
 -      u32 dw7_n_scalar;
 -      u32 dw4_cursor_coeff;
 -      u32 dw4_post_cursor_2;
 -      u32 dw4_post_cursor_1;
 +      u8 dw2_swing_sel;
 +      u8 dw7_n_scalar;
 +      u8 dw4_cursor_coeff;
 +      u8 dw4_post_cursor_2;
 +      u8 dw4_post_cursor_1;
  };
  
  /* Voltage Swing Programming for VccIO 0.85V for DP */
@@@ -588,73 -588,6 +588,73 @@@ skl_get_buf_trans_hdmi(struct drm_i915_
        }
  }
  
 +static const struct cnl_ddi_buf_trans *
 +cnl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv, int *n_entries)
 +{
 +      u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
 +
 +      if (voltage == VOLTAGE_INFO_0_85V) {
 +              *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V);
 +              return cnl_ddi_translations_hdmi_0_85V;
 +      } else if (voltage == VOLTAGE_INFO_0_95V) {
 +              *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V);
 +              return cnl_ddi_translations_hdmi_0_95V;
 +      } else if (voltage == VOLTAGE_INFO_1_05V) {
 +              *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V);
 +              return cnl_ddi_translations_hdmi_1_05V;
 +      } else {
 +              *n_entries = 1; /* shut up gcc */
 +              MISSING_CASE(voltage);
 +      }
 +      return NULL;
 +}
 +
 +static const struct cnl_ddi_buf_trans *
 +cnl_get_buf_trans_dp(struct drm_i915_private *dev_priv, int *n_entries)
 +{
 +      u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
 +
 +      if (voltage == VOLTAGE_INFO_0_85V) {
 +              *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V);
 +              return cnl_ddi_translations_dp_0_85V;
 +      } else if (voltage == VOLTAGE_INFO_0_95V) {
 +              *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V);
 +              return cnl_ddi_translations_dp_0_95V;
 +      } else if (voltage == VOLTAGE_INFO_1_05V) {
 +              *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V);
 +              return cnl_ddi_translations_dp_1_05V;
 +      } else {
 +              *n_entries = 1; /* shut up gcc */
 +              MISSING_CASE(voltage);
 +      }
 +      return NULL;
 +}
 +
 +static const struct cnl_ddi_buf_trans *
 +cnl_get_buf_trans_edp(struct drm_i915_private *dev_priv, int *n_entries)
 +{
 +      u32 voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
 +
 +      if (dev_priv->vbt.edp.low_vswing) {
 +              if (voltage == VOLTAGE_INFO_0_85V) {
 +                      *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V);
 +                      return cnl_ddi_translations_edp_0_85V;
 +              } else if (voltage == VOLTAGE_INFO_0_95V) {
 +                      *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V);
 +                      return cnl_ddi_translations_edp_0_95V;
 +              } else if (voltage == VOLTAGE_INFO_1_05V) {
 +                      *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V);
 +                      return cnl_ddi_translations_edp_1_05V;
 +              } else {
 +                      *n_entries = 1; /* shut up gcc */
 +                      MISSING_CASE(voltage);
 +              }
 +              return NULL;
 +      } else {
 +              return cnl_get_buf_trans_dp(dev_priv, n_entries);
 +      }
 +}
 +
  static int intel_ddi_hdmi_level(struct drm_i915_private *dev_priv, enum port port)
  {
        int n_hdmi_entries;
        if (IS_GEN9_LP(dev_priv))
                return hdmi_level;
  
 -      if (IS_GEN9_BC(dev_priv)) {
 +      if (IS_CANNONLAKE(dev_priv)) {
 +              cnl_get_buf_trans_hdmi(dev_priv, &n_hdmi_entries);
 +              hdmi_default_entry = n_hdmi_entries - 1;
 +      } else if (IS_GEN9_BC(dev_priv)) {
                skl_get_buf_trans_hdmi(dev_priv, &n_hdmi_entries);
                hdmi_default_entry = 8;
        } else if (IS_BROADWELL(dev_priv)) {
@@@ -734,8 -664,8 +734,8 @@@ intel_ddi_get_buf_trans_fdi(struct drm_
                            int *n_entries)
  {
        if (IS_BROADWELL(dev_priv)) {
-               *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi);
-               return hsw_ddi_translations_fdi;
+               *n_entries = ARRAY_SIZE(bdw_ddi_translations_fdi);
+               return bdw_ddi_translations_fdi;
        } else if (IS_HASWELL(dev_priv)) {
                *n_entries = ARRAY_SIZE(hsw_ddi_translations_fdi);
                return hsw_ddi_translations_fdi;
@@@ -758,6 -688,9 +758,6 @@@ static void intel_prepare_dp_ddi_buffer
        enum port port = intel_ddi_get_encoder_port(encoder);
        const struct ddi_buf_trans *ddi_translations;
  
 -      if (IS_GEN9_LP(dev_priv))
 -              return;
 -
        switch (encoder->type) {
        case INTEL_OUTPUT_EDP:
                ddi_translations = intel_ddi_get_buf_trans_edp(dev_priv,
@@@ -808,6 -741,9 +808,6 @@@ static void intel_prepare_hdmi_ddi_buff
        enum port port = intel_ddi_get_encoder_port(encoder);
        const struct ddi_buf_trans *ddi_translations_hdmi;
  
 -      if (IS_GEN9_LP(dev_priv))
 -              return;
 -
        hdmi_level = intel_ddi_hdmi_level(dev_priv, port);
  
        if (IS_GEN9_BC(dev_priv)) {
@@@ -849,7 -785,7 +849,7 @@@ static void intel_wait_ddi_buf_idle(str
        DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
  }
  
 -static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
 +static uint32_t hsw_pll_to_ddi_pll_sel(const struct intel_shared_dpll *pll)
  {
        switch (pll->id) {
        case DPLL_ID_WRPLL1:
@@@ -1218,10 -1154,7 +1218,10 @@@ static int cnl_calc_wrpll_link(struct d
        dco_freq = (cfgcr0 & DPLL_CFGCR0_DCO_INTEGER_MASK) * ref_clock;
  
        dco_freq += (((cfgcr0 & DPLL_CFGCR0_DCO_FRACTION_MASK) >>
 -                    DPLL_CFGCR0_DCO_FRAC_SHIFT) * ref_clock) / 0x8000;
 +                    DPLL_CFGCR0_DCO_FRACTION_SHIFT) * ref_clock) / 0x8000;
 +
 +      if (WARN_ON(p0 == 0 || p1 == 0 || p2 == 0))
 +              return 0;
  
        return dco_freq / (p0 * p1 * p2 * 5);
  }
@@@ -1889,17 -1822,10 +1889,17 @@@ u8 intel_ddi_dp_voltage_max(struct inte
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        int n_entries;
  
 -      if (encoder->type == INTEL_OUTPUT_EDP)
 -              intel_ddi_get_buf_trans_edp(dev_priv, &n_entries);
 -      else
 -              intel_ddi_get_buf_trans_dp(dev_priv, &n_entries);
 +      if (IS_CANNONLAKE(dev_priv)) {
 +              if (encoder->type == INTEL_OUTPUT_EDP)
 +                      cnl_get_buf_trans_edp(dev_priv, &n_entries);
 +              else
 +                      cnl_get_buf_trans_dp(dev_priv, &n_entries);
 +      } else {
 +              if (encoder->type == INTEL_OUTPUT_EDP)
 +                      intel_ddi_get_buf_trans_edp(dev_priv, &n_entries);
 +              else
 +                      intel_ddi_get_buf_trans_dp(dev_priv, &n_entries);
 +      }
  
        if (WARN_ON(n_entries < 1))
                n_entries = 1;
                DP_TRAIN_VOLTAGE_SWING_MASK;
  }
  
 -static const struct cnl_ddi_buf_trans *
 -cnl_get_buf_trans_hdmi(struct drm_i915_private *dev_priv,
 -                     u32 voltage, int *n_entries)
 -{
 -      if (voltage == VOLTAGE_INFO_0_85V) {
 -              *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_85V);
 -              return cnl_ddi_translations_hdmi_0_85V;
 -      } else if (voltage == VOLTAGE_INFO_0_95V) {
 -              *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_0_95V);
 -              return cnl_ddi_translations_hdmi_0_95V;
 -      } else if (voltage == VOLTAGE_INFO_1_05V) {
 -              *n_entries = ARRAY_SIZE(cnl_ddi_translations_hdmi_1_05V);
 -              return cnl_ddi_translations_hdmi_1_05V;
 -      }
 -      return NULL;
 -}
 -
 -static const struct cnl_ddi_buf_trans *
 -cnl_get_buf_trans_dp(struct drm_i915_private *dev_priv,
 -                   u32 voltage, int *n_entries)
 -{
 -      if (voltage == VOLTAGE_INFO_0_85V) {
 -              *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_85V);
 -              return cnl_ddi_translations_dp_0_85V;
 -      } else if (voltage == VOLTAGE_INFO_0_95V) {
 -              *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_0_95V);
 -              return cnl_ddi_translations_dp_0_95V;
 -      } else if (voltage == VOLTAGE_INFO_1_05V) {
 -              *n_entries = ARRAY_SIZE(cnl_ddi_translations_dp_1_05V);
 -              return cnl_ddi_translations_dp_1_05V;
 -      }
 -      return NULL;
 -}
 -
 -static const struct cnl_ddi_buf_trans *
 -cnl_get_buf_trans_edp(struct drm_i915_private *dev_priv,
 -                    u32 voltage, int *n_entries)
 -{
 -      if (dev_priv->vbt.edp.low_vswing) {
 -              if (voltage == VOLTAGE_INFO_0_85V) {
 -                      *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_85V);
 -                      return cnl_ddi_translations_edp_0_85V;
 -              } else if (voltage == VOLTAGE_INFO_0_95V) {
 -                      *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_0_95V);
 -                      return cnl_ddi_translations_edp_0_95V;
 -              } else if (voltage == VOLTAGE_INFO_1_05V) {
 -                      *n_entries = ARRAY_SIZE(cnl_ddi_translations_edp_1_05V);
 -                      return cnl_ddi_translations_edp_1_05V;
 -              }
 -              return NULL;
 -      } else {
 -              return cnl_get_buf_trans_dp(dev_priv, voltage, n_entries);
 -      }
 -}
 -
  static void cnl_ddi_vswing_program(struct drm_i915_private *dev_priv,
                                    u32 level, enum port port, int type)
  {
        const struct cnl_ddi_buf_trans *ddi_translations = NULL;
 -      u32 n_entries, val, voltage;
 +      u32 n_entries, val;
        int ln;
  
 -      /*
 -       * Values for each port type are listed in
 -       * voltage swing programming tables.
 -       * Vccio voltage found in PORT_COMP_DW3.
 -       */
 -      voltage = I915_READ(CNL_PORT_COMP_DW3) & VOLTAGE_INFO_MASK;
 -
        if (type == INTEL_OUTPUT_HDMI) {
 -              ddi_translations = cnl_get_buf_trans_hdmi(dev_priv,
 -                                                        voltage, &n_entries);
 +              ddi_translations = cnl_get_buf_trans_hdmi(dev_priv, &n_entries);
        } else if (type == INTEL_OUTPUT_DP) {
 -              ddi_translations = cnl_get_buf_trans_dp(dev_priv,
 -                                                      voltage, &n_entries);
 +              ddi_translations = cnl_get_buf_trans_dp(dev_priv, &n_entries);
        } else if (type == INTEL_OUTPUT_EDP) {
 -              ddi_translations = cnl_get_buf_trans_edp(dev_priv,
 -                                                       voltage, &n_entries);
 +              ddi_translations = cnl_get_buf_trans_edp(dev_priv, &n_entries);
        }
  
 -      if (ddi_translations == NULL) {
 -              MISSING_CASE(voltage);
 +      if (WARN_ON(ddi_translations == NULL))
                return;
 -      }
  
        if (level >= n_entries) {
                DRM_DEBUG_KMS("DDI translation not found for level %d. Using %d instead.", level, n_entries - 1);
        val |= RCOMP_SCALAR(0x98);
        I915_WRITE(CNL_PORT_TX_DW2_GRP(port), val);
  
 -        /* Program PORT_TX_DW4 */
 +      /* Program PORT_TX_DW4 */
        /* We cannot write to GRP. It would overrite individual loadgen */
        for (ln = 0; ln < 4; ln++) {
                val = I915_READ(CNL_PORT_TX_DW4_LN(port, ln));
                I915_WRITE(CNL_PORT_TX_DW4_LN(port, ln), val);
        }
  
 -        /* Program PORT_TX_DW5 */
 +      /* Program PORT_TX_DW5 */
        /* All DW5 values are fixed for every table entry */
        val = I915_READ(CNL_PORT_TX_DW5_LN0(port));
        val &= ~RTERM_SELECT_MASK;
        val |= TAP3_DISABLE;
        I915_WRITE(CNL_PORT_TX_DW5_GRP(port), val);
  
 -        /* Program PORT_TX_DW7 */
 +      /* Program PORT_TX_DW7 */
        val = I915_READ(CNL_PORT_TX_DW7_LN0(port));
        val &= ~N_SCALAR_MASK;
        val |= N_SCALAR(ddi_translations[level].dw7_n_scalar);
@@@ -2062,46 -2055,33 +2062,46 @@@ static uint32_t translate_signal_level(
        return 0;
  }
  
 -uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
 +static uint32_t intel_ddi_dp_level(struct intel_dp *intel_dp)
  {
 -      struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
 -      struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
 -      struct intel_encoder *encoder = &dport->base;
        uint8_t train_set = intel_dp->train_set[0];
        int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
                                         DP_TRAIN_PRE_EMPHASIS_MASK);
 +
 +      return translate_signal_level(signal_levels);
 +}
 +
 +u32 bxt_signal_levels(struct intel_dp *intel_dp)
 +{
 +      struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
 +      struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
 +      struct intel_encoder *encoder = &dport->base;
        enum port port = dport->port;
 -      uint32_t level;
 +      u32 level = intel_ddi_dp_level(intel_dp);
 +
 +      if (IS_CANNONLAKE(dev_priv))
 +              cnl_ddi_vswing_sequence(encoder, level);
 +      else
 +              bxt_ddi_vswing_sequence(dev_priv, level, port, encoder->type);
 +
 +      return 0;
 +}
  
 -      level = translate_signal_level(signal_levels);
 +uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
 +{
 +      struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
 +      struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
 +      struct intel_encoder *encoder = &dport->base;
 +      uint32_t level = intel_ddi_dp_level(intel_dp);
  
        if (IS_GEN9_BC(dev_priv))
 -              skl_ddi_set_iboost(encoder, level);
 -      else if (IS_GEN9_LP(dev_priv))
 -              bxt_ddi_vswing_sequence(dev_priv, level, port, encoder->type);
 -      else if (IS_CANNONLAKE(dev_priv)) {
 -              cnl_ddi_vswing_sequence(encoder, level);
 -              /* DDI_BUF_CTL bits 27:24 are reserved on CNL */
 -              return 0;
 -      }
 +          skl_ddi_set_iboost(encoder, level);
 +
        return DDI_BUF_TRANS_SELECT(level);
  }
  
  static void intel_ddi_clk_select(struct intel_encoder *encoder,
 -                               struct intel_shared_dpll *pll)
 +                               const struct intel_shared_dpll *pll)
  {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum port port = intel_ddi_get_encoder_port(encoder);
                 * register writes.
                 */
                val = I915_READ(DPCLKA_CFGCR0);
-               val &= ~(DPCLKA_CFGCR0_DDI_CLK_OFF(port) |
-                        DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port));
+               val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
                I915_WRITE(DPCLKA_CFGCR0, val);
        } else if (IS_GEN9_BC(dev_priv)) {
                /* DDI -> PLL mapping  */
@@@ -2150,7 -2129,6 +2149,7 @@@ static void intel_ddi_pre_enable_dp(str
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        enum port port = intel_ddi_get_encoder_port(encoder);
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
 +      uint32_t level = intel_ddi_dp_level(intel_dp);
  
        WARN_ON(link_mst && (port == PORT_A || port == PORT_E));
  
  
        intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
  
 -      intel_prepare_dp_ddi_buffers(encoder);
 +      if (IS_CANNONLAKE(dev_priv))
 +              cnl_ddi_vswing_sequence(encoder, level);
 +      else if (IS_GEN9_LP(dev_priv))
 +              bxt_ddi_vswing_sequence(dev_priv, level, port, encoder->type);
 +      else
 +              intel_prepare_dp_ddi_buffers(encoder);
 +
        intel_ddi_init_dp_buf_reg(encoder);
 -      intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
 +      if (!link_mst)
 +              intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        intel_dp_start_link_train(intel_dp);
        if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
                intel_dp_stop_link_train(intel_dp);
  }
  
  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 -                                    bool has_hdmi_sink,
 +                                    bool has_infoframe,
                                      const struct intel_crtc_state *crtc_state,
                                      const struct drm_connector_state *conn_state,
 -                                    struct intel_shared_dpll *pll)
 +                                    const struct intel_shared_dpll *pll)
  {
 -      struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 +      struct intel_digital_port *intel_dig_port = enc_to_dig_port(&encoder->base);
 +      struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 -      struct drm_encoder *drm_encoder = &encoder->base;
        enum port port = intel_ddi_get_encoder_port(encoder);
        int level = intel_ddi_hdmi_level(dev_priv, port);
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
  
        intel_display_power_get(dev_priv, dig_port->ddi_io_power_domain);
  
 -      intel_prepare_hdmi_ddi_buffers(encoder);
 -      if (IS_GEN9_BC(dev_priv))
 -              skl_ddi_set_iboost(encoder, level);
 +      if (IS_CANNONLAKE(dev_priv))
 +              cnl_ddi_vswing_sequence(encoder, level);
        else if (IS_GEN9_LP(dev_priv))
                bxt_ddi_vswing_sequence(dev_priv, level, port,
                                        INTEL_OUTPUT_HDMI);
 -      else if (IS_CANNONLAKE(dev_priv))
 -              cnl_ddi_vswing_sequence(encoder, level);
 +      else
 +              intel_prepare_hdmi_ddi_buffers(encoder);
 +
 +      if (IS_GEN9_BC(dev_priv))
 +              skl_ddi_set_iboost(encoder, level);
  
 -      intel_hdmi->set_infoframes(drm_encoder,
 -                                 has_hdmi_sink,
 -                                 crtc_state, conn_state);
 +      intel_dig_port->set_infoframes(&encoder->base,
 +                                     has_infoframe,
 +                                     crtc_state, conn_state);
  }
  
  static void intel_ddi_pre_enable(struct intel_encoder *encoder,
 -                               struct intel_crtc_state *pipe_config,
 -                               struct drm_connector_state *conn_state)
 +                               const struct intel_crtc_state *pipe_config,
 +                               const struct drm_connector_state *conn_state)
  {
 +      struct drm_crtc *crtc = pipe_config->base.crtc;
 +      struct drm_i915_private *dev_priv = to_i915(crtc->dev);
 +      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      int pipe = intel_crtc->pipe;
        int type = encoder->type;
  
 +      WARN_ON(intel_crtc->config->has_pch_encoder);
 +
 +      intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
 +
        if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
                intel_ddi_pre_enable_dp(encoder,
                                        pipe_config->port_clock,
        }
        if (type == INTEL_OUTPUT_HDMI) {
                intel_ddi_pre_enable_hdmi(encoder,
 -                                        pipe_config->has_hdmi_sink,
 +                                        pipe_config->has_infoframe,
                                          pipe_config, conn_state,
                                          pipe_config->shared_dpll);
        }
  }
  
  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
 -                                 struct intel_crtc_state *old_crtc_state,
 -                                 struct drm_connector_state *old_conn_state)
 +                                 const struct intel_crtc_state *old_crtc_state,
 +                                 const struct drm_connector_state *old_conn_state)
  {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_i915_private *dev_priv = to_i915(encoder->dev);
        enum port port = intel_ddi_get_encoder_port(intel_encoder);
        struct intel_digital_port *dig_port = enc_to_dig_port(encoder);
 -      struct intel_dp *intel_dp = NULL;
        int type = intel_encoder->type;
        uint32_t val;
        bool wait = false;
  
 -      /* old_crtc_state and old_conn_state are NULL when called from DP_MST */
 -
        if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
 -              intel_dp = enc_to_intel_dp(encoder);
 -              intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
 +              /*
 +               * old_crtc_state and old_conn_state are NULL when called from
 +               * DP_MST. The main connector associated with this port is never
 +               * bound to a crtc for MST.
 +               */
 +              bool is_mst = !old_crtc_state;
 +              struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 +
 +              /*
 +               * Power down sink before disabling the port, otherwise we end
 +               * up getting interrupts from the sink on detecting link loss.
 +               */
 +              if (!is_mst)
 +                      intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        }
  
        val = I915_READ(DDI_BUF_CTL(port));
        if (wait)
                intel_wait_ddi_buf_idle(dev_priv, port);
  
 -      if (intel_dp) {
 +      if (type == INTEL_OUTPUT_HDMI) {
 +              dig_port->set_infoframes(encoder, false,
 +                                       old_crtc_state, old_conn_state);
 +      }
 +
 +      if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
 +              struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 +
                intel_edp_panel_vdd_on(intel_dp);
                intel_edp_panel_off(intel_dp);
        }
  }
  
  void intel_ddi_fdi_post_disable(struct intel_encoder *encoder,
 -                              struct intel_crtc_state *old_crtc_state,
 -                              struct drm_connector_state *old_conn_state)
 +                              const struct intel_crtc_state *old_crtc_state,
 +                              const struct drm_connector_state *old_conn_state)
  {
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        uint32_t val;
  }
  
  static void intel_enable_ddi(struct intel_encoder *intel_encoder,
 -                           struct intel_crtc_state *pipe_config,
 -                           struct drm_connector_state *conn_state)
 +                           const struct intel_crtc_state *pipe_config,
 +                           const struct drm_connector_state *conn_state)
  {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_i915_private *dev_priv = to_i915(encoder->dev);
                        intel_dp_stop_link_train(intel_dp);
  
                intel_edp_backlight_on(pipe_config, conn_state);
 -              intel_psr_enable(intel_dp);
 +              intel_psr_enable(intel_dp, pipe_config);
                intel_edp_drrs_enable(intel_dp, pipe_config);
        }
  
  }
  
  static void intel_disable_ddi(struct intel_encoder *intel_encoder,
 -                            struct intel_crtc_state *old_crtc_state,
 -                            struct drm_connector_state *old_conn_state)
 +                            const struct intel_crtc_state *old_crtc_state,
 +                            const struct drm_connector_state *old_conn_state)
  {
        struct drm_encoder *encoder = &intel_encoder->base;
        int type = intel_encoder->type;
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
  
                intel_edp_drrs_disable(intel_dp, old_crtc_state);
 -              intel_psr_disable(intel_dp);
 +              intel_psr_disable(intel_dp, old_crtc_state);
                intel_edp_backlight_off(old_conn_state);
        }
  }
  
  static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder,
 -                                 struct intel_crtc_state *pipe_config,
 -                                 struct drm_connector_state *conn_state)
 +                                 const struct intel_crtc_state *pipe_config,
 +                                 const struct drm_connector_state *conn_state)
  {
        uint8_t mask = pipe_config->lane_lat_optim_mask;
  
@@@ -2490,7 -2435,7 +2489,7 @@@ void intel_ddi_get_config(struct intel_
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
 -      struct intel_hdmi *intel_hdmi;
 +      struct intel_digital_port *intel_dig_port;
        u32 temp, flags = 0;
  
        /* XXX: DSI transcoder paranoia */
        switch (temp & TRANS_DDI_MODE_SELECT_MASK) {
        case TRANS_DDI_MODE_SELECT_HDMI:
                pipe_config->has_hdmi_sink = true;
 -              intel_hdmi = enc_to_intel_hdmi(&encoder->base);
 +              intel_dig_port = enc_to_dig_port(&encoder->base);
  
 -              if (intel_hdmi->infoframe_enabled(&encoder->base, pipe_config))
 +              if (intel_dig_port->infoframe_enabled(&encoder->base, pipe_config))
                        pipe_config->has_infoframe = true;
  
                if ((temp & TRANS_DDI_HDMI_SCRAMBLING_MASK) ==
@@@ -2784,8 -2729,6 +2783,8 @@@ void intel_ddi_init(struct drm_i915_pri
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        intel_encoder->cloneable = 0;
  
 +      intel_infoframe_init(intel_dig_port);
 +
        if (init_dp) {
                if (!intel_ddi_init_dp_connector(intel_dig_port))
                        goto err;
index a59b2a30ff5ab9b99998d12d27792c4aa15defad,3c2d9cf22ed5a537253a14c2fe85ee200ce7b24c..40e439ca3eb3962356e98beb1329fdaeafbe9278
@@@ -22,8 -22,6 +22,8 @@@
   *
   */
  
 +#include <drm/drm_print.h>
 +
  #include "i915_drv.h"
  #include "intel_ringbuffer.h"
  #include "intel_lrc.h"
@@@ -41,7 -39,6 +41,7 @@@
  
  #define GEN8_LR_CONTEXT_RENDER_SIZE   (20 * PAGE_SIZE)
  #define GEN9_LR_CONTEXT_RENDER_SIZE   (22 * PAGE_SIZE)
 +#define GEN10_LR_CONTEXT_RENDER_SIZE  (18 * PAGE_SIZE)
  
  #define GEN8_LR_CONTEXT_OTHER_SIZE    ( 2 * PAGE_SIZE)
  
@@@ -153,11 -150,10 +153,11 @@@ __intel_engine_context_size(struct drm_
                default:
                        MISSING_CASE(INTEL_GEN(dev_priv));
                case 10:
 +                      return GEN10_LR_CONTEXT_RENDER_SIZE;
                case 9:
                        return GEN9_LR_CONTEXT_RENDER_SIZE;
                case 8:
 -                      return i915.enable_execlists ?
 +                      return i915_modparams.enable_execlists ?
                               GEN8_LR_CONTEXT_RENDER_SIZE :
                               GEN8_CXT_TOTAL_SIZE;
                case 7:
@@@ -305,7 -301,7 +305,7 @@@ int intel_engines_init(struct drm_i915_
                        &intel_engine_classes[engine->class];
                int (*init)(struct intel_engine_cs *engine);
  
 -              if (i915.enable_execlists)
 +              if (i915_modparams.enable_execlists)
                        init = class_info->init_execlists;
                else
                        init = class_info->init_legacy;
@@@ -384,37 -380,6 +384,37 @@@ static void intel_engine_init_timeline(
        engine->timeline = &engine->i915->gt.global_timeline.engine[engine->id];
  }
  
 +static bool csb_force_mmio(struct drm_i915_private *i915)
 +{
 +      /* GVT emulation depends upon intercepting CSB mmio */
 +      if (intel_vgpu_active(i915))
 +              return true;
 +
 +      /*
 +       * IOMMU adds unpredictable latency causing the CSB write (from the
 +       * GPU into the HWSP) to only be visible some time after the interrupt
 +       * (missed breadcrumb syndrome).
 +       */
 +      if (intel_vtd_active())
 +              return true;
 +
 +      return false;
 +}
 +
 +static void intel_engine_init_execlist(struct intel_engine_cs *engine)
 +{
 +      struct intel_engine_execlists * const execlists = &engine->execlists;
 +
 +      execlists->csb_use_mmio = csb_force_mmio(engine->i915);
 +
 +      execlists->port_mask = 1;
 +      BUILD_BUG_ON_NOT_POWER_OF_2(execlists_num_ports(execlists));
 +      GEM_BUG_ON(execlists_num_ports(execlists) > EXECLIST_MAX_PORTS);
 +
 +      execlists->queue = RB_ROOT;
 +      execlists->first = NULL;
 +}
 +
  /**
   * intel_engines_setup_common - setup engine state not requiring hw access
   * @engine: Engine to setup.
   */
  void intel_engine_setup_common(struct intel_engine_cs *engine)
  {
 -      engine->execlist_queue = RB_ROOT;
 -      engine->execlist_first = NULL;
 +      intel_engine_init_execlist(engine);
  
        intel_engine_init_timeline(engine);
        intel_engine_init_hangcheck(engine);
@@@ -476,116 -442,6 +476,116 @@@ static void intel_engine_cleanup_scratc
        i915_vma_unpin_and_release(&engine->scratch);
  }
  
 +static void cleanup_phys_status_page(struct intel_engine_cs *engine)
 +{
 +      struct drm_i915_private *dev_priv = engine->i915;
 +
 +      if (!dev_priv->status_page_dmah)
 +              return;
 +
 +      drm_pci_free(&dev_priv->drm, dev_priv->status_page_dmah);
 +      engine->status_page.page_addr = NULL;
 +}
 +
 +static void cleanup_status_page(struct intel_engine_cs *engine)
 +{
 +      struct i915_vma *vma;
 +      struct drm_i915_gem_object *obj;
 +
 +      vma = fetch_and_zero(&engine->status_page.vma);
 +      if (!vma)
 +              return;
 +
 +      obj = vma->obj;
 +
 +      i915_vma_unpin(vma);
 +      i915_vma_close(vma);
 +
 +      i915_gem_object_unpin_map(obj);
 +      __i915_gem_object_release_unless_active(obj);
 +}
 +
 +static int init_status_page(struct intel_engine_cs *engine)
 +{
 +      struct drm_i915_gem_object *obj;
 +      struct i915_vma *vma;
 +      unsigned int flags;
 +      void *vaddr;
 +      int ret;
 +
 +      obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
 +      if (IS_ERR(obj)) {
 +              DRM_ERROR("Failed to allocate status page\n");
 +              return PTR_ERR(obj);
 +      }
 +
 +      ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
 +      if (ret)
 +              goto err;
 +
 +      vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
 +      if (IS_ERR(vma)) {
 +              ret = PTR_ERR(vma);
 +              goto err;
 +      }
 +
 +      flags = PIN_GLOBAL;
 +      if (!HAS_LLC(engine->i915))
 +              /* On g33, we cannot place HWS above 256MiB, so
 +               * restrict its pinning to the low mappable arena.
 +               * Though this restriction is not documented for
 +               * gen4, gen5, or byt, they also behave similarly
 +               * and hang if the HWS is placed at the top of the
 +               * GTT. To generalise, it appears that all !llc
 +               * platforms have issues with us placing the HWS
 +               * above the mappable region (even though we never
 +               * actually map it).
 +               */
 +              flags |= PIN_MAPPABLE;
 +      else
 +              flags |= PIN_HIGH;
 +      ret = i915_vma_pin(vma, 0, 4096, flags);
 +      if (ret)
 +              goto err;
 +
 +      vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB);
 +      if (IS_ERR(vaddr)) {
 +              ret = PTR_ERR(vaddr);
 +              goto err_unpin;
 +      }
 +
 +      engine->status_page.vma = vma;
 +      engine->status_page.ggtt_offset = i915_ggtt_offset(vma);
 +      engine->status_page.page_addr = memset(vaddr, 0, PAGE_SIZE);
 +
 +      DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
 +                       engine->name, i915_ggtt_offset(vma));
 +      return 0;
 +
 +err_unpin:
 +      i915_vma_unpin(vma);
 +err:
 +      i915_gem_object_put(obj);
 +      return ret;
 +}
 +
 +static int init_phys_status_page(struct intel_engine_cs *engine)
 +{
 +      struct drm_i915_private *dev_priv = engine->i915;
 +
 +      GEM_BUG_ON(engine->id != RCS);
 +
 +      dev_priv->status_page_dmah =
 +              drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE);
 +      if (!dev_priv->status_page_dmah)
 +              return -ENOMEM;
 +
 +      engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
 +      memset(engine->status_page.page_addr, 0, PAGE_SIZE);
 +
 +      return 0;
 +}
 +
  /**
   * intel_engines_init_common - initialize cengine state which might require hw access
   * @engine: Engine to initialize.
@@@ -615,44 -471,17 +615,44 @@@ int intel_engine_init_common(struct int
        if (IS_ERR(ring))
                return PTR_ERR(ring);
  
 +      /*
 +       * Similarly the preempt context must always be available so that
 +       * we can interrupt the engine at any time.
 +       */
 +      if (INTEL_INFO(engine->i915)->has_logical_ring_preemption) {
 +              ring = engine->context_pin(engine,
 +                                         engine->i915->preempt_context);
 +              if (IS_ERR(ring)) {
 +                      ret = PTR_ERR(ring);
 +                      goto err_unpin_kernel;
 +              }
 +      }
 +
        ret = intel_engine_init_breadcrumbs(engine);
        if (ret)
 -              goto err_unpin;
 +              goto err_unpin_preempt;
  
        ret = i915_gem_render_state_init(engine);
        if (ret)
 -              goto err_unpin;
 +              goto err_breadcrumbs;
 +
 +      if (HWS_NEEDS_PHYSICAL(engine->i915))
 +              ret = init_phys_status_page(engine);
 +      else
 +              ret = init_status_page(engine);
 +      if (ret)
 +              goto err_rs_fini;
  
        return 0;
  
 -err_unpin:
 +err_rs_fini:
 +      i915_gem_render_state_fini(engine);
 +err_breadcrumbs:
 +      intel_engine_fini_breadcrumbs(engine);
 +err_unpin_preempt:
 +      if (INTEL_INFO(engine->i915)->has_logical_ring_preemption)
 +              engine->context_unpin(engine, engine->i915->preempt_context);
 +err_unpin_kernel:
        engine->context_unpin(engine, engine->i915->kernel_context);
        return ret;
  }
@@@ -668,18 -497,11 +668,18 @@@ void intel_engine_cleanup_common(struc
  {
        intel_engine_cleanup_scratch(engine);
  
 +      if (HWS_NEEDS_PHYSICAL(engine->i915))
 +              cleanup_phys_status_page(engine);
 +      else
 +              cleanup_status_page(engine);
 +
        i915_gem_render_state_fini(engine);
        intel_engine_fini_breadcrumbs(engine);
        intel_engine_cleanup_cmd_parser(engine);
        i915_gem_batch_pool_fini(&engine->batch_pool);
  
 +      if (INTEL_INFO(engine->i915)->has_logical_ring_preemption)
 +              engine->context_unpin(engine, engine->i915->preempt_context);
        engine->context_unpin(engine, engine->i915->kernel_context);
  }
  
@@@ -850,6 -672,11 +850,6 @@@ static int wa_add(struct drm_i915_priva
  #define WA_SET_FIELD_MASKED(addr, mask, value) \
        WA_REG(addr, mask, _MASKED_FIELD(mask, value))
  
 -#define WA_SET_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) | (mask))
 -#define WA_CLR_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) & ~(mask))
 -
 -#define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val)
 -
  static int wa_ring_whitelist_reg(struct intel_engine_cs *engine,
                                 i915_reg_t reg)
  {
        if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS))
                return -EINVAL;
  
 -      WA_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index),
 -               i915_mmio_reg_offset(reg));
 +      I915_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index),
 +                 i915_mmio_reg_offset(reg));
        wa->hw_whitelist_count[engine->id]++;
  
        return 0;
@@@ -985,23 -812,6 +985,23 @@@ static int gen9_init_workarounds(struc
                I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
                           ECOCHK_DIS_TLB);
  
 +      if (HAS_LLC(dev_priv)) {
 +              /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl
 +               *
 +               * Must match Display Engine. See
 +               * WaCompressedResourceDisplayNewHashMode.
 +               */
 +              WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
 +                                GEN9_PBE_COMPRESSED_HASH_SELECTION);
 +              WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
 +                                GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR);
 +
 +              I915_WRITE(MMCD_MISC_CTRL,
 +                         I915_READ(MMCD_MISC_CTRL) |
 +                         MMCD_PCLA |
 +                         MMCD_HOTSPOT_EN);
 +      }
 +
        /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */
        /* WaDisablePartialInstShootdown:skl,bxt,kbl,glk,cfl */
        WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
        I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) |
                                    GEN8_LQSC_FLUSH_COHERENT_LINES));
  
 +      /*
 +       * Supporting preemption with fine-granularity requires changes in the
 +       * batch buffer programming. Since we can't break old userspace, we
 +       * need to set our default preemption level to safe value. Userspace is
 +       * still able to use more fine-grained preemption levels, since in
 +       * WaEnablePreemptionGranularityControlByUMD we're whitelisting the
 +       * per-ctx register. As such, WaDisable{3D,GPGPU}MidCmdPreemption are
 +       * not real HW workarounds, but merely a way to start using preemption
 +       * while maintaining old contract with userspace.
 +       */
 +
 +      /* WaDisable3DMidCmdPreemption:skl,bxt,glk,cfl,[cnl] */
 +      WA_CLR_BIT_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_3D_OBJECT_LEVEL);
 +
 +      /* WaDisableGPGPUMidCmdPreemption:skl,bxt,blk,cfl,[cnl] */
 +      WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_GPGPU_LEVEL_MASK,
 +                          GEN9_PREEMPT_GPGPU_COMMAND_LEVEL);
 +
        /* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt,glk,cfl */
        ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG);
        if (ret)
                return ret;
  
 -      /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl */
 -      ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1);
 +      /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,[cnl] */
 +      I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1,
 +                 _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL));
 +      ret = wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1);
        if (ret)
                return ret;
  
@@@ -1178,19 -968,25 +1178,19 @@@ static int skl_init_workarounds(struct 
        if (ret)
                return ret;
  
 -      /*
 -       * Actual WA is to disable percontext preemption granularity control
 -       * until D0 which is the default case so this is equivalent to
 -       * !WaDisablePerCtxtPreemptionGranularityControl:skl
 -       */
 -      I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1,
 -                 _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL));
 -
        /* WaEnableGapsTsvCreditFix:skl */
        I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
                                   GEN9_GAPS_TSV_CREDIT_DISABLE));
  
        /* WaDisableGafsUnitClkGating:skl */
 -      WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
 +      I915_WRITE(GEN7_UCGCTL4, (I915_READ(GEN7_UCGCTL4) |
 +                                GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE));
  
        /* WaInPlaceDecompressionHang:skl */
        if (IS_SKL_REVID(dev_priv, SKL_REVID_H0, REVID_FOREVER))
 -              WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
 -                         GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
 +              I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA,
 +                         (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) |
 +                          GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS));
  
        /* WaDisableLSQCROPERFforOCL:skl */
        ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
@@@ -1226,8 -1022,8 +1226,8 @@@ static int bxt_init_workarounds(struct 
  
        /* WaDisablePooledEuLoadBalancingFix:bxt */
        if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER)) {
 -              WA_SET_BIT_MASKED(FF_SLICE_CS_CHICKEN2,
 -                                GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE);
 +              I915_WRITE(FF_SLICE_CS_CHICKEN2,
 +                         _MASKED_BIT_ENABLE(GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE));
        }
  
        /* WaDisableSbeCacheDispatchPortSharing:bxt */
        }
  
        /* WaProgramL3SqcReg1DefaultForPerf:bxt */
-       if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER))
-               I915_WRITE(GEN8_L3SQCREG1, L3_GENERAL_PRIO_CREDITS(62) |
-                                          L3_HIGH_PRIO_CREDITS(2));
+       if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER)) {
+               u32 val = I915_READ(GEN8_L3SQCREG1);
+               val &= ~L3_PRIO_CREDITS_MASK;
+               val |= L3_GENERAL_PRIO_CREDITS(62) | L3_HIGH_PRIO_CREDITS(2);
+               I915_WRITE(GEN8_L3SQCREG1, val);
+       }
  
        /* WaToEnableHwFixForPushConstHWBug:bxt */
        if (IS_BXT_REVID(dev_priv, BXT_REVID_C0, REVID_FOREVER))
  
        /* WaInPlaceDecompressionHang:bxt */
        if (IS_BXT_REVID(dev_priv, BXT_REVID_C0, REVID_FOREVER))
 -              WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
 -                         GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
 +              I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA,
 +                         (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) |
 +                          GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS));
 +
 +      return 0;
 +}
 +
 +static int cnl_init_workarounds(struct intel_engine_cs *engine)
 +{
 +      struct drm_i915_private *dev_priv = engine->i915;
 +      int ret;
 +
 +      /* WaDisableI2mCycleOnWRPort:cnl (pre-prod) */
 +      if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0))
 +              I915_WRITE(GAMT_CHKN_BIT_REG,
 +                         (I915_READ(GAMT_CHKN_BIT_REG) |
 +                          GAMT_CHKN_DISABLE_I2M_CYCLE_ON_WR_PORT));
 +
 +      /* WaForceContextSaveRestoreNonCoherent:cnl */
 +      WA_SET_BIT_MASKED(CNL_HDC_CHICKEN0,
 +                        HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT);
 +
 +      /* WaThrottleEUPerfToAvoidTDBackPressure:cnl(pre-prod) */
 +      if (IS_CNL_REVID(dev_priv, CNL_REVID_B0, CNL_REVID_B0))
 +              WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, THROTTLE_12_5);
 +
 +      /* WaDisableReplayBufferBankArbitrationOptimization:cnl */
 +      WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
 +                        GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
 +
 +      /* WaDisableEnhancedSBEVertexCaching:cnl (pre-prod) */
 +      if (IS_CNL_REVID(dev_priv, 0, CNL_REVID_B0))
 +              WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
 +                                GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE);
 +
 +      /* WaInPlaceDecompressionHang:cnl */
 +      I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA,
 +                 (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) |
 +                  GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS));
 +
 +      /* WaPushConstantDereferenceHoldDisable:cnl */
 +      WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2, PUSH_CONSTANT_DEREF_DISABLE);
 +
 +      /* FtrEnableFastAnisoL1BankingFix: cnl */
 +      WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, CNL_FAST_ANISO_L1_BANKING_FIX);
 +
 +      /* WaDisable3DMidCmdPreemption:cnl */
 +      WA_CLR_BIT_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_3D_OBJECT_LEVEL);
 +
 +      /* WaDisableGPGPUMidCmdPreemption:cnl */
 +      WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_GPGPU_LEVEL_MASK,
 +                          GEN9_PREEMPT_GPGPU_COMMAND_LEVEL);
 +
 +      /* WaEnablePreemptionGranularityControlByUMD:cnl */
 +      I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1,
 +                 _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL));
 +      ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1);
 +      if (ret)
 +              return ret;
  
        return 0;
  }
@@@ -1341,9 -1083,8 +1344,9 @@@ static int kbl_init_workarounds(struct 
  
        /* WaDisableDynamicCreditSharing:kbl */
        if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
 -              WA_SET_BIT(GAMT_CHKN_BIT_REG,
 -                         GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING);
 +              I915_WRITE(GAMT_CHKN_BIT_REG,
 +                         (I915_READ(GAMT_CHKN_BIT_REG) |
 +                          GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING));
  
        /* WaDisableFenceDestinationToSLM:kbl (pre-prod) */
        if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0))
                                  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
  
        /* WaDisableGafsUnitClkGating:kbl */
 -      WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
 +      I915_WRITE(GEN7_UCGCTL4, (I915_READ(GEN7_UCGCTL4) |
 +                                GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE));
  
        /* WaDisableSbeCacheDispatchPortSharing:kbl */
        WA_SET_BIT_MASKED(
                GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
  
        /* WaInPlaceDecompressionHang:kbl */
 -      WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
 -                 GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
 +      I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA,
 +                 (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) |
 +                  GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS));
  
        /* WaDisableLSQCROPERFforOCL:kbl */
        ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
@@@ -1411,8 -1150,7 +1414,8 @@@ static int cfl_init_workarounds(struct 
                          GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
  
        /* WaDisableGafsUnitClkGating:cfl */
 -      WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
 +      I915_WRITE(GEN7_UCGCTL4, (I915_READ(GEN7_UCGCTL4) |
 +                                GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE));
  
        /* WaDisableSbeCacheDispatchPortSharing:cfl */
        WA_SET_BIT_MASKED(
                GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
  
        /* WaInPlaceDecompressionHang:cfl */
 -      WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
 -                 GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
 +      I915_WRITE(GEN9_GAMT_ECO_REG_RW_IA,
 +                 (I915_READ(GEN9_GAMT_ECO_REG_RW_IA) |
 +                  GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS));
  
        return 0;
  }
@@@ -1451,8 -1188,6 +1454,8 @@@ int init_workarounds_ring(struct intel_
                err =  glk_init_workarounds(engine);
        else if (IS_COFFEELAKE(dev_priv))
                err = cfl_init_workarounds(engine);
 +      else if (IS_CANNONLAKE(dev_priv))
 +              err = cnl_init_workarounds(engine);
        else
                err = 0;
        if (err)
@@@ -1545,11 -1280,11 +1548,11 @@@ bool intel_engine_is_idle(struct intel_
                return false;
  
        /* Both ports drained, no more ELSP submission? */
 -      if (port_request(&engine->execlist_port[0]))
 +      if (port_request(&engine->execlists.port[0]))
                return false;
  
        /* ELSP is empty, but there are ready requests? */
 -      if (READ_ONCE(engine->execlist_first))
 +      if (READ_ONCE(engine->execlists.first))
                return false;
  
        /* Ring stopped? */
@@@ -1598,184 -1333,11 +1601,184 @@@ void intel_engines_mark_idle(struct drm
        for_each_engine(engine, i915, id) {
                intel_engine_disarm_breadcrumbs(engine);
                i915_gem_batch_pool_fini(&engine->batch_pool);
 -              tasklet_kill(&engine->irq_tasklet);
 -              engine->no_priolist = false;
 +              tasklet_kill(&engine->execlists.irq_tasklet);
 +              engine->execlists.no_priolist = false;
 +      }
 +}
 +
 +bool intel_engine_can_store_dword(struct intel_engine_cs *engine)
 +{
 +      switch (INTEL_GEN(engine->i915)) {
 +      case 2:
 +              return false; /* uses physical not virtual addresses */
 +      case 3:
 +              /* maybe only uses physical not virtual addresses */
 +              return !(IS_I915G(engine->i915) || IS_I915GM(engine->i915));
 +      case 6:
 +              return engine->class != VIDEO_DECODE_CLASS; /* b0rked */
 +      default:
 +              return true;
        }
  }
  
 +static void print_request(struct drm_printer *m,
 +                        struct drm_i915_gem_request *rq,
 +                        const char *prefix)
 +{
 +      drm_printf(m, "%s%x [%x:%x] prio=%d @ %dms: %s\n", prefix,
 +                 rq->global_seqno, rq->ctx->hw_id, rq->fence.seqno,
 +                 rq->priotree.priority,
 +                 jiffies_to_msecs(jiffies - rq->emitted_jiffies),
 +                 rq->timeline->common->name);
 +}
 +
 +void intel_engine_dump(struct intel_engine_cs *engine, struct drm_printer *m)
 +{
 +      struct intel_breadcrumbs *b = &engine->breadcrumbs;
 +      struct i915_gpu_error *error = &engine->i915->gpu_error;
 +      struct drm_i915_private *dev_priv = engine->i915;
 +      struct drm_i915_gem_request *rq;
 +      struct rb_node *rb;
 +      u64 addr;
 +
 +      drm_printf(m, "%s\n", engine->name);
 +      drm_printf(m, "\tcurrent seqno %x, last %x, hangcheck %x [%d ms], inflight %d\n",
 +                 intel_engine_get_seqno(engine),
 +                 intel_engine_last_submit(engine),
 +                 engine->hangcheck.seqno,
 +                 jiffies_to_msecs(jiffies - engine->hangcheck.action_timestamp),
 +                 engine->timeline->inflight_seqnos);
 +      drm_printf(m, "\tReset count: %d\n",
 +                 i915_reset_engine_count(error, engine));
 +
 +      rcu_read_lock();
 +
 +      drm_printf(m, "\tRequests:\n");
 +
 +      rq = list_first_entry(&engine->timeline->requests,
 +                            struct drm_i915_gem_request, link);
 +      if (&rq->link != &engine->timeline->requests)
 +              print_request(m, rq, "\t\tfirst  ");
 +
 +      rq = list_last_entry(&engine->timeline->requests,
 +                           struct drm_i915_gem_request, link);
 +      if (&rq->link != &engine->timeline->requests)
 +              print_request(m, rq, "\t\tlast   ");
 +
 +      rq = i915_gem_find_active_request(engine);
 +      if (rq) {
 +              print_request(m, rq, "\t\tactive ");
 +              drm_printf(m,
 +                         "\t\t[head %04x, postfix %04x, tail %04x, batch 0x%08x_%08x]\n",
 +                         rq->head, rq->postfix, rq->tail,
 +                         rq->batch ? upper_32_bits(rq->batch->node.start) : ~0u,
 +                         rq->batch ? lower_32_bits(rq->batch->node.start) : ~0u);
 +      }
 +
 +      drm_printf(m, "\tRING_START: 0x%08x [0x%08x]\n",
 +                 I915_READ(RING_START(engine->mmio_base)),
 +                 rq ? i915_ggtt_offset(rq->ring->vma) : 0);
 +      drm_printf(m, "\tRING_HEAD:  0x%08x [0x%08x]\n",
 +                 I915_READ(RING_HEAD(engine->mmio_base)) & HEAD_ADDR,
 +                 rq ? rq->ring->head : 0);
 +      drm_printf(m, "\tRING_TAIL:  0x%08x [0x%08x]\n",
 +                 I915_READ(RING_TAIL(engine->mmio_base)) & TAIL_ADDR,
 +                 rq ? rq->ring->tail : 0);
 +      drm_printf(m, "\tRING_CTL:   0x%08x [%s]\n",
 +                 I915_READ(RING_CTL(engine->mmio_base)),
 +                 I915_READ(RING_CTL(engine->mmio_base)) & (RING_WAIT | RING_WAIT_SEMAPHORE) ? "waiting" : "");
 +
 +      rcu_read_unlock();
 +
 +      addr = intel_engine_get_active_head(engine);
 +      drm_printf(m, "\tACTHD:  0x%08x_%08x\n",
 +                 upper_32_bits(addr), lower_32_bits(addr));
 +      addr = intel_engine_get_last_batch_head(engine);
 +      drm_printf(m, "\tBBADDR: 0x%08x_%08x\n",
 +                 upper_32_bits(addr), lower_32_bits(addr));
 +
 +      if (i915_modparams.enable_execlists) {
 +              const u32 *hws = &engine->status_page.page_addr[I915_HWS_CSB_BUF0_INDEX];
 +              struct intel_engine_execlists * const execlists = &engine->execlists;
 +              u32 ptr, read, write;
 +              unsigned int idx;
 +
 +              drm_printf(m, "\tExeclist status: 0x%08x %08x\n",
 +                         I915_READ(RING_EXECLIST_STATUS_LO(engine)),
 +                         I915_READ(RING_EXECLIST_STATUS_HI(engine)));
 +
 +              ptr = I915_READ(RING_CONTEXT_STATUS_PTR(engine));
 +              read = GEN8_CSB_READ_PTR(ptr);
 +              write = GEN8_CSB_WRITE_PTR(ptr);
 +              drm_printf(m, "\tExeclist CSB read %d [%d cached], write %d [%d from hws], interrupt posted? %s\n",
 +                         read, execlists->csb_head,
 +                         write,
 +                         intel_read_status_page(engine, intel_hws_csb_write_index(engine->i915)),
 +                         yesno(test_bit(ENGINE_IRQ_EXECLIST,
 +                                        &engine->irq_posted)));
 +              if (read >= GEN8_CSB_ENTRIES)
 +                      read = 0;
 +              if (write >= GEN8_CSB_ENTRIES)
 +                      write = 0;
 +              if (read > write)
 +                      write += GEN8_CSB_ENTRIES;
 +              while (read < write) {
 +                      idx = ++read % GEN8_CSB_ENTRIES;
 +                      drm_printf(m, "\tExeclist CSB[%d]: 0x%08x [0x%08x in hwsp], context: %d [%d in hwsp]\n",
 +                                 idx,
 +                                 I915_READ(RING_CONTEXT_STATUS_BUF_LO(engine, idx)),
 +                                 hws[idx * 2],
 +                                 I915_READ(RING_CONTEXT_STATUS_BUF_HI(engine, idx)),
 +                                 hws[idx * 2 + 1]);
 +              }
 +
 +              rcu_read_lock();
 +              for (idx = 0; idx < execlists_num_ports(execlists); idx++) {
 +                      unsigned int count;
 +
 +                      rq = port_unpack(&execlists->port[idx], &count);
 +                      if (rq) {
 +                              drm_printf(m, "\t\tELSP[%d] count=%d, ",
 +                                         idx, count);
 +                              print_request(m, rq, "rq: ");
 +                      } else {
 +                              drm_printf(m, "\t\tELSP[%d] idle\n",
 +                                         idx);
 +                      }
 +              }
 +              rcu_read_unlock();
 +
 +              spin_lock_irq(&engine->timeline->lock);
 +              for (rb = execlists->first; rb; rb = rb_next(rb)) {
 +                      struct i915_priolist *p =
 +                              rb_entry(rb, typeof(*p), node);
 +
 +                      list_for_each_entry(rq, &p->requests,
 +                                          priotree.link)
 +                              print_request(m, rq, "\t\tQ ");
 +              }
 +              spin_unlock_irq(&engine->timeline->lock);
 +      } else if (INTEL_GEN(dev_priv) > 6) {
 +              drm_printf(m, "\tPP_DIR_BASE: 0x%08x\n",
 +                         I915_READ(RING_PP_DIR_BASE(engine)));
 +              drm_printf(m, "\tPP_DIR_BASE_READ: 0x%08x\n",
 +                         I915_READ(RING_PP_DIR_BASE_READ(engine)));
 +              drm_printf(m, "\tPP_DIR_DCLV: 0x%08x\n",
 +                         I915_READ(RING_PP_DIR_DCLV(engine)));
 +      }
 +
 +      spin_lock_irq(&b->rb_lock);
 +      for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
 +              struct intel_wait *w = rb_entry(rb, typeof(*w), node);
 +
 +              drm_printf(m, "\t%s [%d] waiting for %x\n",
 +                         w->tsk->comm, w->tsk->pid, w->seqno);
 +      }
 +      spin_unlock_irq(&b->rb_lock);
 +
 +      drm_printf(m, "\n");
 +}
 +
  #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
  #include "selftests/mock_engine.c"
  #endif
index 2fcff9788b6f3122d152aef60ce2ddcc26230fad,0a09f8ff6aff6710ea3580329d83646a67593b8c..985b59770eec5fcbe92feff8c9b316b6f2fedc21
  
  static void gen9_init_clock_gating(struct drm_i915_private *dev_priv)
  {
 +      if (HAS_LLC(dev_priv)) {
 +              /*
 +               * WaCompressedResourceDisplayNewHashMode:skl,kbl
 +               * Display WA#0390: skl,kbl
 +               *
 +               * Must match Sampler, Pixel Back End, and Media. See
 +               * WaCompressedResourceSamplerPbeMediaNewHashMode.
 +               */
 +              I915_WRITE(CHICKEN_PAR1_1,
 +                         I915_READ(CHICKEN_PAR1_1) |
 +                         SKL_DE_COMPRESSED_HASH_MODE);
 +      }
 +
        /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl,cfl */
        I915_WRITE(CHICKEN_PAR1_1,
                   I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP);
  
 -      /*
 -       * Display WA#0390: skl,bxt,kbl,glk
 -       *
 -       * Must match Sampler, Pixel Back End, and Media
 -       * (0xE194 bit 8, 0x7014 bit 13, 0x4DDC bits 27 and 31).
 -       *
 -       * Including bits outside the page in the hash would
 -       * require 2 (or 4?) MiB alignment of resources. Just
 -       * assume the defaul hashing mode which only uses bits
 -       * within the page.
 -       */
 -      I915_WRITE(CHICKEN_PAR1_1,
 -                 I915_READ(CHICKEN_PAR1_1) & ~SKL_RC_HASH_OUTSIDE);
 -
        I915_WRITE(GEN8_CONFIG0,
                   I915_READ(GEN8_CONFIG0) | GEN9_DEFAULT_FIXES);
  
@@@ -124,7 -125,6 +124,7 @@@ static void bxt_init_clock_gating(struc
  
  static void glk_init_clock_gating(struct drm_i915_private *dev_priv)
  {
 +      u32 val;
        gen9_init_clock_gating(dev_priv);
  
        /*
                I915_WRITE(CHICKEN_MISC_2, val);
        }
  
 +      /* Display WA #1133: WaFbcSkipSegments:glk */
 +      val = I915_READ(ILK_DPFC_CHICKEN);
 +      val &= ~GLK_SKIP_SEG_COUNT_MASK;
 +      val |= GLK_SKIP_SEG_EN | GLK_SKIP_SEG_COUNT(1);
 +      I915_WRITE(ILK_DPFC_CHICKEN, val);
  }
  
  static void i915_pineview_get_mem_freq(struct drm_i915_private *dev_priv)
@@@ -322,7 -317,7 +322,7 @@@ static void chv_set_memory_dvfs(struct 
  {
        u32 val;
  
 -      mutex_lock(&dev_priv->rps.hw_lock);
 +      mutex_lock(&dev_priv->pcu_lock);
  
        val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2);
        if (enable)
                      FORCE_DDR_FREQ_REQ_ACK) == 0, 3))
                DRM_ERROR("timed out waiting for Punit DDR DVFS request\n");
  
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
  }
  
  static void chv_set_memory_pm5(struct drm_i915_private *dev_priv, bool enable)
  {
        u32 val;
  
 -      mutex_lock(&dev_priv->rps.hw_lock);
 +      mutex_lock(&dev_priv->pcu_lock);
  
        val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
        if (enable)
                val &= ~DSP_MAXFIFO_PM5_ENABLE;
        vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
  
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
  }
  
  #define FW_WM(value, plane) \
@@@ -1327,21 -1322,21 +1327,21 @@@ static int g4x_compute_pipe_wm(struct i
        int num_active_planes = hweight32(crtc_state->active_planes &
                                          ~BIT(PLANE_CURSOR));
        const struct g4x_pipe_wm *raw;
 -      struct intel_plane_state *plane_state;
 +      const struct intel_plane_state *old_plane_state;
 +      const struct intel_plane_state *new_plane_state;
        struct intel_plane *plane;
        enum plane_id plane_id;
        int i, level;
        unsigned int dirty = 0;
  
 -      for_each_intel_plane_in_state(state, plane, plane_state, i) {
 -              const struct intel_plane_state *old_plane_state =
 -                      to_intel_plane_state(plane->base.state);
 -
 -              if (plane_state->base.crtc != &crtc->base &&
 +      for_each_oldnew_intel_plane_in_state(state, plane,
 +                                           old_plane_state,
 +                                           new_plane_state, i) {
 +              if (new_plane_state->base.crtc != &crtc->base &&
                    old_plane_state->base.crtc != &crtc->base)
                        continue;
  
 -              if (g4x_raw_plane_wm_compute(crtc_state, plane_state))
 +              if (g4x_raw_plane_wm_compute(crtc_state, new_plane_state))
                        dirty |= BIT(plane->id);
        }
  
@@@ -1836,21 -1831,21 +1836,21 @@@ static int vlv_compute_pipe_wm(struct i
        int num_active_planes = hweight32(crtc_state->active_planes &
                                          ~BIT(PLANE_CURSOR));
        bool needs_modeset = drm_atomic_crtc_needs_modeset(&crtc_state->base);
 -      struct intel_plane_state *plane_state;
 +      const struct intel_plane_state *old_plane_state;
 +      const struct intel_plane_state *new_plane_state;
        struct intel_plane *plane;
        enum plane_id plane_id;
        int level, ret, i;
        unsigned int dirty = 0;
  
 -      for_each_intel_plane_in_state(state, plane, plane_state, i) {
 -              const struct intel_plane_state *old_plane_state =
 -                      to_intel_plane_state(plane->base.state);
 -
 -              if (plane_state->base.crtc != &crtc->base &&
 +      for_each_oldnew_intel_plane_in_state(state, plane,
 +                                           old_plane_state,
 +                                           new_plane_state, i) {
 +              if (new_plane_state->base.crtc != &crtc->base &&
                    old_plane_state->base.crtc != &crtc->base)
                        continue;
  
 -              if (vlv_raw_plane_wm_compute(crtc_state, plane_state))
 +              if (vlv_raw_plane_wm_compute(crtc_state, new_plane_state))
                        dirty |= BIT(plane->id);
        }
  
        /* cursor changes don't warrant a FIFO recompute */
        if (dirty & ~BIT(PLANE_CURSOR)) {
                const struct intel_crtc_state *old_crtc_state =
 -                      to_intel_crtc_state(crtc->base.state);
 +                      intel_atomic_get_old_crtc_state(state, crtc);
                const struct vlv_fifo_state *old_fifo_state =
                        &old_crtc_state->wm.vlv.fifo_state;
  
@@@ -2790,11 -2785,11 +2790,11 @@@ static void intel_read_wm_latency(struc
  
                /* read the first set of memory latencies[0:3] */
                val = 0; /* data0 to be programmed to 0 for first set */
 -              mutex_lock(&dev_priv->rps.hw_lock);
 +              mutex_lock(&dev_priv->pcu_lock);
                ret = sandybridge_pcode_read(dev_priv,
                                             GEN9_PCODE_READ_MEM_LATENCY,
                                             &val);
 -              mutex_unlock(&dev_priv->rps.hw_lock);
 +              mutex_unlock(&dev_priv->pcu_lock);
  
                if (ret) {
                        DRM_ERROR("SKL Mailbox read error = %d\n", ret);
  
                /* read the second set of memory latencies[4:7] */
                val = 1; /* data0 to be programmed to 1 for second set */
 -              mutex_lock(&dev_priv->rps.hw_lock);
 +              mutex_lock(&dev_priv->pcu_lock);
                ret = sandybridge_pcode_read(dev_priv,
                                             GEN9_PCODE_READ_MEM_LATENCY,
                                             &val);
 -              mutex_unlock(&dev_priv->rps.hw_lock);
 +              mutex_unlock(&dev_priv->pcu_lock);
                if (ret) {
                        DRM_ERROR("SKL Mailbox read error = %d\n", ret);
                        return;
@@@ -3608,13 -3603,13 +3608,13 @@@ intel_enable_sagv(struct drm_i915_priva
                return 0;
  
        DRM_DEBUG_KMS("Enabling the SAGV\n");
 -      mutex_lock(&dev_priv->rps.hw_lock);
 +      mutex_lock(&dev_priv->pcu_lock);
  
        ret = sandybridge_pcode_write(dev_priv, GEN9_PCODE_SAGV_CONTROL,
                                      GEN9_SAGV_ENABLE);
  
        /* We don't need to wait for the SAGV when enabling */
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
  
        /*
         * Some skl systems, pre-release machines in particular,
@@@ -3645,14 -3640,14 +3645,14 @@@ intel_disable_sagv(struct drm_i915_priv
                return 0;
  
        DRM_DEBUG_KMS("Disabling the SAGV\n");
 -      mutex_lock(&dev_priv->rps.hw_lock);
 +      mutex_lock(&dev_priv->pcu_lock);
  
        /* bspec says to keep retrying for at least 1 ms */
        ret = skl_pcode_request(dev_priv, GEN9_PCODE_SAGV_CONTROL,
                                GEN9_SAGV_DISABLE,
                                GEN9_SAGV_IS_DISABLED, GEN9_SAGV_IS_DISABLED,
                                1);
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
  
        /*
         * Some skl systems, pre-release machines in particular,
@@@ -4375,147 -4370,134 +4375,147 @@@ skl_adjusted_plane_pixel_rate(const str
                                            downscale_amount);
  }
  
 -static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 -                              struct intel_crtc_state *cstate,
 -                              const struct intel_plane_state *intel_pstate,
 -                              uint16_t ddb_allocation,
 -                              int level,
 -                              uint16_t *out_blocks, /* out */
 -                              uint8_t *out_lines, /* out */
 -                              bool *enabled /* out */)
 +static int
 +skl_compute_plane_wm_params(const struct drm_i915_private *dev_priv,
 +                          struct intel_crtc_state *cstate,
 +                          const struct intel_plane_state *intel_pstate,
 +                          struct skl_wm_params *wp)
  {
        struct intel_plane *plane = to_intel_plane(intel_pstate->base.plane);
        const struct drm_plane_state *pstate = &intel_pstate->base;
        const struct drm_framebuffer *fb = pstate->fb;
 -      uint32_t latency = dev_priv->wm.skl_latency[level];
 -      uint_fixed_16_16_t method1, method2;
 -      uint_fixed_16_16_t plane_blocks_per_line;
 -      uint_fixed_16_16_t selected_result;
        uint32_t interm_pbpl;
 -      uint32_t plane_bytes_per_line;
 -      uint32_t res_blocks, res_lines;
 -      uint8_t cpp;
 -      uint32_t width = 0;
 -      uint32_t plane_pixel_rate;
 -      uint_fixed_16_16_t y_tile_minimum;
 -      uint32_t y_min_scanlines;
        struct intel_atomic_state *state =
                to_intel_atomic_state(cstate->base.state);
        bool apply_memory_bw_wa = skl_needs_memory_bw_wa(state);
 -      bool y_tiled, x_tiled;
  
 -      if (latency == 0 ||
 -          !intel_wm_plane_visible(cstate, intel_pstate)) {
 -              *enabled = false;
 +      if (!intel_wm_plane_visible(cstate, intel_pstate))
                return 0;
 -      }
  
 -      y_tiled = fb->modifier == I915_FORMAT_MOD_Y_TILED ||
 -                fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
 -                fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
 -                fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
 -      x_tiled = fb->modifier == I915_FORMAT_MOD_X_TILED;
 -
 -      /* Display WA #1141: kbl,cfl */
 -      if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) &&
 -          dev_priv->ipc_enabled)
 -              latency += 4;
 -
 -      if (apply_memory_bw_wa && x_tiled)
 -              latency += 15;
 +      wp->y_tiled = fb->modifier == I915_FORMAT_MOD_Y_TILED ||
 +                    fb->modifier == I915_FORMAT_MOD_Yf_TILED ||
 +                    fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
 +                    fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
 +      wp->x_tiled = fb->modifier == I915_FORMAT_MOD_X_TILED;
 +      wp->rc_surface = fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
 +                       fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS;
  
        if (plane->id == PLANE_CURSOR) {
 -              width = intel_pstate->base.crtc_w;
 +              wp->width = intel_pstate->base.crtc_w;
        } else {
                /*
                 * Src coordinates are already rotated by 270 degrees for
                 * the 90/270 degree plane rotation cases (to match the
                 * GTT mapping), hence no need to account for rotation here.
                 */
 -              width = drm_rect_width(&intel_pstate->base.src) >> 16;
 +              wp->width = drm_rect_width(&intel_pstate->base.src) >> 16;
        }
  
 -      cpp = (fb->format->format == DRM_FORMAT_NV12) ? fb->format->cpp[1] :
 -                                                      fb->format->cpp[0];
 -      plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate, intel_pstate);
 +      wp->cpp = (fb->format->format == DRM_FORMAT_NV12) ? fb->format->cpp[1] :
 +                                                          fb->format->cpp[0];
 +      wp->plane_pixel_rate = skl_adjusted_plane_pixel_rate(cstate,
 +                                                           intel_pstate);
  
        if (drm_rotation_90_or_270(pstate->rotation)) {
  
 -              switch (cpp) {
 +              switch (wp->cpp) {
                case 1:
 -                      y_min_scanlines = 16;
 +                      wp->y_min_scanlines = 16;
                        break;
                case 2:
 -                      y_min_scanlines = 8;
 +                      wp->y_min_scanlines = 8;
                        break;
                case 4:
 -                      y_min_scanlines = 4;
 +                      wp->y_min_scanlines = 4;
                        break;
                default:
 -                      MISSING_CASE(cpp);
 +                      MISSING_CASE(wp->cpp);
                        return -EINVAL;
                }
        } else {
 -              y_min_scanlines = 4;
 +              wp->y_min_scanlines = 4;
        }
  
        if (apply_memory_bw_wa)
 -              y_min_scanlines *= 2;
 +              wp->y_min_scanlines *= 2;
  
 -      plane_bytes_per_line = width * cpp;
 -      if (y_tiled) {
 -              interm_pbpl = DIV_ROUND_UP(plane_bytes_per_line *
 -                                         y_min_scanlines, 512);
 +      wp->plane_bytes_per_line = wp->width * wp->cpp;
 +      if (wp->y_tiled) {
 +              interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line *
 +                                         wp->y_min_scanlines, 512);
  
                if (INTEL_GEN(dev_priv) >= 10)
                        interm_pbpl++;
  
 -              plane_blocks_per_line = div_fixed16(interm_pbpl,
 -                                                      y_min_scanlines);
 -      } else if (x_tiled && INTEL_GEN(dev_priv) == 9) {
 -              interm_pbpl = DIV_ROUND_UP(plane_bytes_per_line, 512);
 -              plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
 +              wp->plane_blocks_per_line = div_fixed16(interm_pbpl,
 +                                                      wp->y_min_scanlines);
 +      } else if (wp->x_tiled && IS_GEN9(dev_priv)) {
 +              interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, 512);
 +              wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
        } else {
 -              interm_pbpl = DIV_ROUND_UP(plane_bytes_per_line, 512) + 1;
 -              plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
 +              interm_pbpl = DIV_ROUND_UP(wp->plane_bytes_per_line, 512) + 1;
 +              wp->plane_blocks_per_line = u32_to_fixed16(interm_pbpl);
 +      }
 +
 +      wp->y_tile_minimum = mul_u32_fixed16(wp->y_min_scanlines,
 +                                           wp->plane_blocks_per_line);
 +      wp->linetime_us = fixed16_to_u32_round_up(
 +                                      intel_get_linetime_us(cstate));
 +
 +      return 0;
 +}
 +
 +static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 +                              struct intel_crtc_state *cstate,
 +                              const struct intel_plane_state *intel_pstate,
 +                              uint16_t ddb_allocation,
 +                              int level,
 +                              const struct skl_wm_params *wp,
 +                              uint16_t *out_blocks, /* out */
 +                              uint8_t *out_lines, /* out */
 +                              bool *enabled /* out */)
 +{
 +      const struct drm_plane_state *pstate = &intel_pstate->base;
 +      uint32_t latency = dev_priv->wm.skl_latency[level];
 +      uint_fixed_16_16_t method1, method2;
 +      uint_fixed_16_16_t selected_result;
 +      uint32_t res_blocks, res_lines;
 +      struct intel_atomic_state *state =
 +              to_intel_atomic_state(cstate->base.state);
 +      bool apply_memory_bw_wa = skl_needs_memory_bw_wa(state);
 +
 +      if (latency == 0 ||
 +          !intel_wm_plane_visible(cstate, intel_pstate)) {
 +              *enabled = false;
 +              return 0;
        }
  
 -      method1 = skl_wm_method1(dev_priv, plane_pixel_rate, cpp, latency);
 -      method2 = skl_wm_method2(plane_pixel_rate,
 +      /* Display WA #1141: kbl,cfl */
 +      if ((IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv) ||
 +          IS_CNL_REVID(dev_priv, CNL_REVID_A0, CNL_REVID_B0)) &&
 +          dev_priv->ipc_enabled)
 +              latency += 4;
 +
 +      if (apply_memory_bw_wa && wp->x_tiled)
 +              latency += 15;
 +
 +      method1 = skl_wm_method1(dev_priv, wp->plane_pixel_rate,
 +                               wp->cpp, latency);
 +      method2 = skl_wm_method2(wp->plane_pixel_rate,
                                 cstate->base.adjusted_mode.crtc_htotal,
                                 latency,
 -                               plane_blocks_per_line);
 +                               wp->plane_blocks_per_line);
  
 -      y_tile_minimum = mul_u32_fixed16(y_min_scanlines,
 -                                       plane_blocks_per_line);
 -
 -      if (y_tiled) {
 -              selected_result = max_fixed16(method2, y_tile_minimum);
 +      if (wp->y_tiled) {
 +              selected_result = max_fixed16(method2, wp->y_tile_minimum);
        } else {
 -              uint32_t linetime_us;
 -
 -              linetime_us = fixed16_to_u32_round_up(
 -                              intel_get_linetime_us(cstate));
 -              if ((cpp * cstate->base.adjusted_mode.crtc_htotal / 512 < 1) &&
 -                  (plane_bytes_per_line / 512 < 1))
 +              if ((wp->cpp * cstate->base.adjusted_mode.crtc_htotal /
 +                   512 < 1) && (wp->plane_bytes_per_line / 512 < 1))
                        selected_result = method2;
                else if (ddb_allocation >=
 -                       fixed16_to_u32_round_up(plane_blocks_per_line))
 +                       fixed16_to_u32_round_up(wp->plane_blocks_per_line))
                        selected_result = min_fixed16(method1, method2);
 -              else if (latency >= linetime_us)
 +              else if (latency >= wp->linetime_us)
                        selected_result = min_fixed16(method1, method2);
                else
                        selected_result = method1;
  
        res_blocks = fixed16_to_u32_round_up(selected_result) + 1;
        res_lines = div_round_up_fixed16(selected_result,
 -                                       plane_blocks_per_line);
 +                                       wp->plane_blocks_per_line);
  
        /* Display WA #1125: skl,bxt,kbl,glk */
 -      if (level == 0 &&
 -          (fb->modifier == I915_FORMAT_MOD_Y_TILED_CCS ||
 -           fb->modifier == I915_FORMAT_MOD_Yf_TILED_CCS))
 -              res_blocks += fixed16_to_u32_round_up(y_tile_minimum);
 +      if (level == 0 && wp->rc_surface)
 +              res_blocks += fixed16_to_u32_round_up(wp->y_tile_minimum);
  
        /* Display WA #1126: skl,bxt,kbl,glk */
        if (level >= 1 && level <= 7) {
 -              if (y_tiled) {
 -                      res_blocks += fixed16_to_u32_round_up(y_tile_minimum);
 -                      res_lines += y_min_scanlines;
 +              if (wp->y_tiled) {
 +                      res_blocks += fixed16_to_u32_round_up(
 +                                                      wp->y_tile_minimum);
 +                      res_lines += wp->y_min_scanlines;
                } else {
                        res_blocks++;
                }
@@@ -4572,7 -4555,6 +4572,7 @@@ skl_compute_wm_levels(const struct drm_
                      struct skl_ddb_allocation *ddb,
                      struct intel_crtc_state *cstate,
                      const struct intel_plane_state *intel_pstate,
 +                    const struct skl_wm_params *wm_params,
                      struct skl_plane_wm *wm)
  {
        struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
                                           intel_pstate,
                                           ddb_blocks,
                                           level,
 +                                         wm_params,
                                           &result->plane_res_b,
                                           &result->plane_res_l,
                                           &result->plane_en);
@@@ -4622,65 -4603,20 +4622,65 @@@ skl_compute_linetime_wm(struct intel_cr
  
        linetime_wm = fixed16_to_u32_round_up(mul_u32_fixed16(8, linetime_us));
  
 -      /* Display WA #1135: bxt. */
 -      if (IS_BROXTON(dev_priv) && dev_priv->ipc_enabled)
 -              linetime_wm = DIV_ROUND_UP(linetime_wm, 2);
 +      /* Display WA #1135: bxt:ALL GLK:ALL */
 +      if ((IS_BROXTON(dev_priv) || IS_GEMINILAKE(dev_priv)) &&
 +          dev_priv->ipc_enabled)
 +              linetime_wm /= 2;
  
        return linetime_wm;
  }
  
  static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
 +                                    struct skl_wm_params *wp,
 +                                    struct skl_wm_level *wm_l0,
 +                                    uint16_t ddb_allocation,
                                      struct skl_wm_level *trans_wm /* out */)
  {
 +      struct drm_device *dev = cstate->base.crtc->dev;
 +      const struct drm_i915_private *dev_priv = to_i915(dev);
 +      uint16_t trans_min, trans_y_tile_min;
 +      const uint16_t trans_amount = 10; /* This is configurable amount */
 +      uint16_t trans_offset_b, res_blocks;
 +
        if (!cstate->base.active)
 +              goto exit;
 +
 +      /* Transition WM are not recommended by HW team for GEN9 */
 +      if (INTEL_GEN(dev_priv) <= 9)
 +              goto exit;
 +
 +      /* Transition WM don't make any sense if ipc is disabled */
 +      if (!dev_priv->ipc_enabled)
 +              goto exit;
 +
 +      if (INTEL_GEN(dev_priv) >= 10)
 +              trans_min = 4;
 +
 +      trans_offset_b = trans_min + trans_amount;
 +
 +      if (wp->y_tiled) {
 +              trans_y_tile_min = (uint16_t) mul_round_up_u32_fixed16(2,
 +                                                      wp->y_tile_minimum);
 +              res_blocks = max(wm_l0->plane_res_b, trans_y_tile_min) +
 +                              trans_offset_b;
 +      } else {
 +              res_blocks = wm_l0->plane_res_b + trans_offset_b;
 +
 +              /* WA BUG:1938466 add one block for non y-tile planes */
 +              if (IS_CNL_REVID(dev_priv, CNL_REVID_A0, CNL_REVID_A0))
 +                      res_blocks += 1;
 +
 +      }
 +
 +      res_blocks += 1;
 +
 +      if (res_blocks < ddb_allocation) {
 +              trans_wm->plane_res_b = res_blocks;
 +              trans_wm->plane_en = true;
                return;
 +      }
  
 -      /* Until we know more, just disable transition WMs */
 +exit:
        trans_wm->plane_en = false;
  }
  
@@@ -4706,25 -4642,14 +4706,25 @@@ static int skl_build_pipe_wm(struct int
                const struct intel_plane_state *intel_pstate =
                                                to_intel_plane_state(pstate);
                enum plane_id plane_id = to_intel_plane(plane)->id;
 +              struct skl_wm_params wm_params;
 +              enum pipe pipe = to_intel_crtc(cstate->base.crtc)->pipe;
 +              uint16_t ddb_blocks;
  
                wm = &pipe_wm->planes[plane_id];
 +              ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][plane_id]);
 +              memset(&wm_params, 0, sizeof(struct skl_wm_params));
 +
 +              ret = skl_compute_plane_wm_params(dev_priv, cstate,
 +                                                intel_pstate, &wm_params);
 +              if (ret)
 +                      return ret;
  
                ret = skl_compute_wm_levels(dev_priv, ddb, cstate,
 -                                          intel_pstate, wm);
 +                                          intel_pstate, &wm_params, wm);
                if (ret)
                        return ret;
 -              skl_compute_transition_wm(cstate, &wm->trans_wm);
 +              skl_compute_transition_wm(cstate, &wm_params, &wm->wm[0],
 +                                        ddb_blocks, &wm->trans_wm);
        }
        pipe_wm->linetime = skl_compute_linetime_wm(cstate);
  
@@@ -4820,18 -4745,16 +4820,18 @@@ static inline bool skl_ddb_entries_over
        return a->start < b->end && b->start < a->end;
  }
  
 -bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry **entries,
 +bool skl_ddb_allocation_overlaps(struct drm_i915_private *dev_priv,
 +                               const struct skl_ddb_entry **entries,
                                 const struct skl_ddb_entry *ddb,
                                 int ignore)
  {
 -      int i;
 +      enum pipe pipe;
  
 -      for (i = 0; i < I915_MAX_PIPES; i++)
 -              if (i != ignore && entries[i] &&
 -                  skl_ddb_entries_overlap(ddb, entries[i]))
 +      for_each_pipe(dev_priv, pipe) {
 +              if (pipe != ignore && entries[pipe] &&
 +                  skl_ddb_entries_overlap(ddb, entries[pipe]))
                        return true;
 +      }
  
        return false;
  }
@@@ -5621,7 -5544,7 +5621,7 @@@ void vlv_wm_get_hw_state(struct drm_dev
        wm->level = VLV_WM_LEVEL_PM2;
  
        if (IS_CHERRYVIEW(dev_priv)) {
 -              mutex_lock(&dev_priv->rps.hw_lock);
 +              mutex_lock(&dev_priv->pcu_lock);
  
                val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
                if (val & DSP_MAXFIFO_PM5_ENABLE)
                                wm->level = VLV_WM_LEVEL_DDR_DVFS;
                }
  
 -              mutex_unlock(&dev_priv->rps.hw_lock);
 +              mutex_unlock(&dev_priv->pcu_lock);
        }
  
        for_each_intel_crtc(dev, crtc) {
@@@ -5825,36 -5748,6 +5825,36 @@@ void intel_update_watermarks(struct int
                dev_priv->display.update_wm(crtc);
  }
  
 +void intel_enable_ipc(struct drm_i915_private *dev_priv)
 +{
 +      u32 val;
 +
 +      /* Display WA #0477 WaDisableIPC: skl */
 +      if (IS_SKYLAKE(dev_priv)) {
 +              dev_priv->ipc_enabled = false;
 +              return;
 +      }
 +
 +      val = I915_READ(DISP_ARB_CTL2);
 +
 +      if (dev_priv->ipc_enabled)
 +              val |= DISP_IPC_ENABLE;
 +      else
 +              val &= ~DISP_IPC_ENABLE;
 +
 +      I915_WRITE(DISP_ARB_CTL2, val);
 +}
 +
 +void intel_init_ipc(struct drm_i915_private *dev_priv)
 +{
 +      dev_priv->ipc_enabled = false;
 +      if (!HAS_IPC(dev_priv))
 +              return;
 +
 +      dev_priv->ipc_enabled = true;
 +      intel_enable_ipc(dev_priv);
 +}
 +
  /*
   * Lock protecting IPS related data structures
   */
@@@ -5988,7 -5881,6 +5988,7 @@@ static void ironlake_disable_drps(struc
   */
  static u32 intel_rps_limits(struct drm_i915_private *dev_priv, u8 val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
        u32 limits;
  
        /* Only set the down limit when we've reached the lowest level to avoid
         * frequency, if the down threshold expires in that window we will not
         * receive a down interrupt. */
        if (INTEL_GEN(dev_priv) >= 9) {
 -              limits = (dev_priv->rps.max_freq_softlimit) << 23;
 -              if (val <= dev_priv->rps.min_freq_softlimit)
 -                      limits |= (dev_priv->rps.min_freq_softlimit) << 14;
 +              limits = (rps->max_freq_softlimit) << 23;
 +              if (val <= rps->min_freq_softlimit)
 +                      limits |= (rps->min_freq_softlimit) << 14;
        } else {
 -              limits = dev_priv->rps.max_freq_softlimit << 24;
 -              if (val <= dev_priv->rps.min_freq_softlimit)
 -                      limits |= dev_priv->rps.min_freq_softlimit << 16;
 +              limits = rps->max_freq_softlimit << 24;
 +              if (val <= rps->min_freq_softlimit)
 +                      limits |= rps->min_freq_softlimit << 16;
        }
  
        return limits;
  
  static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
        int new_power;
        u32 threshold_up = 0, threshold_down = 0; /* in % */
        u32 ei_up = 0, ei_down = 0;
  
 -      new_power = dev_priv->rps.power;
 -      switch (dev_priv->rps.power) {
 +      new_power = rps->power;
 +      switch (rps->power) {
        case LOW_POWER:
 -              if (val > dev_priv->rps.efficient_freq + 1 &&
 -                  val > dev_priv->rps.cur_freq)
 +              if (val > rps->efficient_freq + 1 &&
 +                  val > rps->cur_freq)
                        new_power = BETWEEN;
                break;
  
        case BETWEEN:
 -              if (val <= dev_priv->rps.efficient_freq &&
 -                  val < dev_priv->rps.cur_freq)
 +              if (val <= rps->efficient_freq &&
 +                  val < rps->cur_freq)
                        new_power = LOW_POWER;
 -              else if (val >= dev_priv->rps.rp0_freq &&
 -                       val > dev_priv->rps.cur_freq)
 +              else if (val >= rps->rp0_freq &&
 +                       val > rps->cur_freq)
                        new_power = HIGH_POWER;
                break;
  
        case HIGH_POWER:
 -              if (val < (dev_priv->rps.rp1_freq + dev_priv->rps.rp0_freq) >> 1 &&
 -                  val < dev_priv->rps.cur_freq)
 +              if (val < (rps->rp1_freq + rps->rp0_freq) >> 1 &&
 +                  val < rps->cur_freq)
                        new_power = BETWEEN;
                break;
        }
        /* Max/min bins are special */
 -      if (val <= dev_priv->rps.min_freq_softlimit)
 +      if (val <= rps->min_freq_softlimit)
                new_power = LOW_POWER;
 -      if (val >= dev_priv->rps.max_freq_softlimit)
 +      if (val >= rps->max_freq_softlimit)
                new_power = HIGH_POWER;
 -      if (new_power == dev_priv->rps.power)
 +      if (new_power == rps->power)
                return;
  
        /* Note the units here are not exactly 1us, but 1280ns. */
                   GEN6_RP_DOWN_IDLE_AVG);
  
  skip_hw_write:
 -      dev_priv->rps.power = new_power;
 -      dev_priv->rps.up_threshold = threshold_up;
 -      dev_priv->rps.down_threshold = threshold_down;
 -      dev_priv->rps.last_adj = 0;
 +      rps->power = new_power;
 +      rps->up_threshold = threshold_up;
 +      rps->down_threshold = threshold_down;
 +      rps->last_adj = 0;
  }
  
  static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
        u32 mask = 0;
  
        /* We use UP_EI_EXPIRED interupts for both up/down in manual mode */
 -      if (val > dev_priv->rps.min_freq_softlimit)
 +      if (val > rps->min_freq_softlimit)
                mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
 -      if (val < dev_priv->rps.max_freq_softlimit)
 +      if (val < rps->max_freq_softlimit)
                mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
  
        mask &= dev_priv->pm_rps_events;
   * update the GEN6_RP_INTERRUPT_LIMITS register accordingly. */
  static int gen6_set_rps(struct drm_i915_private *dev_priv, u8 val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
        /* min/max delay may still have been modified so be sure to
         * write the limits value.
         */
 -      if (val != dev_priv->rps.cur_freq) {
 +      if (val != rps->cur_freq) {
                gen6_set_rps_thresholds(dev_priv, val);
  
                if (INTEL_GEN(dev_priv) >= 9)
        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, intel_rps_limits(dev_priv, val));
        I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
  
 -      dev_priv->rps.cur_freq = val;
 +      rps->cur_freq = val;
        trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
  
        return 0;
@@@ -6178,7 -6066,7 +6178,7 @@@ static int valleyview_set_rps(struct dr
  
        I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
  
 -      if (val != dev_priv->rps.cur_freq) {
 +      if (val != dev_priv->gt_pm.rps.cur_freq) {
                err = vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
                if (err)
                        return err;
                gen6_set_rps_thresholds(dev_priv, val);
        }
  
 -      dev_priv->rps.cur_freq = val;
 +      dev_priv->gt_pm.rps.cur_freq = val;
        trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
  
        return 0;
  */
  static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
  {
 -      u32 val = dev_priv->rps.idle_freq;
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +      u32 val = rps->idle_freq;
        int err;
  
 -      if (dev_priv->rps.cur_freq <= val)
 +      if (rps->cur_freq <= val)
                return;
  
        /* The punit delays the write of the frequency and voltage until it
  
  void gen6_rps_busy(struct drm_i915_private *dev_priv)
  {
 -      mutex_lock(&dev_priv->rps.hw_lock);
 -      if (dev_priv->rps.enabled) {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
 +      mutex_lock(&dev_priv->pcu_lock);
 +      if (rps->enabled) {
                u8 freq;
  
                if (dev_priv->pm_rps_events & GEN6_PM_RP_UP_EI_EXPIRED)
                        gen6_rps_reset_ei(dev_priv);
                I915_WRITE(GEN6_PMINTRMSK,
 -                         gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
 +                         gen6_rps_pm_mask(dev_priv, rps->cur_freq));
  
                gen6_enable_rps_interrupts(dev_priv);
  
                /* Use the user's desired frequency as a guide, but for better
                 * performance, jump directly to RPe as our starting frequency.
                 */
 -              freq = max(dev_priv->rps.cur_freq,
 -                         dev_priv->rps.efficient_freq);
 +              freq = max(rps->cur_freq,
 +                         rps->efficient_freq);
  
                if (intel_set_rps(dev_priv,
                                  clamp(freq,
 -                                      dev_priv->rps.min_freq_softlimit,
 -                                      dev_priv->rps.max_freq_softlimit)))
 +                                      rps->min_freq_softlimit,
 +                                      rps->max_freq_softlimit)))
                        DRM_DEBUG_DRIVER("Failed to set idle frequency\n");
        }
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
  }
  
  void gen6_rps_idle(struct drm_i915_private *dev_priv)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
        /* Flush our bottom-half so that it does not race with us
         * setting the idle frequency and so that it is bounded by
         * our rpm wakeref. And then disable the interrupts to stop any
         */
        gen6_disable_rps_interrupts(dev_priv);
  
 -      mutex_lock(&dev_priv->rps.hw_lock);
 -      if (dev_priv->rps.enabled) {
 +      mutex_lock(&dev_priv->pcu_lock);
 +      if (rps->enabled) {
                if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                        vlv_set_rps_idle(dev_priv);
                else
 -                      gen6_set_rps(dev_priv, dev_priv->rps.idle_freq);
 -              dev_priv->rps.last_adj = 0;
 +                      gen6_set_rps(dev_priv, rps->idle_freq);
 +              rps->last_adj = 0;
                I915_WRITE(GEN6_PMINTRMSK,
                           gen6_sanitize_rps_pm_mask(dev_priv, ~0));
        }
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
  }
  
  void gen6_rps_boost(struct drm_i915_gem_request *rq,
 -                  struct intel_rps_client *rps)
 +                  struct intel_rps_client *rps_client)
  {
 -      struct drm_i915_private *i915 = rq->i915;
 +      struct intel_rps *rps = &rq->i915->gt_pm.rps;
 +      unsigned long flags;
        bool boost;
  
        /* This is intentionally racy! We peek at the state here, then
         * validate inside the RPS worker.
         */
 -      if (!i915->rps.enabled)
 +      if (!rps->enabled)
                return;
  
        boost = false;
 -      spin_lock_irq(&rq->lock);
 +      spin_lock_irqsave(&rq->lock, flags);
        if (!rq->waitboost && !i915_gem_request_completed(rq)) {
 -              atomic_inc(&i915->rps.num_waiters);
 +              atomic_inc(&rps->num_waiters);
                rq->waitboost = true;
                boost = true;
        }
 -      spin_unlock_irq(&rq->lock);
 +      spin_unlock_irqrestore(&rq->lock, flags);
        if (!boost)
                return;
  
 -      if (READ_ONCE(i915->rps.cur_freq) < i915->rps.boost_freq)
 -              schedule_work(&i915->rps.work);
 +      if (READ_ONCE(rps->cur_freq) < rps->boost_freq)
 +              schedule_work(&rps->work);
  
 -      atomic_inc(rps ? &rps->boosts : &i915->rps.boosts);
 +      atomic_inc(rps_client ? &rps_client->boosts : &rps->boosts);
  }
  
  int intel_set_rps(struct drm_i915_private *dev_priv, u8 val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
        int err;
  
 -      lockdep_assert_held(&dev_priv->rps.hw_lock);
 -      GEM_BUG_ON(val > dev_priv->rps.max_freq);
 -      GEM_BUG_ON(val < dev_priv->rps.min_freq);
 +      lockdep_assert_held(&dev_priv->pcu_lock);
 +      GEM_BUG_ON(val > rps->max_freq);
 +      GEM_BUG_ON(val < rps->min_freq);
  
 -      if (!dev_priv->rps.enabled) {
 -              dev_priv->rps.cur_freq = val;
 +      if (!rps->enabled) {
 +              rps->cur_freq = val;
                return 0;
        }
  
@@@ -6345,30 -6226,21 +6345,30 @@@ static void gen9_disable_rps(struct drm
        I915_WRITE(GEN6_RP_CONTROL, 0);
  }
  
 -static void gen6_disable_rps(struct drm_i915_private *dev_priv)
 +static void gen6_disable_rc6(struct drm_i915_private *dev_priv)
  {
        I915_WRITE(GEN6_RC_CONTROL, 0);
 +}
 +
 +static void gen6_disable_rps(struct drm_i915_private *dev_priv)
 +{
        I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
        I915_WRITE(GEN6_RP_CONTROL, 0);
  }
  
 -static void cherryview_disable_rps(struct drm_i915_private *dev_priv)
 +static void cherryview_disable_rc6(struct drm_i915_private *dev_priv)
  {
        I915_WRITE(GEN6_RC_CONTROL, 0);
  }
  
 -static void valleyview_disable_rps(struct drm_i915_private *dev_priv)
 +static void cherryview_disable_rps(struct drm_i915_private *dev_priv)
 +{
 +      I915_WRITE(GEN6_RP_CONTROL, 0);
 +}
 +
 +static void valleyview_disable_rc6(struct drm_i915_private *dev_priv)
  {
 -      /* we're doing forcewake before Disabling RC6,
 +      /* We're doing forcewake before Disabling RC6,
         * This what the BIOS expects when going into suspend */
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
  
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
  }
  
 +static void valleyview_disable_rps(struct drm_i915_private *dev_priv)
 +{
 +      I915_WRITE(GEN6_RP_CONTROL, 0);
 +}
 +
  static void intel_print_rc6_info(struct drm_i915_private *dev_priv, u32 mode)
  {
        if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
@@@ -6504,26 -6371,24 +6504,26 @@@ int sanitize_rc6_option(struct drm_i915
  
  static void gen6_init_rps_frequencies(struct drm_i915_private *dev_priv)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
        /* All of these values are in units of 50MHz */
  
        /* static values from HW: RP0 > RP1 > RPn (min_freq) */
        if (IS_GEN9_LP(dev_priv)) {
                u32 rp_state_cap = I915_READ(BXT_RP_STATE_CAP);
 -              dev_priv->rps.rp0_freq = (rp_state_cap >> 16) & 0xff;
 -              dev_priv->rps.rp1_freq = (rp_state_cap >>  8) & 0xff;
 -              dev_priv->rps.min_freq = (rp_state_cap >>  0) & 0xff;
 +              rps->rp0_freq = (rp_state_cap >> 16) & 0xff;
 +              rps->rp1_freq = (rp_state_cap >>  8) & 0xff;
 +              rps->min_freq = (rp_state_cap >>  0) & 0xff;
        } else {
                u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
 -              dev_priv->rps.rp0_freq = (rp_state_cap >>  0) & 0xff;
 -              dev_priv->rps.rp1_freq = (rp_state_cap >>  8) & 0xff;
 -              dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff;
 +              rps->rp0_freq = (rp_state_cap >>  0) & 0xff;
 +              rps->rp1_freq = (rp_state_cap >>  8) & 0xff;
 +              rps->min_freq = (rp_state_cap >> 16) & 0xff;
        }
        /* hw_max = RP0 until we check for overclocking */
 -      dev_priv->rps.max_freq = dev_priv->rps.rp0_freq;
 +      rps->max_freq = rps->rp0_freq;
  
 -      dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq;
 +      rps->efficient_freq = rps->rp1_freq;
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv) ||
            IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) {
                u32 ddcc_status = 0;
                if (sandybridge_pcode_read(dev_priv,
                                           HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
                                           &ddcc_status) == 0)
 -                      dev_priv->rps.efficient_freq =
 +                      rps->efficient_freq =
                                clamp_t(u8,
                                        ((ddcc_status >> 8) & 0xff),
 -                                      dev_priv->rps.min_freq,
 -                                      dev_priv->rps.max_freq);
 +                                      rps->min_freq,
 +                                      rps->max_freq);
        }
  
        if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) {
                /* Store the frequency values in 16.66 MHZ units, which is
                 * the natural hardware unit for SKL
                 */
 -              dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER;
 -              dev_priv->rps.rp1_freq *= GEN9_FREQ_SCALER;
 -              dev_priv->rps.min_freq *= GEN9_FREQ_SCALER;
 -              dev_priv->rps.max_freq *= GEN9_FREQ_SCALER;
 -              dev_priv->rps.efficient_freq *= GEN9_FREQ_SCALER;
 +              rps->rp0_freq *= GEN9_FREQ_SCALER;
 +              rps->rp1_freq *= GEN9_FREQ_SCALER;
 +              rps->min_freq *= GEN9_FREQ_SCALER;
 +              rps->max_freq *= GEN9_FREQ_SCALER;
 +              rps->efficient_freq *= GEN9_FREQ_SCALER;
        }
  }
  
  static void reset_rps(struct drm_i915_private *dev_priv,
                      int (*set)(struct drm_i915_private *, u8))
  {
 -      u8 freq = dev_priv->rps.cur_freq;
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +      u8 freq = rps->cur_freq;
  
        /* force a reset */
 -      dev_priv->rps.power = -1;
 -      dev_priv->rps.cur_freq = -1;
 +      rps->power = -1;
 +      rps->cur_freq = -1;
  
        if (set(dev_priv, freq))
                DRM_ERROR("Failed to reset RPS to initial values\n");
@@@ -6571,7 -6435,7 +6571,7 @@@ static void gen9_enable_rps(struct drm_
  
        /* Program defaults and thresholds for RPS*/
        I915_WRITE(GEN6_RC_VIDEO_FREQ,
 -              GEN9_FREQUENCY(dev_priv->rps.rp1_freq));
 +              GEN9_FREQUENCY(dev_priv->gt_pm.rps.rp1_freq));
  
        /* 1 second timeout*/
        I915_WRITE(GEN6_RP_DOWN_TIMEOUT,
@@@ -6625,7 -6489,7 +6625,7 @@@ static void gen9_enable_rc6(struct drm_
        I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 25);
  
        /* 3a: Enable RC6 */
 -      if (intel_enable_rc6() & INTEL_RC6_ENABLE)
 +      if (intel_rc6_enabled() & INTEL_RC6_ENABLE)
                rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
        DRM_INFO("RC6 %s\n", onoff(rc6_mask & GEN6_RC_CTL_RC6_ENABLE));
        I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
  }
  
 -static void gen8_enable_rps(struct drm_i915_private *dev_priv)
 +static void gen8_enable_rc6(struct drm_i915_private *dev_priv)
  {
        struct intel_engine_cs *engine;
        enum intel_engine_id id;
        /* 1a: Software RC state - RC0 */
        I915_WRITE(GEN6_RC_STATE, 0);
  
 -      /* 1c & 1d: Get forcewake during program sequence. Although the driver
 +      /* 1b: Get forcewake during program sequence. Although the driver
         * hasn't enabled a state yet where we need forcewake, BIOS may have.*/
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
  
        for_each_engine(engine, dev_priv, id)
                I915_WRITE(RING_MAX_IDLE(engine->mmio_base), 10);
        I915_WRITE(GEN6_RC_SLEEP, 0);
 -      if (IS_BROADWELL(dev_priv))
 -              I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us/1.28 for TO */
 -      else
 -              I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
 +      I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us/1.28 for TO */
  
        /* 3: Enable RC6 */
 -      if (intel_enable_rc6() & INTEL_RC6_ENABLE)
 +      if (intel_rc6_enabled() & INTEL_RC6_ENABLE)
                rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
        intel_print_rc6_info(dev_priv, rc6_mask);
 -      if (IS_BROADWELL(dev_priv))
 -              I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
 -                              GEN7_RC_CTL_TO_MODE |
 -                              rc6_mask);
 -      else
 -              I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
 -                              GEN6_RC_CTL_EI_MODE(1) |
 -                              rc6_mask);
  
 -      /* 4 Program defaults and thresholds for RPS*/
 +      I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
 +                      GEN7_RC_CTL_TO_MODE |
 +                      rc6_mask);
 +
 +      intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 +}
 +
 +static void gen8_enable_rps(struct drm_i915_private *dev_priv)
 +{
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
 +      intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 +
 +      /* 1 Program defaults and thresholds for RPS*/
        I915_WRITE(GEN6_RPNSWREQ,
 -                 HSW_FREQUENCY(dev_priv->rps.rp1_freq));
 +                 HSW_FREQUENCY(rps->rp1_freq));
        I915_WRITE(GEN6_RC_VIDEO_FREQ,
 -                 HSW_FREQUENCY(dev_priv->rps.rp1_freq));
 +                 HSW_FREQUENCY(rps->rp1_freq));
        /* NB: Docs say 1s, and 1000000 - which aren't equivalent */
        I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 100000000 / 128); /* 1 second timeout */
  
        /* Docs recommend 900MHz, and 300 MHz respectively */
        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
 -                 dev_priv->rps.max_freq_softlimit << 24 |
 -                 dev_priv->rps.min_freq_softlimit << 16);
 +                 rps->max_freq_softlimit << 24 |
 +                 rps->min_freq_softlimit << 16);
  
        I915_WRITE(GEN6_RP_UP_THRESHOLD, 7600000 / 128); /* 76ms busyness per EI, 90% */
        I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 31300000 / 128); /* 313ms busyness per EI, 70%*/
  
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
  
 -      /* 5: Enable RPS */
 +      /* 2: Enable RPS */
        I915_WRITE(GEN6_RP_CONTROL,
                   GEN6_RP_MEDIA_TURBO |
                   GEN6_RP_MEDIA_HW_NORMAL_MODE |
                   GEN6_RP_UP_BUSY_AVG |
                   GEN6_RP_DOWN_IDLE_AVG);
  
 -      /* 6: Ring frequency + overclocking (our driver does this later */
 -
        reset_rps(dev_priv, gen6_set_rps);
  
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
  }
  
 -static void gen6_enable_rps(struct drm_i915_private *dev_priv)
 +static void gen6_enable_rc6(struct drm_i915_private *dev_priv)
  {
        struct intel_engine_cs *engine;
        enum intel_engine_id id;
        int rc6_mode;
        int ret;
  
 -      WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 -
 -      /* Here begins a magic sequence of register writes to enable
 -       * auto-downclocking.
 -       *
 -       * Perhaps there might be some value in exposing these to
 -       * userspace...
 -       */
        I915_WRITE(GEN6_RC_STATE, 0);
  
        /* Clear the DBG now so we don't confuse earlier errors */
        I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
  
        /* Check if we are enabling RC6 */
 -      rc6_mode = intel_enable_rc6();
 +      rc6_mode = intel_rc6_enabled();
        if (rc6_mode & INTEL_RC6_ENABLE)
                rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
  
                   GEN6_RC_CTL_EI_MODE(1) |
                   GEN6_RC_CTL_HW_ENABLE);
  
 -      /* Power down if completely idle for over 50ms */
 -      I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 50000);
 -      I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 -
 -      reset_rps(dev_priv, gen6_set_rps);
 -
        rc6vids = 0;
        ret = sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
        if (IS_GEN6(dev_priv) && ret) {
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
  }
  
 +static void gen6_enable_rps(struct drm_i915_private *dev_priv)
 +{
 +      /* Here begins a magic sequence of register writes to enable
 +       * auto-downclocking.
 +       *
 +       * Perhaps there might be some value in exposing these to
 +       * userspace...
 +       */
 +      intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 +
 +      /* Power down if completely idle for over 50ms */
 +      I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 50000);
 +      I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 +
 +      reset_rps(dev_priv, gen6_set_rps);
 +
 +      intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 +}
 +
  static void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
        int min_freq = 15;
        unsigned int gpu_freq;
        unsigned int max_ia_freq, min_ring_freq;
        int scaling_factor = 180;
        struct cpufreq_policy *policy;
  
 -      WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 +      WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock));
  
        policy = cpufreq_cpu_get(0);
        if (policy) {
  
        if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv)) {
                /* Convert GT frequency to 50 HZ units */
 -              min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER;
 -              max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER;
 +              min_gpu_freq = rps->min_freq / GEN9_FREQ_SCALER;
 +              max_gpu_freq = rps->max_freq / GEN9_FREQ_SCALER;
        } else {
 -              min_gpu_freq = dev_priv->rps.min_freq;
 -              max_gpu_freq = dev_priv->rps.max_freq;
 +              min_gpu_freq = rps->min_freq;
 +              max_gpu_freq = rps->max_freq;
        }
  
        /*
@@@ -7108,18 -6966,17 +7108,18 @@@ static void valleyview_cleanup_pctx(str
  
  static void vlv_init_gpll_ref_freq(struct drm_i915_private *dev_priv)
  {
 -      dev_priv->rps.gpll_ref_freq =
 +      dev_priv->gt_pm.rps.gpll_ref_freq =
                vlv_get_cck_clock(dev_priv, "GPLL ref",
                                  CCK_GPLL_CLOCK_CONTROL,
                                  dev_priv->czclk_freq);
  
        DRM_DEBUG_DRIVER("GPLL reference freq: %d kHz\n",
 -                       dev_priv->rps.gpll_ref_freq);
 +                       dev_priv->gt_pm.rps.gpll_ref_freq);
  }
  
  static void valleyview_init_gt_powersave(struct drm_i915_private *dev_priv)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
        u32 val;
  
        valleyview_setup_pctx(dev_priv);
        }
        DRM_DEBUG_DRIVER("DDR speed: %d MHz\n", dev_priv->mem_freq);
  
 -      dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
 -      dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
 +      rps->max_freq = valleyview_rps_max_freq(dev_priv);
 +      rps->rp0_freq = rps->max_freq;
        DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.max_freq),
 -                       dev_priv->rps.max_freq);
 +                       intel_gpu_freq(dev_priv, rps->max_freq),
 +                       rps->max_freq);
  
 -      dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv);
 +      rps->efficient_freq = valleyview_rps_rpe_freq(dev_priv);
        DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
 -                       dev_priv->rps.efficient_freq);
 +                       intel_gpu_freq(dev_priv, rps->efficient_freq),
 +                       rps->efficient_freq);
  
 -      dev_priv->rps.rp1_freq = valleyview_rps_guar_freq(dev_priv);
 +      rps->rp1_freq = valleyview_rps_guar_freq(dev_priv);
        DRM_DEBUG_DRIVER("RP1(Guar Freq) GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
 -                       dev_priv->rps.rp1_freq);
 +                       intel_gpu_freq(dev_priv, rps->rp1_freq),
 +                       rps->rp1_freq);
  
 -      dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv);
 +      rps->min_freq = valleyview_rps_min_freq(dev_priv);
        DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
 -                       dev_priv->rps.min_freq);
 +                       intel_gpu_freq(dev_priv, rps->min_freq),
 +                       rps->min_freq);
  }
  
  static void cherryview_init_gt_powersave(struct drm_i915_private *dev_priv)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
        u32 val;
  
        cherryview_setup_pctx(dev_priv);
        }
        DRM_DEBUG_DRIVER("DDR speed: %d MHz\n", dev_priv->mem_freq);
  
 -      dev_priv->rps.max_freq = cherryview_rps_max_freq(dev_priv);
 -      dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
 +      rps->max_freq = cherryview_rps_max_freq(dev_priv);
 +      rps->rp0_freq = rps->max_freq;
        DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.max_freq),
 -                       dev_priv->rps.max_freq);
 +                       intel_gpu_freq(dev_priv, rps->max_freq),
 +                       rps->max_freq);
  
 -      dev_priv->rps.efficient_freq = cherryview_rps_rpe_freq(dev_priv);
 +      rps->efficient_freq = cherryview_rps_rpe_freq(dev_priv);
        DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
 -                       dev_priv->rps.efficient_freq);
 +                       intel_gpu_freq(dev_priv, rps->efficient_freq),
 +                       rps->efficient_freq);
  
 -      dev_priv->rps.rp1_freq = cherryview_rps_guar_freq(dev_priv);
 +      rps->rp1_freq = cherryview_rps_guar_freq(dev_priv);
        DRM_DEBUG_DRIVER("RP1(Guar) GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
 -                       dev_priv->rps.rp1_freq);
 +                       intel_gpu_freq(dev_priv, rps->rp1_freq),
 +                       rps->rp1_freq);
  
 -      dev_priv->rps.min_freq = cherryview_rps_min_freq(dev_priv);
 +      rps->min_freq = cherryview_rps_min_freq(dev_priv);
        DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
 -                       intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
 -                       dev_priv->rps.min_freq);
 +                       intel_gpu_freq(dev_priv, rps->min_freq),
 +                       rps->min_freq);
  
 -      WARN_ONCE((dev_priv->rps.max_freq |
 -                 dev_priv->rps.efficient_freq |
 -                 dev_priv->rps.rp1_freq |
 -                 dev_priv->rps.min_freq) & 1,
 +      WARN_ONCE((rps->max_freq | rps->efficient_freq | rps->rp1_freq |
 +                 rps->min_freq) & 1,
                  "Odd GPU freq values\n");
  }
  
@@@ -7217,11 -7075,13 +7217,11 @@@ static void valleyview_cleanup_gt_power
        valleyview_cleanup_pctx(dev_priv);
  }
  
 -static void cherryview_enable_rps(struct drm_i915_private *dev_priv)
 +static void cherryview_enable_rc6(struct drm_i915_private *dev_priv)
  {
        struct intel_engine_cs *engine;
        enum intel_engine_id id;
 -      u32 gtfifodbg, val, rc6_mode = 0, pcbr;
 -
 -      WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 +      u32 gtfifodbg, rc6_mode = 0, pcbr;
  
        gtfifodbg = I915_READ(GTFIFODBG) & ~(GT_FIFO_SBDEDICATE_FREE_ENTRY_CHV |
                                             GT_FIFO_FREE_ENTRIES_CHV);
        /* TO threshold set to 500 us ( 0x186 * 1.28 us) */
        I915_WRITE(GEN6_RC6_THRESHOLD, 0x186);
  
 -      /* allows RC6 residency counter to work */
 +      /* Allows RC6 residency counter to work */
        I915_WRITE(VLV_COUNTER_CONTROL,
                   _MASKED_BIT_ENABLE(VLV_COUNT_RANGE_HIGH |
                                      VLV_MEDIA_RC6_COUNT_EN |
        pcbr = I915_READ(VLV_PCBR);
  
        /* 3: Enable RC6 */
 -      if ((intel_enable_rc6() & INTEL_RC6_ENABLE) &&
 +      if ((intel_rc6_enabled() & INTEL_RC6_ENABLE) &&
            (pcbr >> VLV_PCBR_ADDR_SHIFT))
                rc6_mode = GEN7_RC_CTL_TO_MODE;
  
        I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
  
 -      /* 4 Program defaults and thresholds for RPS*/
 +      intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 +}
 +
 +static void cherryview_enable_rps(struct drm_i915_private *dev_priv)
 +{
 +      u32 val;
 +
 +      intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 +
 +      /* 1: Program defaults and thresholds for RPS*/
        I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
        I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
        I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
  
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
  
 -      /* 5: Enable RPS */
 +      /* 2: Enable RPS */
        I915_WRITE(GEN6_RP_CONTROL,
                   GEN6_RP_MEDIA_HW_NORMAL_MODE |
                   GEN6_RP_MEDIA_IS_GFX |
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
  }
  
 -static void valleyview_enable_rps(struct drm_i915_private *dev_priv)
 +static void valleyview_enable_rc6(struct drm_i915_private *dev_priv)
  {
        struct intel_engine_cs *engine;
        enum intel_engine_id id;
 -      u32 gtfifodbg, val, rc6_mode = 0;
 -
 -      WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 +      u32 gtfifodbg, rc6_mode = 0;
  
        valleyview_check_pctx(dev_priv);
  
                I915_WRITE(GTFIFODBG, gtfifodbg);
        }
  
 -      /* If VLV, Forcewake all wells, else re-direct to regular path */
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
  
        /*  Disable RC states. */
        I915_WRITE(GEN6_RC_CONTROL, 0);
  
 -      I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
 -      I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
 -      I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
 -      I915_WRITE(GEN6_RP_UP_EI, 66000);
 -      I915_WRITE(GEN6_RP_DOWN_EI, 350000);
 -
 -      I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 -
 -      I915_WRITE(GEN6_RP_CONTROL,
 -                 GEN6_RP_MEDIA_TURBO |
 -                 GEN6_RP_MEDIA_HW_NORMAL_MODE |
 -                 GEN6_RP_MEDIA_IS_GFX |
 -                 GEN6_RP_ENABLE |
 -                 GEN6_RP_UP_BUSY_AVG |
 -                 GEN6_RP_DOWN_IDLE_CONT);
 -
        I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 0x00280000);
        I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
        I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
  
        I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
  
 -      /* allows RC6 residency counter to work */
 +      /* Allows RC6 residency counter to work */
        I915_WRITE(VLV_COUNTER_CONTROL,
                   _MASKED_BIT_ENABLE(VLV_COUNT_RANGE_HIGH |
                                      VLV_MEDIA_RC0_COUNT_EN |
                                      VLV_MEDIA_RC6_COUNT_EN |
                                      VLV_RENDER_RC6_COUNT_EN));
  
 -      if (intel_enable_rc6() & INTEL_RC6_ENABLE)
 +      if (intel_rc6_enabled() & INTEL_RC6_ENABLE)
                rc6_mode = GEN7_RC_CTL_TO_MODE | VLV_RC_CTL_CTX_RST_PARALLEL;
  
        intel_print_rc6_info(dev_priv, rc6_mode);
  
        I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
  
 +      intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 +}
 +
 +static void valleyview_enable_rps(struct drm_i915_private *dev_priv)
 +{
 +      u32 val;
 +
 +      intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 +
 +      I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
 +      I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
 +      I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
 +      I915_WRITE(GEN6_RP_UP_EI, 66000);
 +      I915_WRITE(GEN6_RP_DOWN_EI, 350000);
 +
 +      I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 +
 +      I915_WRITE(GEN6_RP_CONTROL,
 +                 GEN6_RP_MEDIA_TURBO |
 +                 GEN6_RP_MEDIA_HW_NORMAL_MODE |
 +                 GEN6_RP_MEDIA_IS_GFX |
 +                 GEN6_RP_ENABLE |
 +                 GEN6_RP_UP_BUSY_AVG |
 +                 GEN6_RP_DOWN_IDLE_CONT);
 +
        /* Setting Fixed Bias */
        val = VLV_OVERRIDE_EN |
                  VLV_SOC_TDP_EN |
@@@ -7589,7 -7434,7 +7589,7 @@@ static unsigned long __i915_gfx_val(str
  
        lockdep_assert_held(&mchdev_lock);
  
 -      pxvid = I915_READ(PXVFREQ(dev_priv->rps.cur_freq));
 +      pxvid = I915_READ(PXVFREQ(dev_priv->gt_pm.rps.cur_freq));
        pxvid = (pxvid >> 24) & 0x7f;
        ext_v = pvid_to_extvid(dev_priv, pxvid);
  
@@@ -7876,19 -7721,17 +7876,19 @@@ static void intel_init_emon(struct drm_
  
  void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
        /*
         * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
         * requirement.
         */
 -      if (!i915.enable_rc6) {
 +      if (!i915_modparams.enable_rc6) {
                DRM_INFO("RC6 disabled, disabling runtime PM support\n");
                intel_runtime_pm_get(dev_priv);
        }
  
        mutex_lock(&dev_priv->drm.struct_mutex);
 -      mutex_lock(&dev_priv->rps.hw_lock);
 +      mutex_lock(&dev_priv->pcu_lock);
  
        /* Initialize RPS limits (for userspace) */
        if (IS_CHERRYVIEW(dev_priv))
                gen6_init_rps_frequencies(dev_priv);
  
        /* Derive initial user preferences/limits from the hardware limits */
 -      dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
 -      dev_priv->rps.cur_freq = dev_priv->rps.idle_freq;
 +      rps->idle_freq = rps->min_freq;
 +      rps->cur_freq = rps->idle_freq;
  
 -      dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
 -      dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
 +      rps->max_freq_softlimit = rps->max_freq;
 +      rps->min_freq_softlimit = rps->min_freq;
  
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
 -              dev_priv->rps.min_freq_softlimit =
 +              rps->min_freq_softlimit =
                        max_t(int,
 -                            dev_priv->rps.efficient_freq,
 +                            rps->efficient_freq,
                              intel_freq_opcode(dev_priv, 450));
  
        /* After setting max-softlimit, find the overclock max freq */
                sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &params);
                if (params & BIT(31)) { /* OC supported */
                        DRM_DEBUG_DRIVER("Overclocking supported, max: %dMHz, overclock: %dMHz\n",
 -                                       (dev_priv->rps.max_freq & 0xff) * 50,
 +                                       (rps->max_freq & 0xff) * 50,
                                         (params & 0xff) * 50);
 -                      dev_priv->rps.max_freq = params & 0xff;
 +                      rps->max_freq = params & 0xff;
                }
        }
  
        /* Finally allow us to boost to max by default */
 -      dev_priv->rps.boost_freq = dev_priv->rps.max_freq;
 +      rps->boost_freq = rps->max_freq;
  
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
        mutex_unlock(&dev_priv->drm.struct_mutex);
  
        intel_autoenable_gt_powersave(dev_priv);
@@@ -7939,7 -7782,7 +7939,7 @@@ void intel_cleanup_gt_powersave(struct 
        if (IS_VALLEYVIEW(dev_priv))
                valleyview_cleanup_gt_powersave(dev_priv);
  
 -      if (!i915.enable_rc6)
 +      if (!i915_modparams.enable_rc6)
                intel_runtime_pm_put(dev_priv);
  }
  
@@@ -7956,7 -7799,7 +7956,7 @@@ void intel_suspend_gt_powersave(struct 
        if (INTEL_GEN(dev_priv) < 6)
                return;
  
 -      if (cancel_delayed_work_sync(&dev_priv->rps.autoenable_work))
 +      if (cancel_delayed_work_sync(&dev_priv->gt_pm.autoenable_work))
                intel_runtime_pm_put(dev_priv);
  
        /* gen6_rps_idle() will be called later to disable interrupts */
  
  void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv)
  {
 -      dev_priv->rps.enabled = true; /* force disabling */
 +      dev_priv->gt_pm.rps.enabled = true; /* force RPS disabling */
 +      dev_priv->gt_pm.rc6.enabled = true; /* force RC6 disabling */
        intel_disable_gt_powersave(dev_priv);
  
        gen6_reset_rps_interrupts(dev_priv);
  }
  
 -void intel_disable_gt_powersave(struct drm_i915_private *dev_priv)
 +static inline void intel_disable_llc_pstate(struct drm_i915_private *i915)
  {
 -      if (!READ_ONCE(dev_priv->rps.enabled))
 +      lockdep_assert_held(&i915->pcu_lock);
 +
 +      if (!i915->gt_pm.llc_pstate.enabled)
                return;
  
 -      mutex_lock(&dev_priv->rps.hw_lock);
 +      /* Currently there is no HW configuration to be done to disable. */
  
 -      if (INTEL_GEN(dev_priv) >= 9) {
 +      i915->gt_pm.llc_pstate.enabled = false;
 +}
 +
 +static void intel_disable_rc6(struct drm_i915_private *dev_priv)
 +{
 +      lockdep_assert_held(&dev_priv->pcu_lock);
 +
 +      if (!dev_priv->gt_pm.rc6.enabled)
 +              return;
 +
 +      if (INTEL_GEN(dev_priv) >= 9)
                gen9_disable_rc6(dev_priv);
 +      else if (IS_CHERRYVIEW(dev_priv))
 +              cherryview_disable_rc6(dev_priv);
 +      else if (IS_VALLEYVIEW(dev_priv))
 +              valleyview_disable_rc6(dev_priv);
 +      else if (INTEL_GEN(dev_priv) >= 6)
 +              gen6_disable_rc6(dev_priv);
 +
 +      dev_priv->gt_pm.rc6.enabled = false;
 +}
 +
 +static void intel_disable_rps(struct drm_i915_private *dev_priv)
 +{
 +      lockdep_assert_held(&dev_priv->pcu_lock);
 +
 +      if (!dev_priv->gt_pm.rps.enabled)
 +              return;
 +
 +      if (INTEL_GEN(dev_priv) >= 9)
                gen9_disable_rps(dev_priv);
 -      } else if (IS_CHERRYVIEW(dev_priv)) {
 +      else if (IS_CHERRYVIEW(dev_priv))
                cherryview_disable_rps(dev_priv);
 -      } else if (IS_VALLEYVIEW(dev_priv)) {
 +      else if (IS_VALLEYVIEW(dev_priv))
                valleyview_disable_rps(dev_priv);
 -      } else if (INTEL_GEN(dev_priv) >= 6) {
 +      else if (INTEL_GEN(dev_priv) >= 6)
                gen6_disable_rps(dev_priv);
 -      }  else if (IS_IRONLAKE_M(dev_priv)) {
 +      else if (IS_IRONLAKE_M(dev_priv))
                ironlake_disable_drps(dev_priv);
 -      }
  
 -      dev_priv->rps.enabled = false;
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      dev_priv->gt_pm.rps.enabled = false;
  }
  
 -void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
 +void intel_disable_gt_powersave(struct drm_i915_private *dev_priv)
  {
 -      /* We shouldn't be disabling as we submit, so this should be less
 -       * racy than it appears!
 -       */
 -      if (READ_ONCE(dev_priv->rps.enabled))
 +      mutex_lock(&dev_priv->pcu_lock);
 +
 +      intel_disable_rc6(dev_priv);
 +      intel_disable_rps(dev_priv);
 +      if (HAS_LLC(dev_priv))
 +              intel_disable_llc_pstate(dev_priv);
 +
 +      mutex_unlock(&dev_priv->pcu_lock);
 +}
 +
 +static inline void intel_enable_llc_pstate(struct drm_i915_private *i915)
 +{
 +      lockdep_assert_held(&i915->pcu_lock);
 +
 +      if (i915->gt_pm.llc_pstate.enabled)
                return;
  
 -      /* Powersaving is controlled by the host when inside a VM */
 -      if (intel_vgpu_active(dev_priv))
 +      gen6_update_ring_freq(i915);
 +
 +      i915->gt_pm.llc_pstate.enabled = true;
 +}
 +
 +static void intel_enable_rc6(struct drm_i915_private *dev_priv)
 +{
 +      lockdep_assert_held(&dev_priv->pcu_lock);
 +
 +      if (dev_priv->gt_pm.rc6.enabled)
                return;
  
 -      mutex_lock(&dev_priv->rps.hw_lock);
 +      if (IS_CHERRYVIEW(dev_priv))
 +              cherryview_enable_rc6(dev_priv);
 +      else if (IS_VALLEYVIEW(dev_priv))
 +              valleyview_enable_rc6(dev_priv);
 +      else if (INTEL_GEN(dev_priv) >= 9)
 +              gen9_enable_rc6(dev_priv);
 +      else if (IS_BROADWELL(dev_priv))
 +              gen8_enable_rc6(dev_priv);
 +      else if (INTEL_GEN(dev_priv) >= 6)
 +              gen6_enable_rc6(dev_priv);
 +
 +      dev_priv->gt_pm.rc6.enabled = true;
 +}
 +
 +static void intel_enable_rps(struct drm_i915_private *dev_priv)
 +{
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
 +      lockdep_assert_held(&dev_priv->pcu_lock);
 +
 +      if (rps->enabled)
 +              return;
  
        if (IS_CHERRYVIEW(dev_priv)) {
                cherryview_enable_rps(dev_priv);
        } else if (IS_VALLEYVIEW(dev_priv)) {
                valleyview_enable_rps(dev_priv);
        } else if (INTEL_GEN(dev_priv) >= 9) {
 -              gen9_enable_rc6(dev_priv);
                gen9_enable_rps(dev_priv);
 -              if (IS_GEN9_BC(dev_priv) || IS_CANNONLAKE(dev_priv))
 -                      gen6_update_ring_freq(dev_priv);
        } else if (IS_BROADWELL(dev_priv)) {
                gen8_enable_rps(dev_priv);
 -              gen6_update_ring_freq(dev_priv);
        } else if (INTEL_GEN(dev_priv) >= 6) {
                gen6_enable_rps(dev_priv);
 -              gen6_update_ring_freq(dev_priv);
        } else if (IS_IRONLAKE_M(dev_priv)) {
                ironlake_enable_drps(dev_priv);
                intel_init_emon(dev_priv);
        }
  
 -      WARN_ON(dev_priv->rps.max_freq < dev_priv->rps.min_freq);
 -      WARN_ON(dev_priv->rps.idle_freq > dev_priv->rps.max_freq);
 +      WARN_ON(rps->max_freq < rps->min_freq);
 +      WARN_ON(rps->idle_freq > rps->max_freq);
 +
 +      WARN_ON(rps->efficient_freq < rps->min_freq);
 +      WARN_ON(rps->efficient_freq > rps->max_freq);
  
 -      WARN_ON(dev_priv->rps.efficient_freq < dev_priv->rps.min_freq);
 -      WARN_ON(dev_priv->rps.efficient_freq > dev_priv->rps.max_freq);
 +      rps->enabled = true;
 +}
 +
 +void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
 +{
 +      /* Powersaving is controlled by the host when inside a VM */
 +      if (intel_vgpu_active(dev_priv))
 +              return;
 +
 +      mutex_lock(&dev_priv->pcu_lock);
 +
 +      intel_enable_rc6(dev_priv);
 +      intel_enable_rps(dev_priv);
 +      if (HAS_LLC(dev_priv))
 +              intel_enable_llc_pstate(dev_priv);
  
 -      dev_priv->rps.enabled = true;
 -      mutex_unlock(&dev_priv->rps.hw_lock);
 +      mutex_unlock(&dev_priv->pcu_lock);
  }
  
  static void __intel_autoenable_gt_powersave(struct work_struct *work)
  {
        struct drm_i915_private *dev_priv =
 -              container_of(work, typeof(*dev_priv), rps.autoenable_work.work);
 +              container_of(work,
 +                           typeof(*dev_priv),
 +                           gt_pm.autoenable_work.work);
        struct intel_engine_cs *rcs;
        struct drm_i915_gem_request *req;
  
 -      if (READ_ONCE(dev_priv->rps.enabled))
 -              goto out;
 -
        rcs = dev_priv->engine[RCS];
        if (rcs->last_retired_context)
                goto out;
        if (IS_ERR(req))
                goto unlock;
  
 -      if (!i915.enable_execlists && i915_switch_context(req) == 0)
 +      if (!i915_modparams.enable_execlists && i915_switch_context(req) == 0)
                rcs->init_context(req);
  
        /* Mark the device busy, calling intel_enable_gt_powersave() */
@@@ -8153,6 -7918,9 +8153,6 @@@ out
  
  void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv)
  {
 -      if (READ_ONCE(dev_priv->rps.enabled))
 -              return;
 -
        if (IS_IRONLAKE_M(dev_priv)) {
                ironlake_enable_drps(dev_priv);
                intel_init_emon(dev_priv);
                 * runtime resume it's necessary).
                 */
                if (queue_delayed_work(dev_priv->wq,
 -                                     &dev_priv->rps.autoenable_work,
 +                                     &dev_priv->gt_pm.autoenable_work,
                                       round_jiffies_up_relative(HZ)))
                        intel_runtime_pm_get_noresume(dev_priv);
        }
@@@ -8212,7 -7980,7 +8212,7 @@@ static void ilk_init_lp_watermarks(stru
         */
  }
  
 -static void ironlake_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void ilk_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
  
@@@ -8477,14 -8245,17 +8477,17 @@@ static void gen8_set_l3sqc_credits(stru
                                   int high_prio_credits)
  {
        u32 misccpctl;
+       u32 val;
  
        /* WaTempDisableDOPClkGating:bdw */
        misccpctl = I915_READ(GEN7_MISCCPCTL);
        I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
  
-       I915_WRITE(GEN8_L3SQCREG1,
-                  L3_GENERAL_PRIO_CREDITS(general_prio_credits) |
-                  L3_HIGH_PRIO_CREDITS(high_prio_credits));
+       val = I915_READ(GEN8_L3SQCREG1);
+       val &= ~L3_PRIO_CREDITS_MASK;
+       val |= L3_GENERAL_PRIO_CREDITS(general_prio_credits);
+       val |= L3_HIGH_PRIO_CREDITS(high_prio_credits);
+       I915_WRITE(GEN8_L3SQCREG1, val);
  
        /*
         * Wait at least 100 clocks before re-enabling clock gating.
        I915_WRITE(GEN7_MISCCPCTL, misccpctl);
  }
  
 -static void kabylake_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void cnp_init_clock_gating(struct drm_i915_private *dev_priv)
 +{
 +      if (!HAS_PCH_CNP(dev_priv))
 +              return;
 +
 +      /* Wa #1181 */
 +      I915_WRITE(SOUTH_DSPCLK_GATE_D, I915_READ(SOUTH_DSPCLK_GATE_D) |
 +                 CNP_PWM_CGE_GATING_DISABLE);
 +}
 +
 +static void cnl_init_clock_gating(struct drm_i915_private *dev_priv)
 +{
 +      u32 val;
 +      cnp_init_clock_gating(dev_priv);
 +
 +      /* This is not an Wa. Enable for better image quality */
 +      I915_WRITE(_3D_CHICKEN3,
 +                 _MASKED_BIT_ENABLE(_3D_CHICKEN3_AA_LINE_QUALITY_FIX_ENABLE));
 +
 +      /* WaEnableChickenDCPR:cnl */
 +      I915_WRITE(GEN8_CHICKEN_DCPR_1,
 +                 I915_READ(GEN8_CHICKEN_DCPR_1) | MASK_WAKEMEM);
 +
 +      /* WaFbcWakeMemOn:cnl */
 +      I915_WRITE(DISP_ARB_CTL, I915_READ(DISP_ARB_CTL) |
 +                 DISP_FBC_MEMORY_WAKE);
 +
 +      /* WaSarbUnitClockGatingDisable:cnl (pre-prod) */
 +      if (IS_CNL_REVID(dev_priv, CNL_REVID_A0, CNL_REVID_B0))
 +              I915_WRITE(SLICE_UNIT_LEVEL_CLKGATE,
 +                         I915_READ(SLICE_UNIT_LEVEL_CLKGATE) |
 +                         SARBUNIT_CLKGATE_DIS);
 +
 +      /* Display WA #1133: WaFbcSkipSegments:cnl */
 +      val = I915_READ(ILK_DPFC_CHICKEN);
 +      val &= ~GLK_SKIP_SEG_COUNT_MASK;
 +      val |= GLK_SKIP_SEG_EN | GLK_SKIP_SEG_COUNT(1);
 +      I915_WRITE(ILK_DPFC_CHICKEN, val);
 +}
 +
 +static void cfl_init_clock_gating(struct drm_i915_private *dev_priv)
 +{
 +      cnp_init_clock_gating(dev_priv);
 +      gen9_init_clock_gating(dev_priv);
 +
 +      /* WaFbcNukeOnHostModify:cfl */
 +      I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) |
 +                 ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
 +}
 +
 +static void kbl_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        gen9_init_clock_gating(dev_priv);
  
                I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) |
                           GEN6_GAMUNIT_CLOCK_GATE_DISABLE);
  
 -      /* WaFbcNukeOnHostModify:kbl,cfl */
 +      /* WaFbcNukeOnHostModify:kbl */
        I915_WRITE(ILK_DPFC_CHICKEN, I915_READ(ILK_DPFC_CHICKEN) |
                   ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
  }
  
 -static void skylake_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void skl_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        gen9_init_clock_gating(dev_priv);
  
                   ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
  }
  
 -static void broadwell_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
  {
 +      /* The GTT cache must be disabled if the system is using 2M pages. */
 +      bool can_use_gtt_cache = !HAS_PAGE_SIZES(dev_priv,
 +                                               I915_GTT_PAGE_SIZE_2M);
        enum pipe pipe;
  
        ilk_init_lp_watermarks(dev_priv);
        /* WaProgramL3SqcReg1Default:bdw */
        gen8_set_l3sqc_credits(dev_priv, 30, 2);
  
 -      /*
 -       * WaGttCachingOffByDefault:bdw
 -       * GTT cache may not work with big pages, so if those
 -       * are ever enabled GTT cache may need to be disabled.
 -       */
 -      I915_WRITE(HSW_GTT_CACHE_EN, GTT_CACHE_EN_ALL);
 +      /* WaGttCachingOffByDefault:bdw */
 +      I915_WRITE(HSW_GTT_CACHE_EN, can_use_gtt_cache ? GTT_CACHE_EN_ALL : 0);
  
        /* WaKVMNotificationOnConfigChange:bdw */
        I915_WRITE(CHICKEN_PAR2_1, I915_READ(CHICKEN_PAR2_1)
                   I915_READ(GEN6_UCGCTL1) | GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE);
  }
  
 -static void haswell_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void hsw_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        ilk_init_lp_watermarks(dev_priv);
  
        lpt_init_clock_gating(dev_priv);
  }
  
 -static void ivybridge_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void ivb_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        uint32_t snpcr;
  
        gen6_check_mch_setup(dev_priv);
  }
  
 -static void valleyview_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void vlv_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        /* WaDisableEarlyCull:vlv */
        I915_WRITE(_3D_CHICKEN3,
        I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS);
  }
  
 -static void cherryview_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void chv_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        /* WaVSRefCountFullforceMissDisable:chv */
        /* WaDSRefCountFullforceMissDisable:chv */
@@@ -8925,7 -8647,7 +8928,7 @@@ static void g4x_init_clock_gating(struc
        g4x_disable_trickle_feed(dev_priv);
  }
  
 -static void crestline_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void i965gm_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
        I915_WRITE(RENCLK_GATE_D2, 0);
        I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
  }
  
 -static void broadwater_init_clock_gating(struct drm_i915_private *dev_priv)
 +static void i965g_init_clock_gating(struct drm_i915_private *dev_priv)
  {
        I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
                   I965_RCC_CLOCK_GATE_DISABLE |
@@@ -9024,38 -8746,34 +9027,38 @@@ static void nop_init_clock_gating(struc
   */
  void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv)
  {
 -      if (IS_SKYLAKE(dev_priv))
 -              dev_priv->display.init_clock_gating = skylake_init_clock_gating;
 -      else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv))
 -              dev_priv->display.init_clock_gating = kabylake_init_clock_gating;
 +      if (IS_CANNONLAKE(dev_priv))
 +              dev_priv->display.init_clock_gating = cnl_init_clock_gating;
 +      else if (IS_COFFEELAKE(dev_priv))
 +              dev_priv->display.init_clock_gating = cfl_init_clock_gating;
 +      else if (IS_SKYLAKE(dev_priv))
 +              dev_priv->display.init_clock_gating = skl_init_clock_gating;
 +      else if (IS_KABYLAKE(dev_priv))
 +              dev_priv->display.init_clock_gating = kbl_init_clock_gating;
        else if (IS_BROXTON(dev_priv))
                dev_priv->display.init_clock_gating = bxt_init_clock_gating;
        else if (IS_GEMINILAKE(dev_priv))
                dev_priv->display.init_clock_gating = glk_init_clock_gating;
        else if (IS_BROADWELL(dev_priv))
 -              dev_priv->display.init_clock_gating = broadwell_init_clock_gating;
 +              dev_priv->display.init_clock_gating = bdw_init_clock_gating;
        else if (IS_CHERRYVIEW(dev_priv))
 -              dev_priv->display.init_clock_gating = cherryview_init_clock_gating;
 +              dev_priv->display.init_clock_gating = chv_init_clock_gating;
        else if (IS_HASWELL(dev_priv))
 -              dev_priv->display.init_clock_gating = haswell_init_clock_gating;
 +              dev_priv->display.init_clock_gating = hsw_init_clock_gating;
        else if (IS_IVYBRIDGE(dev_priv))
 -              dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
 +              dev_priv->display.init_clock_gating = ivb_init_clock_gating;
        else if (IS_VALLEYVIEW(dev_priv))
 -              dev_priv->display.init_clock_gating = valleyview_init_clock_gating;
 +              dev_priv->display.init_clock_gating = vlv_init_clock_gating;
        else if (IS_GEN6(dev_priv))
                dev_priv->display.init_clock_gating = gen6_init_clock_gating;
        else if (IS_GEN5(dev_priv))
 -              dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
 +              dev_priv->display.init_clock_gating = ilk_init_clock_gating;
        else if (IS_G4X(dev_priv))
                dev_priv->display.init_clock_gating = g4x_init_clock_gating;
        else if (IS_I965GM(dev_priv))
 -              dev_priv->display.init_clock_gating = crestline_init_clock_gating;
 +              dev_priv->display.init_clock_gating = i965gm_init_clock_gating;
        else if (IS_I965G(dev_priv))
 -              dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
 +              dev_priv->display.init_clock_gating = i965g_init_clock_gating;
        else if (IS_GEN3(dev_priv))
                dev_priv->display.init_clock_gating = gen3_init_clock_gating;
        else if (IS_I85X(dev_priv) || IS_I865G(dev_priv))
@@@ -9198,7 -8916,7 +9201,7 @@@ int sandybridge_pcode_read(struct drm_i
  {
        int status;
  
 -      WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 +      WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock));
  
        /* GEN6_PCODE_* are outside of the forcewake domain, we can
         * use te fw I915_READ variants to reduce the amount of work
@@@ -9245,7 -8963,7 +9248,7 @@@ int sandybridge_pcode_write(struct drm_
  {
        int status;
  
 -      WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 +      WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock));
  
        /* GEN6_PCODE_* are outside of the forcewake domain, we can
         * use te fw I915_READ variants to reduce the amount of work
@@@ -9322,7 -9040,7 +9325,7 @@@ int skl_pcode_request(struct drm_i915_p
        u32 status;
        int ret;
  
 -      WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 +      WARN_ON(!mutex_is_locked(&dev_priv->pcu_lock));
  
  #define COND skl_pcode_try_request(dev_priv, mbox, request, reply_mask, reply, \
                                   &status)
  
  static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
        /*
         * N = val - 0xb7
         * Slow = Fast = GPLL ref * N
         */
 -      return DIV_ROUND_CLOSEST(dev_priv->rps.gpll_ref_freq * (val - 0xb7), 1000);
 +      return DIV_ROUND_CLOSEST(rps->gpll_ref_freq * (val - 0xb7), 1000);
  }
  
  static int byt_freq_opcode(struct drm_i915_private *dev_priv, int val)
  {
 -      return DIV_ROUND_CLOSEST(1000 * val, dev_priv->rps.gpll_ref_freq) + 0xb7;
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
 +      return DIV_ROUND_CLOSEST(1000 * val, rps->gpll_ref_freq) + 0xb7;
  }
  
  static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
        /*
         * N = val / 2
         * CU (slow) = CU2x (fast) / 2 = GPLL ref * N / 2
         */
 -      return DIV_ROUND_CLOSEST(dev_priv->rps.gpll_ref_freq * val, 2 * 2 * 1000);
 +      return DIV_ROUND_CLOSEST(rps->gpll_ref_freq * val, 2 * 2 * 1000);
  }
  
  static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
  {
 +      struct intel_rps *rps = &dev_priv->gt_pm.rps;
 +
        /* CHV needs even values */
 -      return DIV_ROUND_CLOSEST(2 * 1000 * val, dev_priv->rps.gpll_ref_freq) * 2;
 +      return DIV_ROUND_CLOSEST(2 * 1000 * val, rps->gpll_ref_freq) * 2;
  }
  
  int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
@@@ -9425,16 -9135,53 +9428,16 @@@ int intel_freq_opcode(struct drm_i915_p
                return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER);
  }
  
 -struct request_boost {
 -      struct work_struct work;
 -      struct drm_i915_gem_request *req;
 -};
 -
 -static void __intel_rps_boost_work(struct work_struct *work)
 -{
 -      struct request_boost *boost = container_of(work, struct request_boost, work);
 -      struct drm_i915_gem_request *req = boost->req;
 -
 -      if (!i915_gem_request_completed(req))
 -              gen6_rps_boost(req, NULL);
 -
 -      i915_gem_request_put(req);
 -      kfree(boost);
 -}
 -
 -void intel_queue_rps_boost_for_request(struct drm_i915_gem_request *req)
 -{
 -      struct request_boost *boost;
 -
 -      if (req == NULL || INTEL_GEN(req->i915) < 6)
 -              return;
 -
 -      if (i915_gem_request_completed(req))
 -              return;
 -
 -      boost = kmalloc(sizeof(*boost), GFP_ATOMIC);
 -      if (boost == NULL)
 -              return;
 -
 -      boost->req = i915_gem_request_get(req);
 -
 -      INIT_WORK(&boost->work, __intel_rps_boost_work);
 -      queue_work(req->i915->wq, &boost->work);
 -}
 -
  void intel_pm_setup(struct drm_i915_private *dev_priv)
  {
 -      mutex_init(&dev_priv->rps.hw_lock);
 +      mutex_init(&dev_priv->pcu_lock);
  
 -      INIT_DELAYED_WORK(&dev_priv->rps.autoenable_work,
 +      INIT_DELAYED_WORK(&dev_priv->gt_pm.autoenable_work,
                          __intel_autoenable_gt_powersave);
 -      atomic_set(&dev_priv->rps.num_waiters, 0);
 +      atomic_set(&dev_priv->gt_pm.rps.num_waiters, 0);
  
 -      dev_priv->pm.suspended = false;
 -      atomic_set(&dev_priv->pm.wakeref_count, 0);
 +      dev_priv->runtime_pm.suspended = false;
 +      atomic_set(&dev_priv->runtime_pm.wakeref_count, 0);
  }
  
  static u64 vlv_residency_raw(struct drm_i915_private *dev_priv,
@@@ -9487,7 -9234,7 +9490,7 @@@ u64 intel_rc6_residency_us(struct drm_i
  {
        u64 time_hw, units, div;
  
 -      if (!intel_enable_rc6())
 +      if (!intel_rc6_enabled())
                return 0;
  
        intel_runtime_pm_get(dev_priv);
index 50d437568d43b976ab652da29358c32367fb4e62,deaf869374ea7016bbaa33aa45fb013aa00ec6ad..0f7324a686cac183949a952d34b4394b6701861c
@@@ -248,7 -248,7 +248,7 @@@ disable_clks
        clk_disable_unprepare(ahb_clk);
  disable_gdsc:
        regulator_disable(gdsc_reg);
-       pm_runtime_put_autosuspend(dev);
+       pm_runtime_put_sync(dev);
  put_clk:
        clk_put(ahb_clk);
  put_gdsc:
@@@ -334,46 -334,46 +334,46 @@@ static int dsi_regulator_init(struct ms
  
  static int dsi_clk_init(struct msm_dsi_host *msm_host)
  {
 -      struct device *dev = &msm_host->pdev->dev;
 +      struct platform_device *pdev = msm_host->pdev;
        const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd;
        const struct msm_dsi_config *cfg = cfg_hnd->cfg;
        int i, ret = 0;
  
        /* get bus clocks */
        for (i = 0; i < cfg->num_bus_clks; i++) {
 -              msm_host->bus_clks[i] = devm_clk_get(dev,
 +              msm_host->bus_clks[i] = msm_clk_get(pdev,
                                                cfg->bus_clk_names[i]);
                if (IS_ERR(msm_host->bus_clks[i])) {
                        ret = PTR_ERR(msm_host->bus_clks[i]);
 -                      pr_err("%s: Unable to get %s, ret = %d\n",
 +                      pr_err("%s: Unable to get %s clock, ret = %d\n",
                                __func__, cfg->bus_clk_names[i], ret);
                        goto exit;
                }
        }
  
        /* get link and source clocks */
 -      msm_host->byte_clk = devm_clk_get(dev, "byte_clk");
 +      msm_host->byte_clk = msm_clk_get(pdev, "byte");
        if (IS_ERR(msm_host->byte_clk)) {
                ret = PTR_ERR(msm_host->byte_clk);
 -              pr_err("%s: can't find dsi_byte_clk. ret=%d\n",
 +              pr_err("%s: can't find dsi_byte clock. ret=%d\n",
                        __func__, ret);
                msm_host->byte_clk = NULL;
                goto exit;
        }
  
 -      msm_host->pixel_clk = devm_clk_get(dev, "pixel_clk");
 +      msm_host->pixel_clk = msm_clk_get(pdev, "pixel");
        if (IS_ERR(msm_host->pixel_clk)) {
                ret = PTR_ERR(msm_host->pixel_clk);
 -              pr_err("%s: can't find dsi_pixel_clk. ret=%d\n",
 +              pr_err("%s: can't find dsi_pixel clock. ret=%d\n",
                        __func__, ret);
                msm_host->pixel_clk = NULL;
                goto exit;
        }
  
 -      msm_host->esc_clk = devm_clk_get(dev, "core_clk");
 +      msm_host->esc_clk = msm_clk_get(pdev, "core");
        if (IS_ERR(msm_host->esc_clk)) {
                ret = PTR_ERR(msm_host->esc_clk);
 -              pr_err("%s: can't find dsi_esc_clk. ret=%d\n",
 +              pr_err("%s: can't find dsi_esc clock. ret=%d\n",
                        __func__, ret);
                msm_host->esc_clk = NULL;
                goto exit;
        msm_host->byte_clk_src = clk_get_parent(msm_host->byte_clk);
        if (!msm_host->byte_clk_src) {
                ret = -ENODEV;
 -              pr_err("%s: can't find byte_clk_src. ret=%d\n", __func__, ret);
 +              pr_err("%s: can't find byte_clk clock. ret=%d\n", __func__, ret);
                goto exit;
        }
  
        msm_host->pixel_clk_src = clk_get_parent(msm_host->pixel_clk);
        if (!msm_host->pixel_clk_src) {
                ret = -ENODEV;
 -              pr_err("%s: can't find pixel_clk_src. ret=%d\n", __func__, ret);
 +              pr_err("%s: can't find pixel_clk clock. ret=%d\n", __func__, ret);
                goto exit;
        }
  
        if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) {
 -              msm_host->src_clk = devm_clk_get(dev, "src_clk");
 +              msm_host->src_clk = msm_clk_get(pdev, "src");
                if (IS_ERR(msm_host->src_clk)) {
                        ret = PTR_ERR(msm_host->src_clk);
 -                      pr_err("%s: can't find dsi_src_clk. ret=%d\n",
 +                      pr_err("%s: can't find src clock. ret=%d\n",
                                __func__, ret);
                        msm_host->src_clk = NULL;
                        goto exit;
                msm_host->esc_clk_src = clk_get_parent(msm_host->esc_clk);
                if (!msm_host->esc_clk_src) {
                        ret = -ENODEV;
 -                      pr_err("%s: can't get esc_clk_src. ret=%d\n",
 +                      pr_err("%s: can't get esc clock parent. ret=%d\n",
                                __func__, ret);
                        goto exit;
                }
                msm_host->dsi_clk_src = clk_get_parent(msm_host->src_clk);
                if (!msm_host->dsi_clk_src) {
                        ret = -ENODEV;
 -                      pr_err("%s: can't get dsi_clk_src. ret=%d\n",
 +                      pr_err("%s: can't get src clock parent. ret=%d\n",
                                __func__, ret);
                }
        }
index 6f84796c5abcd02000c5870e33988686f366de18,44097767700124df63f8a325969ea44b494256d7..e414850dbbdac72dbafae9277ad483ff000329ed
@@@ -55,23 -55,18 +55,23 @@@ struct mdp5_crtc 
  
        struct completion pp_completion;
  
 +      bool lm_cursor_enabled;
 +
        struct {
                /* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/
                spinlock_t lock;
  
                /* current cursor being scanned out: */
                struct drm_gem_object *scanout_bo;
 +              uint64_t iova;
                uint32_t width, height;
                uint32_t x, y;
        } cursor;
  };
  #define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
  
 +static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc);
 +
  static struct mdp5_kms *get_kms(struct drm_crtc *crtc)
  {
        struct msm_drm_private *priv = crtc->dev->dev_private;
@@@ -119,8 -114,6 +119,8 @@@ static u32 crtc_flush_all(struct drm_cr
                return 0;
  
        drm_atomic_crtc_for_each_plane(plane, crtc) {
 +              if (!plane->state->visible)
 +                      continue;
                flush_mask |= mdp5_plane_get_flush(plane);
        }
  
@@@ -249,9 -242,6 +249,9 @@@ static void blend_setup(struct drm_crt
        drm_atomic_crtc_for_each_plane(plane, crtc) {
                enum mdp5_pipe right_pipe;
  
 +              if (!plane->state->visible)
 +                      continue;
 +
                pstate = to_mdp5_plane_state(plane->state);
                pstates[pstate->stage] = pstate;
                stage[pstate->stage][PIPE_LEFT] = mdp5_plane_pipe(plane);
@@@ -432,14 -422,11 +432,14 @@@ static void mdp5_crtc_atomic_disable(st
        if (WARN_ON(!mdp5_crtc->enabled))
                return;
  
 +      /* Disable/save vblank irq handling before power is disabled */
 +      drm_crtc_vblank_off(crtc);
 +
        if (mdp5_cstate->cmd_mode)
                mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done);
  
        mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
 -      pm_runtime_put_autosuspend(dev);
 +      pm_runtime_put_sync(dev);
  
        mdp5_crtc->enabled = false;
  }
@@@ -459,29 -446,6 +459,29 @@@ static void mdp5_crtc_atomic_enable(str
  
        pm_runtime_get_sync(dev);
  
 +      if (mdp5_crtc->lm_cursor_enabled) {
 +              /*
 +               * Restore LM cursor state, as it might have been lost
 +               * with suspend:
 +               */
 +              if (mdp5_crtc->cursor.iova) {
 +                      unsigned long flags;
 +
 +                      spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
 +                      mdp5_crtc_restore_cursor(crtc);
 +                      spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
 +
 +                      mdp5_ctl_set_cursor(mdp5_cstate->ctl,
 +                                          &mdp5_cstate->pipeline, 0, true);
 +              } else {
 +                      mdp5_ctl_set_cursor(mdp5_cstate->ctl,
 +                                          &mdp5_cstate->pipeline, 0, false);
 +              }
 +      }
 +
 +      /* Restore vblank irq handling after power is enabled */
 +      drm_crtc_vblank_on(crtc);
 +
        mdp5_crtc_mode_set_nofb(crtc);
  
        mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
@@@ -616,9 -580,6 +616,9 @@@ static int mdp5_crtc_atomic_check(struc
        DBG("%s: check", crtc->name);
  
        drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
 +              if (!pstate->visible)
 +                      continue;
 +
                pstates[cnt].plane = plane;
                pstates[cnt].state = to_mdp5_plane_state(pstate);
  
@@@ -762,50 -723,6 +762,50 @@@ static void get_roi(struct drm_crtc *cr
                        mdp5_crtc->cursor.y);
  }
  
 +static void mdp5_crtc_restore_cursor(struct drm_crtc *crtc)
 +{
 +      struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
 +      struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
 +      struct mdp5_kms *mdp5_kms = get_kms(crtc);
 +      const enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
 +      uint32_t blendcfg, stride;
 +      uint32_t x, y, width, height;
 +      uint32_t roi_w, roi_h;
 +      int lm;
 +
 +      assert_spin_locked(&mdp5_crtc->cursor.lock);
 +
 +      lm = mdp5_cstate->pipeline.mixer->lm;
 +
 +      x = mdp5_crtc->cursor.x;
 +      y = mdp5_crtc->cursor.y;
 +      width = mdp5_crtc->cursor.width;
 +      height = mdp5_crtc->cursor.height;
 +
 +      stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0);
 +
 +      get_roi(crtc, &roi_w, &roi_h);
 +
 +      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
 +      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
 +                      MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
 +      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_IMG_SIZE(lm),
 +                      MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
 +                      MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
 +      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
 +                      MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
 +                      MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
 +      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(lm),
 +                      MDP5_LM_CURSOR_START_XY_Y_START(y) |
 +                      MDP5_LM_CURSOR_START_XY_X_START(x));
 +      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm),
 +                      mdp5_crtc->cursor.iova);
 +
 +      blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
 +      blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
 +      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
 +}
 +
  static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
                struct drm_file *file, uint32_t handle,
                uint32_t width, uint32_t height)
        struct platform_device *pdev = mdp5_kms->pdev;
        struct msm_kms *kms = &mdp5_kms->base.base;
        struct drm_gem_object *cursor_bo, *old_bo = NULL;
 -      uint32_t blendcfg, stride;
 -      uint64_t cursor_addr;
        struct mdp5_ctl *ctl;
 -      int ret, lm;
 -      enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
 +      int ret;
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
 -      uint32_t roi_w, roi_h;
        bool cursor_enable = true;
        unsigned long flags;
  
 +      if (!mdp5_crtc->lm_cursor_enabled) {
 +              dev_warn(dev->dev,
 +                       "cursor_set is deprecated with cursor planes\n");
 +              return -EINVAL;
 +      }
 +
        if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
                dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
                return -EINVAL;
        if (!handle) {
                DBG("Cursor off");
                cursor_enable = false;
 +              mdp5_crtc->cursor.iova = 0;
                pm_runtime_get_sync(&pdev->dev);
                goto set_cursor;
        }
        if (!cursor_bo)
                return -ENOENT;
  
 -      ret = msm_gem_get_iova(cursor_bo, kms->aspace, &cursor_addr);
 +      ret = msm_gem_get_iova(cursor_bo, kms->aspace,
 +                      &mdp5_crtc->cursor.iova);
        if (ret)
                return -EINVAL;
  
 -      lm = mdp5_cstate->pipeline.mixer->lm;
 -      stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0);
 -
        pm_runtime_get_sync(&pdev->dev);
  
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
        mdp5_crtc->cursor.width = width;
        mdp5_crtc->cursor.height = height;
  
 -      get_roi(crtc, &roi_w, &roi_h);
 -
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
 -                      MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_IMG_SIZE(lm),
 -                      MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
 -                      MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
 -                      MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
 -                      MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr);
 -
 -      blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
 -      blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
 +      mdp5_crtc_restore_cursor(crtc);
  
        spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
  
-       pm_runtime_put_autosuspend(&pdev->dev);
  set_cursor:
        ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable);
        if (ret) {
        crtc_flush(crtc, flush_mask);
  
  end:
 -      pm_runtime_put_autosuspend(&pdev->dev);
 +      pm_runtime_put_sync(&pdev->dev);
        if (old_bo) {
                drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo);
                /* enable vblank to complete cursor work: */
@@@ -900,18 -829,12 +898,18 @@@ static int mdp5_crtc_cursor_move(struc
        struct mdp5_kms *mdp5_kms = get_kms(crtc);
        struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
        struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
 -      uint32_t lm = mdp5_cstate->pipeline.mixer->lm;
        uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
 +      struct drm_device *dev = crtc->dev;
        uint32_t roi_w;
        uint32_t roi_h;
        unsigned long flags;
  
 +      if (!mdp5_crtc->lm_cursor_enabled) {
 +              dev_warn(dev->dev,
 +                       "cursor_move is deprecated with cursor planes\n");
 +              return -EINVAL;
 +      }
 +
        /* don't support LM cursors when we we have source split enabled */
        if (mdp5_cstate->pipeline.r_mixer)
                return -EINVAL;
        pm_runtime_get_sync(&mdp5_kms->pdev->dev);
  
        spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
 -                      MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
 -                      MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
 -      mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(lm),
 -                      MDP5_LM_CURSOR_START_XY_Y_START(y) |
 -                      MDP5_LM_CURSOR_START_XY_X_START(x));
 +      mdp5_crtc_restore_cursor(crtc);
        spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
  
        crtc_flush(crtc, flush_mask);
  
 -      pm_runtime_put_autosuspend(&mdp5_kms->pdev->dev);
 +      pm_runtime_put_sync(&mdp5_kms->pdev->dev);
  
        return 0;
  }
@@@ -1013,6 -941,16 +1011,6 @@@ static const struct drm_crtc_funcs mdp5
        .atomic_print_state = mdp5_crtc_atomic_print_state,
  };
  
 -static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = {
 -      .set_config = drm_atomic_helper_set_config,
 -      .destroy = mdp5_crtc_destroy,
 -      .page_flip = drm_atomic_helper_page_flip,
 -      .reset = mdp5_crtc_reset,
 -      .atomic_duplicate_state = mdp5_crtc_duplicate_state,
 -      .atomic_destroy_state = mdp5_crtc_destroy_state,
 -      .atomic_print_state = mdp5_crtc_atomic_print_state,
 -};
 -
  static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
        .mode_set_nofb = mdp5_crtc_mode_set_nofb,
        .atomic_check = mdp5_crtc_atomic_check,
@@@ -1181,10 -1119,12 +1179,10 @@@ struct drm_crtc *mdp5_crtc_init(struct 
        mdp5_crtc->err.irq = mdp5_crtc_err_irq;
        mdp5_crtc->pp_done.irq = mdp5_crtc_pp_done_irq;
  
 -      if (cursor_plane)
 -              drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane,
 -                                        &mdp5_crtc_no_lm_cursor_funcs, NULL);
 -      else
 -              drm_crtc_init_with_planes(dev, crtc, plane, NULL,
 -                                        &mdp5_crtc_funcs, NULL);
 +      mdp5_crtc->lm_cursor_enabled = cursor_plane ? false : true;
 +
 +      drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane,
 +                                &mdp5_crtc_funcs, NULL);
  
        drm_flip_work_init(&mdp5_crtc->unref_cursor_work,
                        "unref cursor", unref_cursor_worker);
index 0776160a6924fc04970838b7c883d1e3da7388c3,ea5bb0e1632c69e45e746d8abfb820ba9d540e0b..81fe6d6740cec7582d11b4f92e267509dffb2c29
@@@ -470,16 -470,14 +470,16 @@@ fail
        return ret;
  }
  
 -void *msm_gem_get_vaddr(struct drm_gem_object *obj)
 +static void *get_vaddr(struct drm_gem_object *obj, unsigned madv)
  {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        int ret = 0;
  
        mutex_lock(&msm_obj->lock);
  
 -      if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) {
 +      if (WARN_ON(msm_obj->madv > madv)) {
 +              dev_err(obj->dev->dev, "Invalid madv state: %u vs %u\n",
 +                      msm_obj->madv, madv);
                mutex_unlock(&msm_obj->lock);
                return ERR_PTR(-EBUSY);
        }
@@@ -515,22 -513,6 +515,22 @@@ fail
        return ERR_PTR(ret);
  }
  
 +void *msm_gem_get_vaddr(struct drm_gem_object *obj)
 +{
 +      return get_vaddr(obj, MSM_MADV_WILLNEED);
 +}
 +
 +/*
 + * Don't use this!  It is for the very special case of dumping
 + * submits from GPU hangs or faults, were the bo may already
 + * be MSM_MADV_DONTNEED, but we know the buffer is still on the
 + * active list.
 + */
 +void *msm_gem_get_vaddr_active(struct drm_gem_object *obj)
 +{
 +      return get_vaddr(obj, __MSM_MADV_PURGED);
 +}
 +
  void msm_gem_put_vaddr(struct drm_gem_object *obj)
  {
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@@ -1052,10 -1034,10 +1052,10 @@@ static void *_msm_gem_kernel_new(struc
        }
  
        vaddr = msm_gem_get_vaddr(obj);
-       if (!vaddr) {
+       if (IS_ERR(vaddr)) {
                msm_gem_put_iova(obj, aspace);
                drm_gem_object_unreference(obj);
-               return ERR_PTR(-ENOMEM);
+               return ERR_CAST(vaddr);
        }
  
        if (bo)
index 96d678b582d9ead1f9e9f936b2eea44d11c65721,ec56794ad0399277693b9185c75b6abcf9241e4a..3aa8a8576abea8323a4c30534837a3defcac9b17
   *
   *   tail -f /sys/kernel/debug/dri/<minor>/rd > logfile.rd
   *
 - * To log the cmdstream in a format that is understood by freedreno/cffdump
 + * to log the cmdstream in a format that is understood by freedreno/cffdump
   * utility.  By comparing the last successfully completed fence #, to the
   * cmdstream for the next fence, you can narrow down which process and submit
   * caused the gpu crash/lockup.
   *
 + * Additionally:
 + *
 + *   tail -f /sys/kernel/debug/dri/<minor>/hangrd > logfile.rd
 + *
 + * will capture just the cmdstream from submits which triggered a GPU hang.
 + *
   * This bypasses drm_debugfs_create_files() mainly because we need to use
   * our own fops for a bit more control.  In particular, we don't want to
   * do anything if userspace doesn't have the debugfs file open.
@@@ -117,10 -111,14 +117,14 @@@ static void rd_write(struct msm_rd_stat
  
                wait_event(rd->fifo_event, circ_space(&rd->fifo) > 0);
  
+               /* Note that smp_load_acquire() is not strictly required
+                * as CIRC_SPACE_TO_END() does not access the tail more
+                * than once.
+                */
                n = min(sz, circ_space_to_end(&rd->fifo));
                memcpy(fptr, ptr, n);
  
-               fifo->head = (fifo->head + n) & (BUF_SZ - 1);
+               smp_store_release(&fifo->head, (fifo->head + n) & (BUF_SZ - 1));
                sz  -= n;
                ptr += n;
  
@@@ -151,13 -149,17 +155,17 @@@ static ssize_t rd_read(struct file *fil
        if (ret)
                goto out;
  
+       /* Note that smp_load_acquire() is not strictly required
+        * as CIRC_CNT_TO_END() does not access the head more than
+        * once.
+        */
        n = min_t(int, sz, circ_count_to_end(&rd->fifo));
        if (copy_to_user(buf, fptr, n)) {
                ret = -EFAULT;
                goto out;
        }
  
-       fifo->tail = (fifo->tail + n) & (BUF_SZ - 1);
+       smp_store_release(&fifo->tail, (fifo->tail + n) & (BUF_SZ - 1));
        *ppos += n;
  
        wake_up_all(&rd->fifo_event);
@@@ -218,89 -220,53 +226,89 @@@ static const struct file_operations rd_
        .release = rd_release,
  };
  
 -int msm_rd_debugfs_init(struct drm_minor *minor)
 +
 +static void rd_cleanup(struct msm_rd_state *rd)
 +{
 +      if (!rd)
 +              return;
 +
 +      mutex_destroy(&rd->read_lock);
 +      kfree(rd);
 +}
 +
 +static struct msm_rd_state *rd_init(struct drm_minor *minor, const char *name)
  {
 -      struct msm_drm_private *priv = minor->dev->dev_private;
        struct msm_rd_state *rd;
        struct dentry *ent;
 -
 -      /* only create on first minor: */
 -      if (priv->rd)
 -              return 0;
 +      int ret = 0;
  
        rd = kzalloc(sizeof(*rd), GFP_KERNEL);
        if (!rd)
 -              return -ENOMEM;
 +              return ERR_PTR(-ENOMEM);
  
        rd->dev = minor->dev;
        rd->fifo.buf = rd->buf;
  
        mutex_init(&rd->read_lock);
 -      priv->rd = rd;
  
        init_waitqueue_head(&rd->fifo_event);
  
 -      ent = debugfs_create_file("rd", S_IFREG | S_IRUGO,
 +      ent = debugfs_create_file(name, S_IFREG | S_IRUGO,
                        minor->debugfs_root, rd, &rd_debugfs_fops);
        if (!ent) {
 -              DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/rd\n",
 -                              minor->debugfs_root);
 +              DRM_ERROR("Cannot create /sys/kernel/debug/dri/%pd/%s\n",
 +                              minor->debugfs_root, name);
 +              ret = -ENOMEM;
                goto fail;
        }
  
 +      return rd;
 +
 +fail:
 +      rd_cleanup(rd);
 +      return ERR_PTR(ret);
 +}
 +
 +int msm_rd_debugfs_init(struct drm_minor *minor)
 +{
 +      struct msm_drm_private *priv = minor->dev->dev_private;
 +      struct msm_rd_state *rd;
 +      int ret;
 +
 +      /* only create on first minor: */
 +      if (priv->rd)
 +              return 0;
 +
 +      rd = rd_init(minor, "rd");
 +      if (IS_ERR(rd)) {
 +              ret = PTR_ERR(rd);
 +              goto fail;
 +      }
 +
 +      priv->rd = rd;
 +
 +      rd = rd_init(minor, "hangrd");
 +      if (IS_ERR(rd)) {
 +              ret = PTR_ERR(rd);
 +              goto fail;
 +      }
 +
 +      priv->hangrd = rd;
 +
        return 0;
  
  fail:
        msm_rd_debugfs_cleanup(priv);
 -      return -1;
 +      return ret;
  }
  
  void msm_rd_debugfs_cleanup(struct msm_drm_private *priv)
  {
 -      struct msm_rd_state *rd = priv->rd;
 -
 -      if (!rd)
 -              return;
 -
 +      rd_cleanup(priv->rd);
        priv->rd = NULL;
 -      mutex_destroy(&rd->read_lock);
 -      kfree(rd);
 +
 +      rd_cleanup(priv->hangrd);
 +      priv->hangrd = NULL;
  }
  
  static void snapshot_buf(struct msm_rd_state *rd,
        struct msm_gem_object *obj = submit->bos[idx].obj;
        const char *buf;
  
 -      buf = msm_gem_get_vaddr(&obj->base);
 -      if (IS_ERR(buf))
 -              return;
 -
        if (iova) {
                buf += iova - submit->bos[idx].iova;
        } else {
                size = obj->base.size;
        }
  
 +      /*
 +       * Always write the GPUADDR header so can get a complete list of all the
 +       * buffers in the cmd
 +       */
        rd_write_section(rd, RD_GPUADDR,
                        (uint32_t[3]){ iova, size, iova >> 32 }, 12);
 +
 +      /* But only dump the contents of buffers marked READ */
 +      if (!(submit->bos[idx].flags & MSM_SUBMIT_BO_READ))
 +              return;
 +
 +      buf = msm_gem_get_vaddr_active(&obj->base);
 +      if (IS_ERR(buf))
 +              return;
 +
        rd_write_section(rd, RD_BUFFER_CONTENTS, buf, size);
  
        msm_gem_put_vaddr(&obj->base);
  }
  
  /* called under struct_mutex */
 -void msm_rd_dump_submit(struct msm_gem_submit *submit)
 +void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit,
 +              const char *fmt, ...)
  {
        struct drm_device *dev = submit->dev;
 -      struct msm_drm_private *priv = dev->dev_private;
 -      struct msm_rd_state *rd = priv->rd;
 -      char msg[128];
 +      struct task_struct *task;
 +      char msg[256];
        int i, n;
  
        if (!rd->open)
         */
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
  
 -      n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u",
 -                      TASK_COMM_LEN, current->comm, task_pid_nr(current),
 -                      submit->fence->seqno);
 +      if (fmt) {
 +              va_list args;
  
 -      rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4));
 +              va_start(args, fmt);
 +              n = vsnprintf(msg, sizeof(msg), fmt, args);
 +              va_end(args);
  
 -      if (rd_full) {
 -              for (i = 0; i < submit->nr_bos; i++) {
 -                      /* buffers that are written to probably don't start out
 -                       * with anything interesting:
 -                       */
 -                      if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
 -                              continue;
 +              rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4));
 +      }
  
 -                      snapshot_buf(rd, submit, i, 0, 0);
 -              }
 +      rcu_read_lock();
 +      task = pid_task(submit->pid, PIDTYPE_PID);
 +      if (task) {
 +              n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u",
 +                              TASK_COMM_LEN, task->comm,
 +                              pid_nr(submit->pid), submit->seqno);
 +      } else {
 +              n = snprintf(msg, sizeof(msg), "???/%d: fence=%u",
 +                              pid_nr(submit->pid), submit->seqno);
        }
 +      rcu_read_unlock();
 +
 +      rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4));
 +
 +      for (i = 0; rd_full && i < submit->nr_bos; i++)
 +              snapshot_buf(rd, submit, i, 0, 0);
  
        for (i = 0; i < submit->nr_cmds; i++) {
                uint64_t iova = submit->cmd[i].iova;