]> Git Repo - linux.git/commitdiff
Merge tag 'drm-next-2020-06-02' of git://anongit.freedesktop.org/drm/drm
authorLinus Torvalds <[email protected]>
Tue, 2 Jun 2020 22:04:15 +0000 (15:04 -0700)
committerLinus Torvalds <[email protected]>
Tue, 2 Jun 2020 22:04:15 +0000 (15:04 -0700)
Pull drm updates from Dave Airlie:
 "Highlights:

   - Core DRM had a lot of refactoring around managed drm resources to
     make drivers simpler.

   - Intel Tigerlake support is on by default

   - amdgpu now support p2p PCI buffer sharing and encrypted GPU memory

  Details:

  core:
   - uapi: error out EBUSY when existing master
   - uapi: rework SET/DROP MASTER permission handling
   - remove drm_pci.h
   - drm_pci* are now legacy
   - introduced managed DRM resources
   - subclassing support for drm_framebuffer
   - simple encoder helper
   - edid improvements
   - vblank + writeback documentation improved
   - drm/mm - optimise tree searches
   - port drivers to use devm_drm_dev_alloc

  dma-buf:
   - add flag for p2p buffer support

  mst:
   - ACT timeout improvements
   - remove drm_dp_mst_has_audio
   - don't use 2nd TX slot - spec recommends against it

  bridge:
   - dw-hdmi various improvements
   - chrontel ch7033 support
   - fix stack issues with old gcc

  hdmi:
   - add unpack function for drm infoframe

  fbdev:
   - misc fbdev driver fixes

  i915:
   - uapi: global sseu pinning
   - uapi: OA buffer polling
   - uapi: remove generated perf code
   - uapi: per-engine default property values in sysfs
   - Tigerlake GEN12 enabled.
   - Lots of gem refactoring
   - Tigerlake enablement patches
   - move to drm_device logging
   - Icelake gamma HW readout
   - push MST link retrain to hotplug work
   - bandwidth atomic helpers
   - ICL fixes
   - RPS/GT refactoring
   - Cherryview full-ppgtt support
   - i915 locking guidelines documented
   - require linear fb stride to be 512 multiple on gen9
   - Tigerlake SAGV support

  amdgpu:
   - uapi: encrypted GPU memory handling
   - uapi: add MEM_SYNC IB flag
   - p2p dma-buf support
   - export VRAM dma-bufs
   - FRU chip access support
   - RAS/SR-IOV updates
   - Powerplay locking fixes
   - VCN DPG (powergating) enablement
   - GFX10 clockgating fixes
   - DC fixes
   - GPU reset fixes
   - navi SDMA fix
   - expose FP16 for modesetting
   - DP 1.4 compliance fixes
   - gfx10 soft recovery
   - Improved Critical Thermal Faults handling
   - resizable BAR on gmc10

  amdkfd:
   - uapi: GWS resource management
   - track GPU memory per process
   - report PCI domain in topology

  radeon:
   - safe reg list generator fixes

  nouveau:
   - HD audio fixes on recent systems
   - vGPU detection (fail probe if we're on one, for now)
   - Interlaced mode fixes (mostly avoidance on Turing, which doesn't support it)
   - SVM improvements/fixes
   - NVIDIA format modifier support
   - Misc other fixes.

  adv7511:
   - HDMI SPDIF support

  ast:
   - allocate crtc state size
   - fix double assignment
   - fix suspend

  bochs:
   - drop connector register

  cirrus:
   - move to tiny drivers.

  exynos:
   - fix imported dma-buf mapping
   - enable runtime PM
   - fixes and cleanups

  mediatek:
   - DPI pin mode swap
   - config mipi_tx current/impedance

  lima:
   - devfreq + cooling device support
   - task handling improvements
   - runtime PM support

  pl111:
   - vexpress init improvements
   - fix module auto-load

  rcar-du:
   - DT bindings conversion to YAML
   - Planes zpos sanity check and fix
   - MAINTAINERS entry for LVDS panel driver

  mcde:
   - fix return value

  mgag200:
   - use managed config init

  stm:
   - read endpoints from DT

  vboxvideo:
   - use PCI managed functions
   - drop WC mtrr

  vkms:
   - enable cursor by default

  rockchip:
   - afbc support

  virtio:
   - various cleanups

  qxl:
   - fix cursor notify port

  hisilicon:
   - 128-byte stride alignment fix

  sun4i:
   - improved format handling"

* tag 'drm-next-2020-06-02' of git://anongit.freedesktop.org/drm/drm: (1401 commits)
  drm/amd/display: Fix potential integer wraparound resulting in a hang
  drm/amd/display: drop cursor position check in atomic test
  drm/amdgpu: fix device attribute node create failed with multi gpu
  drm/nouveau: use correct conflicting framebuffer API
  drm/vblank: Fix -Wformat compile warnings on some arches
  drm/amdgpu: Sync with VM root BO when switching VM to CPU update mode
  drm/amd/display: Handle GPU reset for DC block
  drm/amdgpu: add apu flags (v2)
  drm/amd/powerpay: Disable gfxoff when setting manual mode on picasso and raven
  drm/amdgpu: fix pm sysfs node handling (v2)
  drm/amdgpu: move gpu_info parsing after common early init
  drm/amdgpu: move discovery gfx config fetching
  drm/nouveau/dispnv50: fix runtime pm imbalance on error
  drm/nouveau: fix runtime pm imbalance on error
  drm/nouveau: fix runtime pm imbalance on error
  drm/nouveau/debugfs: fix runtime pm imbalance on error
  drm/nouveau/nouveau/hmm: fix migrate zero page to GPU
  drm/nouveau/nouveau/hmm: fix nouveau_dmem_chunk allocations
  drm/nouveau/kms/nv50-: Share DP SST mode_valid() handling with MST
  drm/nouveau/kms/nv50-: Move 8BPC limit for MST into nv50_mstc_get_modes()
  ...

36 files changed:
1  2 
Documentation/devicetree/bindings/vendor-prefixes.yaml
MAINTAINERS
drivers/dma-buf/dma-buf.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_file.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/etnaviv/etnaviv_drv.c
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/ingenic/ingenic-drm.c
drivers/gpu/drm/meson/meson_drv.c
drivers/gpu/drm/meson/meson_dw_hdmi.c
drivers/gpu/drm/nouveau/nouveau_dmem.c
drivers/gpu/drm/nouveau/nouveau_dmem.h
drivers/gpu/drm/nouveau/nouveau_svm.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tidss/tidss_crtc.c
drivers/gpu/drm/tidss/tidss_plane.c
drivers/gpu/drm/virtio/virtgpu_drv.h
drivers/gpu/drm/virtio/virtgpu_gem.c
drivers/gpu/drm/virtio/virtgpu_ioctl.c
include/drm/drm_modes.h
include/linux/dma-buf.h
mm/slub.c

index d3277fe6640bd8b0c7bc50d2f3da493172edf07d,7a39732c582d1248eaed218f16a2c435ba881e65..997934c58f9a3d2672265ecd1695084c47d81cc4
@@@ -187,6 -187,8 +187,8 @@@ patternProperties
      description: ChipOne
    "^chipspark,.*":
      description: ChipSPARK
+   "^chrontel,.*":
+     description: Chrontel, Inc.
    "^chrp,.*":
      description: Common Hardware Reference Platform
    "^chunghwa,.*":
      description: Infineon Technologies
    "^inforce,.*":
      description: Inforce Computing
+   "^ivo,.*":
+     description: InfoVision Optoelectronics Kunshan Co. Ltd.
    "^ingenic,.*":
      description: Ingenic Semiconductor
    "^innolux,.*":
    "^issi,.*":
      description: Integrated Silicon Solutions Inc.
    "^ite,.*":
-     description: ITE Tech, Inc.
+     description: ITE Tech. Inc.
    "^itead,.*":
      description: ITEAD Intelligent Systems Co.Ltd
    "^iwave,.*":
      description: Microsoft Corporation
    "^mikroe,.*":
      description: MikroElektronika d.o.o.
 +  "^mikrotik,.*":
 +    description: MikroTik
    "^miniand,.*":
      description: Miniand Tech
    "^minix,.*":
      description: Tronsmart
    "^truly,.*":
      description: Truly Semiconductors Limited
+   "^visionox,.*":
+     description: Visionox
    "^tsd,.*":
      description: Theobroma Systems Design und Consulting GmbH
    "^tyan,.*":
diff --combined MAINTAINERS
index ef7414d7de3f0dd88c7fed9d570a1d2b08a48824,f437f42b73ad74e6b59f5feaa088e65243e10770..a439da570dc3586c40880b3a92e2f66b5803a800
@@@ -189,7 -189,7 +189,7 @@@ F: drivers/net/hamradio/6pack.
  M:    Johannes Berg <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/
 +W:    https://wireless.wiki.kernel.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
  F:    Documentation/driver-api/80211/cfg80211.rst
@@@ -505,7 -505,7 +505,7 @@@ F: drivers/hwmon/adm1029.
  ADM8211 WIRELESS DRIVER
  L:    [email protected]
  S:    Orphan
 -W:    http://wireless.kernel.org/
 +W:    https://wireless.wiki.kernel.org/
  F:    drivers/net/wireless/admtek/adm8211.*
  
  ADP1653 FLASH CONTROLLER DRIVER
@@@ -570,7 -570,7 +570,7 @@@ F: Documentation/devicetree/bindings/ii
  F:    drivers/input/misc/adxl34x.c
  
  ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
 -M:    Stefan Popa <stefan.popa@analog.com>
 +M:    Michael Hennerich <michael.hennerich@analog.com>
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
  F:    Documentation/devicetree/bindings/iio/accel/adi,adxl372.yaml
@@@ -842,13 -842,6 +842,13 @@@ S:       Supporte
  T:    git git://people.freedesktop.org/~agd5f/linux
  F:    drivers/gpu/drm/amd/display/
  
 +AMD ENERGY DRIVER
 +M:    Naveen Krishna Chatradhi <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    Documentation/hwmon/amd_energy.rst
 +F:    drivers/hwmon/amd_energy.c
 +
  AMD FAM15H PROCESSOR POWER MONITORING DRIVER
  M:    Huang Rui <[email protected]>
  L:    [email protected]
@@@ -899,11 -892,6 +899,11 @@@ F:       drivers/gpu/drm/amd/include/v9_struc
  F:    drivers/gpu/drm/amd/include/vi_structs.h
  F:    include/uapi/linux/kfd_ioctl.h
  
 +AMD SPI DRIVER
 +M:    Sanjay R Mehta <[email protected]>
 +S:    Maintained
 +F:    drivers/spi/spi-amd.c
 +
  AMD MP2 I2C DRIVER
  M:    Elie Morisse <[email protected]>
  M:    Nehal Shah <[email protected]>
@@@ -934,7 -922,7 +934,7 @@@ F: arch/arm64/boot/dts/amd/amd-seattle-
  F:    drivers/net/ethernet/amd/xgbe/
  
  ANALOG DEVICES INC AD5686 DRIVER
 -M:    Stefan Popa <stefan.popa@analog.com>
 +M:    Michael Hennerich <Michael.Hennerich@analog.com>
  L:    [email protected]
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
@@@ -942,7 -930,7 +942,7 @@@ F: drivers/iio/dac/ad5686
  F:    drivers/iio/dac/ad5696*
  
  ANALOG DEVICES INC AD5758 DRIVER
 -M:    Stefan Popa <stefan.popa@analog.com>
 +M:    Michael Hennerich <Michael.Hennerich@analog.com>
  L:    [email protected]
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
@@@ -958,7 -946,7 +958,7 @@@ F: Documentation/devicetree/bindings/ii
  F:    drivers/iio/adc/ad7091r5.c
  
  ANALOG DEVICES INC AD7124 DRIVER
 -M:    Stefan Popa <stefan.popa@analog.com>
 +M:    Michael Hennerich <Michael.Hennerich@analog.com>
  L:    [email protected]
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
@@@ -982,7 -970,7 +982,7 @@@ F: Documentation/devicetree/bindings/ii
  F:    drivers/iio/adc/ad7292.c
  
  ANALOG DEVICES INC AD7606 DRIVER
 -M:    Stefan Popa <stefan.popa@analog.com>
 +M:    Michael Hennerich <Michael.Hennerich@analog.com>
  M:    Beniamin Bia <[email protected]>
  L:    [email protected]
  S:    Supported
@@@ -991,7 -979,7 +991,7 @@@ F: Documentation/devicetree/bindings/ii
  F:    drivers/iio/adc/ad7606.c
  
  ANALOG DEVICES INC AD7768-1 DRIVER
 -M:    Stefan Popa <stefan.popa@analog.com>
 +M:    Michael Hennerich <Michael.Hennerich@analog.com>
  L:    [email protected]
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
@@@ -1052,7 -1040,7 +1052,7 @@@ F:      Documentation/devicetree/bindings/hw
  F:    drivers/hwmon/adm1177.c
  
  ANALOG DEVICES INC ADP5061 DRIVER
 -M:    Stefan Popa <stefan.popa@analog.com>
 +M:    Michael Hennerich <Michael.Hennerich@analog.com>
  L:    [email protected]
  S:    Supported
  W:    http://ez.analog.com/community/linux-device-drivers
@@@ -1121,6 -1109,7 +1121,6 @@@ F:      drivers/iio/amplifiers/hmc425a.
  ANALOG DEVICES INC IIO DRIVERS
  M:    Lars-Peter Clausen <[email protected]>
  M:    Michael Hennerich <[email protected]>
 -M:    Stefan Popa <[email protected]>
  S:    Supported
  W:    http://wiki.analog.com/
  W:    http://ez.analog.com/community/linux-device-drivers
@@@ -2237,7 -2226,6 +2237,7 @@@ F:      drivers/*/qcom
  F:    drivers/*/qcom/
  F:    drivers/bluetooth/btqcomsmd.c
  F:    drivers/clocksource/timer-qcom.c
 +F:    drivers/cpuidle/cpuidle-qcom-spm.c
  F:    drivers/extcon/extcon-qcom*
  F:    drivers/i2c/busses/i2c-qcom-geni.c
  F:    drivers/i2c/busses/i2c-qup.c
@@@ -2862,14 -2850,14 +2862,14 @@@ M:   Nick Kossifidis <[email protected]
  M:    Luis Chamberlain <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/en/users/Drivers/ath5k
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/ath5k
  F:    drivers/net/wireless/ath/ath5k/
  
  ATHEROS ATH6KL WIRELESS DRIVER
  M:    Kalle Valo <[email protected]>
  L:    [email protected]
  S:    Supported
 -W:    http://wireless.kernel.org/en/users/Drivers/ath6kl
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/ath6kl
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
  F:    drivers/net/wireless/ath/ath6kl/
  
@@@ -3032,7 -3020,7 +3032,7 @@@ B43 WIRELESS DRIVE
  L:    [email protected]
  L:    [email protected]
  S:    Odd Fixes
 -W:    http://wireless.kernel.org/en/users/Drivers/b43
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/b43
  F:    drivers/net/wireless/broadcom/b43/
  
  B43LEGACY WIRELESS DRIVER
@@@ -3040,7 -3028,7 +3040,7 @@@ M:      Larry Finger <Larry.Finger@lwfinger.
  L:    [email protected]
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/en/users/Drivers/b43
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/b43
  F:    drivers/net/wireless/broadcom/b43legacy/
  
  BACKLIGHT CLASS/SUBSYSTEM
@@@ -3670,7 -3658,7 +3670,7 @@@ L:      [email protected]
  S:    Maintained
  W:    http://btrfs.wiki.kernel.org/
  Q:    http://patchwork.kernel.org/project/linux-btrfs/list/
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux.git
  F:    Documentation/filesystems/btrfs.rst
  F:    fs/btrfs/
  F:    include/linux/btrfs*
@@@ -3743,7 -3731,7 +3743,7 @@@ CACHEFILES: FS-CACHE BACKEND FOR CACHIN
  M:    David Howells <[email protected]>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
 -F:    Documentation/filesystems/caching/cachefiles.txt
 +F:    Documentation/filesystems/caching/cachefiles.rst
  F:    fs/cachefiles/
  
  CADENCE MIPI-CSI2 BRIDGES
@@@ -3855,7 -3843,7 +3855,7 @@@ CARL9170 LINUX COMMUNITY WIRELESS DRIVE
  M:    Christian Lamparter <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/en/users/Drivers/carl9170
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/carl9170
  F:    drivers/net/wireless/ath/carl9170/
  
  CAVIUM I2C DRIVER
@@@ -3909,15 -3897,6 +3909,15 @@@ S:    Supporte
  W:    https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family
  F:    drivers/crypto/ccree/
  
 +CCTRNG ARM TRUSTZONE CRYPTOCELL TRUE RANDOM NUMBER GENERATOR (TRNG) DRIVER
 +M:    Hadar Gat <[email protected]>
 +L:    [email protected]
 +S:    Supported
 +F:    drivers/char/hw_random/cctrng.c
 +F:    drivers/char/hw_random/cctrng.h
 +F:    Documentation/devicetree/bindings/rng/arm-cctrng.txt
 +W:    https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family
 +
  CEC FRAMEWORK
  M:    Hans Verkuil <[email protected]>
  L:    [email protected]
@@@ -3958,9 -3937,11 +3958,9 @@@ F:     arch/powerpc/platforms/cell
  CEPH COMMON CODE (LIBCEPH)
  M:    Ilya Dryomov <[email protected]>
  M:    Jeff Layton <[email protected]>
 -M:    Sage Weil <[email protected]>
  L:    [email protected]
  S:    Supported
  W:    http://ceph.com/
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
  T:    git git://github.com/ceph/ceph-client.git
  F:    include/linux/ceph/
  F:    include/linux/crush/
@@@ -3968,10 -3949,12 +3968,10 @@@ F:   net/ceph
  
  CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
  M:    Jeff Layton <[email protected]>
 -M:    Sage Weil <[email protected]>
  M:    Ilya Dryomov <[email protected]>
  L:    [email protected]
  S:    Supported
  W:    http://ceph.com/
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
  T:    git git://github.com/ceph/ceph-client.git
  F:    Documentation/filesystems/ceph.rst
  F:    fs/ceph/
@@@ -4220,7 -4203,7 +4220,7 @@@ M:      [email protected]
  L:    [email protected]
  S:    Maintained
  W:    http://www.coda.cs.cmu.edu/
 -F:    Documentation/filesystems/coda.txt
 +F:    Documentation/filesystems/coda.rst
  F:    fs/coda/
  F:    include/linux/coda*.h
  F:    include/uapi/linux/coda*.h
@@@ -5013,7 -4996,7 +5013,7 @@@ M:      Jan Kara <[email protected]
  R:    Amir Goldstein <[email protected]>
  L:    [email protected]
  S:    Maintained
 -F:    Documentation/filesystems/dnotify.txt
 +F:    Documentation/filesystems/dnotify.rst
  F:    fs/notify/dnotify/
  F:    include/linux/dnotify.h
  
@@@ -5027,7 -5010,7 +5027,7 @@@ W:      http://www.win.tue.nl/~aeb/partition
  DISKQUOTA
  M:    Jan Kara <[email protected]>
  S:    Maintained
 -F:    Documentation/filesystems/quota.txt
 +F:    Documentation/filesystems/quota.rst
  F:    fs/quota/
  F:    include/linux/quota*.h
  F:    include/uapi/linux/quota*.h
@@@ -5062,7 -5045,7 +5062,7 @@@ F:      drivers/dma-buf
  F:    include/linux/*fence.h
  F:    include/linux/dma-buf*
  F:    include/linux/dma-resv.h
- K:    dma_(buf|fence|resv)
+ K:    \bdma_(?:buf|fence|resv)\b
  
  DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
  M:    Vinod Koul <[email protected]>
@@@ -5193,7 -5176,6 +5193,7 @@@ S:      Maintaine
  F:    drivers/soc/fsl/dpio
  
  DPAA2 ETHERNET DRIVER
 +M:    Ioana Ciornei <[email protected]>
  M:    Ioana Radulescu <[email protected]>
  L:    [email protected]
  S:    Maintained
@@@ -5274,7 -5256,7 +5274,7 @@@ DRM DRIVER FOR ARM VERSATILE TFT PANEL
  M:    Linus Walleij <[email protected]>
  S:    Maintained
  T:    git git://anongit.freedesktop.org/drm/drm-misc
- F:    Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.txt
+ F:    Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.yaml
  F:    drivers/gpu/drm/panel/panel-arm-versatile.c
  
  DRM DRIVER FOR ASPEED BMC GFX
@@@ -5300,7 -5282,7 +5300,7 @@@ F:      drivers/gpu/drm/bochs
  DRM DRIVER FOR BOE HIMAX8279D PANELS
  M:    Jerry Han <[email protected]>
  S:    Maintained
- F:    Documentation/devicetree/bindings/display/panel/boe,himax8279d.txt
+ F:    Documentation/devicetree/bindings/display/panel/boe,himax8279d.yaml
  F:    drivers/gpu/drm/panel/panel-boe-himax8279d.c
  
  DRM DRIVER FOR FARADAY TVE200 TV ENCODER
@@@ -5318,7 -5300,7 +5318,7 @@@ F:      drivers/gpu/drm/panel/panel-feixin-k
  DRM DRIVER FOR FEIYANG FY07024DI26A30-D MIPI-DSI LCD PANELS
  M:    Jagan Teki <[email protected]>
  S:    Maintained
- F:    Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.txt
+ F:    Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml
  F:    drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
  
  DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
@@@ -5353,6 -5335,14 +5353,14 @@@ S:    Orphan / Obsolet
  F:    drivers/gpu/drm/i810/
  F:    include/uapi/drm/i810_drm.h
  
+ DRM DRIVER FOR LVDS PANELS
+ M:    Laurent Pinchart <[email protected]>
+ L:    [email protected]
+ T:    git git://anongit.freedesktop.org/drm/drm-misc
+ S:    Maintained
+ F:    drivers/gpu/drm/panel/panel-lvds.c
+ F:    Documentation/devicetree/bindings/display/panel/lvds.yaml
  DRM DRIVER FOR MATROX G200/G400 GRAPHICS CARDS
  S:    Orphan / Obsolete
  F:    drivers/gpu/drm/mga/
@@@ -5401,7 -5391,7 +5409,7 @@@ F:      include/uapi/drm/nouveau_drm.
  DRM DRIVER FOR OLIMEX LCD-OLINUXINO PANELS
  M:    Stefan Mavrodiev <[email protected]>
  S:    Maintained
- F:    Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.txt
+ F:    Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.yaml
  F:    drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
  
  DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
@@@ -5418,7 -5408,7 +5426,7 @@@ L:      [email protected]
  S:    Obsolete
  W:    https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
  T:    git git://anongit.freedesktop.org/drm/drm-misc
- F:    drivers/gpu/drm/cirrus/
+ F:    drivers/gpu/drm/tiny/cirrus.c
  
  DRM DRIVER FOR QXL VIRTUAL GPU
  M:    Dave Airlie <[email protected]>
@@@ -5468,7 -5458,7 +5476,7 @@@ F:      drivers/gpu/drm/tiny/st7586.
  DRM DRIVER FOR SITRONIX ST7701 PANELS
  M:    Jagan Teki <[email protected]>
  S:    Maintained
- F:    Documentation/devicetree/bindings/display/panel/sitronix,st7701.txt
+ F:    Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml
  F:    drivers/gpu/drm/panel/panel-sitronix-st7701.c
  
  DRM DRIVER FOR SITRONIX ST7735R PANELS
@@@ -5529,10 -5519,10 +5537,10 @@@ F:   drivers/gpu/drm/vboxvideo
  
  DRM DRIVER FOR VMWARE VIRTUAL GPU
  M:    "VMware Graphics" <[email protected]>
 -M:    Thomas Hellstrom <thellstrom@vmware.com>
 +M:    Roland Scheidegger <sroland@vmware.com>
  L:    [email protected]
  S:    Supported
 -T:    git git://people.freedesktop.org/~thomash/linux
 +T:    git git://people.freedesktop.org/~sroland/linux
  F:    drivers/gpu/drm/vmwgfx/
  F:    include/uapi/drm/vmwgfx_drm.h
  
@@@ -5953,9 -5943,9 +5961,9 @@@ F:      lib/dynamic_debug.
  DYNAMIC INTERRUPT MODERATION
  M:    Tal Gilboa <[email protected]>
  S:    Maintained
 +F:    Documentation/networking/net_dim.rst
  F:    include/linux/dim.h
  F:    lib/dim/
 -F:    Documentation/networking/net_dim.rst
  
  DZ DECSTATION DZ11 SERIAL DRIVER
  M:    "Maciej W. Rozycki" <[email protected]>
@@@ -6194,6 -6184,7 +6202,6 @@@ M:      Yash Shah <[email protected]
  L:    [email protected]
  S:    Supported
  F:    drivers/edac/sifive_edac.c
 -F:    drivers/soc/sifive_l2_cache.c
  
  EDAC-SKYLAKE
  M:    Tony Luck <[email protected]>
@@@ -6734,13 -6725,6 +6742,13 @@@ S:    Maintaine
  F:    Documentation/devicetree/bindings/crypto/fsl-sec4.txt
  F:    drivers/crypto/caam/
  
 +FREESCALE COLDFIRE M5441X MMC DRIVER
 +M:    Angelo Dureghello <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/mmc/host/sdhci-esdhc-mcf.c
 +F:    include/linux/platform_data/mmc-esdhc-mcf.h
 +
  FREESCALE DIU FRAMEBUFFER DRIVER
  M:    Timur Tabi <[email protected]>
  L:    [email protected]
@@@ -7048,24 -7032,13 +7056,24 @@@ R:   Darren Hart <[email protected]
  L:    [email protected]
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
 -F:    Documentation/*futex*
 +F:    Documentation/locking/*futex*
  F:    include/asm-generic/futex.h
  F:    include/linux/futex.h
  F:    include/uapi/linux/futex.h
  F:    kernel/futex.c
  F:    tools/perf/bench/futex*
 -F:    tools/testing/selftests/futex/
 +F:    Documentation/locking/*futex*
 +
 +GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER
 +M:    Tim Harvey <[email protected]>
 +M:    Robert Jones <[email protected]>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
 +F:    drivers/mfd/gateworks-gsc.c
 +F:    include/linux/mfd/gsc.h
 +F:    Documentation/hwmon/gsc-hwmon.rst
 +F:    drivers/hwmon/gsc-hwmon.c
 +F:    include/linux/platform_data/gsc_hwmon.h
  
  GASKET DRIVER FRAMEWORK
  M:    Rob Springer <[email protected]>
@@@ -7154,10 -7127,9 +7162,10 @@@ F:    include/uapi/asm-generic
  
  GENERIC PHY FRAMEWORK
  M:    Kishon Vijay Abraham I <[email protected]>
 +M:    Vinod Koul <[email protected]>
  L:    [email protected]
  S:    Supported
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy.git
  F:    Documentation/devicetree/bindings/phy/
  F:    drivers/phy/
  F:    include/linux/phy/
@@@ -7535,7 -7507,7 +7543,7 @@@ L:      [email protected]
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc.git hwspinlock-next
  F:    Documentation/devicetree/bindings/hwlock/
 -F:    Documentation/hwspinlock.txt
 +F:    Documentation/locking/hwspinlock.rst
  F:    drivers/hwspinlock/
  F:    include/linux/hwspinlock.h
  
@@@ -7768,9 -7740,7 +7776,9 @@@ L:      [email protected]
  S:    Maintained
  F:    Documentation/vm/hmm.rst
  F:    include/linux/hmm*
 +F:    lib/test_hmm*
  F:    mm/hmm*
 +F:    tools/testing/selftests/vm/*hmm*
  
  HOST AP DRIVER
  M:    Jouni Malinen <[email protected]>
  S:    Orphan
  F:    drivers/platform/x86/tc1100-wmi.c
  
 -HP100:        Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
 -M:    Jaroslav Kysela <[email protected]>
 -S:    Obsolete
 -F:    drivers/staging/hp/hp100.*
 -
  HPET: High Precision Event Timers driver
  M:    Clemens Ladisch <[email protected]>
  S:    Maintained
@@@ -7870,7 -7845,7 +7878,7 @@@ T:      git git://linuxtv.org/media_tree.gi
  F:    drivers/media/platform/sti/hva
  
  HWPOISON MEMORY FAILURE HANDLING
 -M:    Naoya Horiguchi <n[email protected].nec.com>
 +M:    Naoya Horiguchi <naoya.horiguchi@nec.com>
  L:    [email protected]
  S:    Maintained
  F:    mm/hwpoison-inject.c
@@@ -7982,7 -7957,7 +7990,7 @@@ F:      Documentation/i2c/busses/i2c-parport
  F:    drivers/i2c/busses/i2c-parport.c
  
  I2C SUBSYSTEM
 -M:    Wolfram Sang <wsa@the-dreams.de>
 +M:    Wolfram Sang <wsa@kernel.org>
  L:    [email protected]
  S:    Maintained
  W:    https://i2c.wiki.kernel.org/
  S:    Maintained
  F:    drivers/platform/x86/intel_atomisp2_pm.c
  
 +INTEL BROXTON PMC DRIVER
 +M:    Mika Westerberg <[email protected]>
 +M:    Zha Qipeng <[email protected]>
 +S:    Maintained
 +F:    drivers/mfd/intel_pmc_bxt.c
 +F:    include/linux/mfd/intel_pmc_bxt.h
 +
  INTEL C600 SERIES SAS CONTROLLER DRIVER
  M:    Intel SCU Linux support <[email protected]>
  M:    Artur Paszkiewicz <[email protected]>
@@@ -8746,13 -8714,6 +8754,13 @@@ F:    include/uapi/linux/mic_common.
  F:    include/uapi/linux/mic_ioctl.h
  F:    include/uapi/linux/scif_ioctl.h
  
 +INTEL P-Unit IPC DRIVER
 +M:    Zha Qipeng <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    arch/x86/include/asm/intel_punit_ipc.h
 +F:    drivers/platform/x86/intel_punit_ipc.c
 +
  INTEL PMC CORE DRIVER
  M:    Rajneesh Bhardwaj <[email protected]>
  M:    Vishwanath Somayaji <[email protected]>
  S:    Maintained
  F:    drivers/platform/x86/intel_pmc_core*
  
 -INTEL PMC/P-Unit IPC DRIVER
 -M:    Zha Qipeng<[email protected]>
 -L:    [email protected]
 -S:    Maintained
 -F:    arch/x86/include/asm/intel_pmc_ipc.h
 -F:    arch/x86/include/asm/intel_punit_ipc.h
 -F:    drivers/platform/x86/intel_pmc_ipc.c
 -F:    drivers/platform/x86/intel_punit_ipc.c
 -
  INTEL PMIC GPIO DRIVERS
  M:    Andy Shevchenko <[email protected]>
  S:    Maintained
@@@ -8798,12 -8768,6 +8806,12 @@@ S:    Supporte
  F:    drivers/infiniband/hw/i40iw/
  F:    include/uapi/rdma/i40iw-abi.h
  
 +INTEL SCU DRIVERS
 +M:    Mika Westerberg <[email protected]>
 +S:    Maintained
 +F:    arch/x86/include/asm/intel_scu_ipc.h
 +F:    drivers/platform/x86/intel_scu_*
 +
  INTEL SPEED SELECT TECHNOLOGY
  M:    Srinivas Pandruvada <[email protected]>
  L:    [email protected]
@@@ -8870,13 -8834,6 +8878,13 @@@ F:    Documentation/admin-guide/wimax/i240
  F:    drivers/net/wimax/i2400m/
  F:    include/uapi/linux/wimax/i2400m.h
  
 +INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER
 +M:    Jithu Joseph <[email protected]>
 +R:    Maurice Ma <[email protected]>
 +S:    Maintained
 +W:    https://slimbootloader.github.io/security/firmware-update.html
 +F:    drivers/platform/x86/intel-wmi-sbl-fw-update.c
 +
  INTEL WMI THUNDERBOLT FORCE POWER DRIVER
  M:    Mario Limonciello <[email protected]>
  S:    Maintained
@@@ -8962,7 -8919,7 +8970,7 @@@ M:      Corey Minyard <[email protected]
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  W:    http://openipmi.sourceforge.net/
 -F:    Documentation/IPMI.txt
 +F:    Documentation/driver-api/ipmi.rst
  F:    Documentation/devicetree/bindings/ipmi/
  F:    drivers/char/ipmi/
  F:    include/linux/ipmi*
@@@ -9004,7 -8961,7 +9012,7 @@@ IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY
  M:    Marc Zyngier <[email protected]>
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
 -F:    Documentation/IRQ-domain.txt
 +F:    Documentation/core-api/irq/irq-domain.rst
  F:    include/linux/irqdomain.h
  F:    kernel/irq/irqdomain.c
  F:    kernel/irq/msi.c
  S:    Maintained
  W:    http://lse.sourceforge.net/kdump/
  F:    Documentation/admin-guide/kdump/
 +F:    fs/proc/vmcore.c
 +F:    include/linux/crash_core.h
 +F:    include/linux/crash_dump.h
 +F:    include/uapi/linux/vmcore.h
 +F:    kernel/crash_*.c
  
  KEENE FM RADIO TRANSMITTER DRIVER
  M:    Hans Verkuil <[email protected]>
@@@ -9385,7 -9337,6 +9393,7 @@@ M:      Christian Borntraeger <borntraeger@d
  M:    Janosch Frank <[email protected]>
  R:    David Hildenbrand <[email protected]>
  R:    Cornelia Huck <[email protected]>
 +R:    Claudio Imbrenda <[email protected]>
  L:    [email protected]
  S:    Supported
  W:    http://www.ibm.com/developerworks/linux/linux390/
@@@ -9473,13 -9424,6 +9481,13 @@@ F:    include/linux/keyctl.
  F:    include/uapi/linux/keyctl.h
  F:    security/keys/
  
 +KFIFO
 +M:    Stefani Seibold <[email protected]>
 +S:    Maintained
 +F:    include/linux/kfifo.h
 +F:    lib/kfifo.c
 +F:    samples/kfifo/
 +
  KGDB / KDB /debug_core
  M:    Jason Wessel <[email protected]>
  M:    Daniel Thompson <[email protected]>
@@@ -9784,13 -9728,6 +9792,13 @@@ F:    drivers/lightnvm
  F:    include/linux/lightnvm.h
  F:    include/uapi/linux/lightnvm.h
  
 +LINEAR RANGES HELPERS
 +M:    Mark Brown <[email protected]>
 +R:    Matti Vaittinen <[email protected]>
 +F:    lib/linear_ranges.c
 +F:    lib/test_linear_ranges.c
 +F:    include/linux/linear_range.h
 +
  LINUX FOR POWER MACINTOSH
  M:    Benjamin Herrenschmidt <[email protected]>
  L:    [email protected]
@@@ -10138,7 -10075,7 +10146,7 @@@ MAC8021
  M:    Johannes Berg <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/
 +W:    https://wireless.wiki.kernel.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
  F:    Documentation/networking/mac80211-injection.txt
  S:    Maintained
  F:    drivers/net/ethernet/mediatek/
  
 +MEDIATEK I2C CONTROLLER DRIVER
 +M:    Qii Wang <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/i2c/i2c-mt65xx.txt
 +F:    drivers/i2c/busses/i2c-mt65xx.c
 +
  MEDIATEK JPEG DRIVER
  M:    Rick Chang <[email protected]>
  M:    Bin Liu <[email protected]>
@@@ -10775,6 -10705,7 +10783,6 @@@ MEDIATEK MT76 WIRELESS LAN DRIVE
  M:    Felix Fietkau <[email protected]>
  M:    Lorenzo Bianconi <[email protected]>
  R:    Ryder Lee <[email protected]>
 -R:    Roy Luo <[email protected]>
  L:    [email protected]
  S:    Maintained
  F:    drivers/net/wireless/mediatek/mt76/
@@@ -11788,9 -11719,8 +11796,9 @@@ F:   net/core/drop_monitor.
  
  NETWORKING DRIVERS
  M:    "David S. Miller" <[email protected]>
 +M:    Jakub Kicinski <[email protected]>
  L:    [email protected]
 -S:    Odd Fixes
 +S:    Maintained
  W:    http://www.linuxfoundation.org/en/Net
  Q:    http://patchwork.ozlabs.org/project/netdev/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git
@@@ -12726,7 -12656,7 +12734,7 @@@ F:   fs/orangefs
  ORINOCO DRIVER
  L:    [email protected]
  S:    Orphan
 -W:    http://wireless.kernel.org/en/users/Drivers/orinoco
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/orinoco
  W:    http://www.nongnu.org/orinoco/
  F:    drivers/net/wireless/intersil/orinoco/
  
@@@ -12752,7 -12682,7 +12760,7 @@@ P54 WIRELESS DRIVE
  M:    Christian Lamparter <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/en/users/Drivers/p54
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/p54
  F:    drivers/net/wireless/intersil/p54/
  
  PACKING
@@@ -13120,7 -13050,7 +13128,7 @@@ F:   drivers/pci/controller/pci-xgene-msi
  
  PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
  M:    Lorenzo Pieralisi <[email protected]>
 -R:    Andrew Murray <[email protected]>
 +R:    Rob Herring <[email protected]>
  L:    [email protected]
  S:    Supported
  Q:    http://patchwork.ozlabs.org/project/linux-pci/list/
@@@ -13673,7 -13603,7 +13681,7 @@@ PRISM54 WIRELESS DRIVE
  M:    Luis Chamberlain <[email protected]>
  L:    [email protected]
  S:    Obsolete
 -W:    http://wireless.kernel.org/en/users/Drivers/p54
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/p54
  F:    drivers/net/wireless/intersil/prism54/
  
  PROC FILESYSTEM
@@@ -13742,7 -13672,6 +13750,7 @@@ M:   Tony Luck <[email protected]
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/pstore
  F:    Documentation/admin-guide/ramoops.rst
 +F:    Documentation/admin-guide/pstore-blk.rst
  F:    Documentation/devicetree/bindings/reserved-memory/ramoops.txt
  F:    drivers/acpi/apei/erst.c
  F:    drivers/firmware/efi/efi-pstore.c
@@@ -14015,7 -13944,7 +14023,7 @@@ QUALCOMM ATHEROS ATH10K WIRELESS DRIVE
  M:    Kalle Valo <[email protected]>
  L:    [email protected]
  S:    Supported
 -W:    http://wireless.kernel.org/en/users/Drivers/ath10k
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
  F:    drivers/net/wireless/ath/ath10k/
  
@@@ -14030,7 -13959,7 +14038,7 @@@ QUALCOMM ATHEROS ATH9K WIRELESS DRIVE
  M:    QCA ath9k Development <[email protected]>
  L:    [email protected]
  S:    Supported
 -W:    http://wireless.kernel.org/en/users/Drivers/ath9k
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/ath9k
  F:    drivers/net/wireless/ath/ath9k/
  
  QUALCOMM CAMERA SUBSYSTEM DRIVER
@@@ -14127,12 -14056,13 +14135,12 @@@ QUALCOMM WCN36XX WIRELESS DRIVE
  M:    Kalle Valo <[email protected]>
  L:    [email protected]
  S:    Supported
 -W:    http://wireless.kernel.org/en/users/Drivers/wcn36xx
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/wcn36xx
  T:    git git://github.com/KrasnikovEugene/wcn36xx.git
  F:    drivers/net/wireless/ath/wcn36xx/
  
  QUANTENNA QTNFMAC WIRELESS DRIVER
  M:    Igor Mitsyanko <[email protected]>
 -M:    Avinash Patil <[email protected]>
  M:    Sergey Matyukevich <[email protected]>
  L:    [email protected]
  S:    Maintained
@@@ -14141,7 -14071,6 +14149,6 @@@ F:   drivers/net/wireless/quantenn
  RADEON and AMDGPU DRM DRIVERS
  M:    Alex Deucher <[email protected]>
  M:    Christian König <[email protected]>
- M:    David (ChunMing) Zhou <[email protected]>
  L:    [email protected]
  S:    Supported
  T:    git git://people.freedesktop.org/~agd5f/linux
@@@ -14174,10 -14103,12 +14181,10 @@@ F:        drivers/media/radio/radio-tea5777.
  
  RADOS BLOCK DEVICE (RBD)
  M:    Ilya Dryomov <[email protected]>
 -M:    Sage Weil <[email protected]>
  R:    Dongsheng Yang <[email protected]>
  L:    [email protected]
  S:    Supported
  W:    http://ceph.com/
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
  T:    git git://github.com/ceph/ceph-client.git
  F:    Documentation/ABI/testing/sysfs-bus-rbd
  F:    drivers/block/rbd.c
@@@ -14297,7 -14228,7 +14304,7 @@@ M:   Reinette Chatre <reinette.chatre@int
  L:    [email protected]
  S:    Supported
  F:    Documentation/x86/resctrl*
 -F:    arch/x86/include/asm/resctrl_sched.h
 +F:    arch/x86/include/asm/resctrl.h
  F:    arch/x86/kernel/cpu/resctrl/
  F:    tools/testing/selftests/resctrl/
  
@@@ -14352,7 -14283,7 +14359,7 @@@ REALTEK WIRELESS DRIVER (rtlwifi family
  M:    Ping-Ke Shih <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/
 +W:    https://wireless.wiki.kernel.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
  F:    drivers/net/wireless/realtek/rtlwifi/
  
@@@ -14487,7 -14418,7 +14494,7 @@@ RFKIL
  M:    Johannes Berg <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/
 +W:    https://wireless.wiki.kernel.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
  F:    Documentation/ABI/stable/sysfs-class-rfkill
@@@ -14636,7 -14567,7 +14643,7 @@@ F:   drivers/media/dvb-frontends/rtl2832_
  RTL8180 WIRELESS DRIVER
  L:    [email protected]
  S:    Orphan
 -W:    http://wireless.kernel.org/
 +W:    https://wireless.wiki.kernel.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
  F:    drivers/net/wireless/realtek/rtl818x/rtl8180/
  
@@@ -14646,7 -14577,7 +14653,7 @@@ M:   Hin-Tak Leung <[email protected]
  M:    Larry Finger <[email protected]>
  L:    [email protected]
  S:    Maintained
 -W:    http://wireless.kernel.org/
 +W:    https://wireless.wiki.kernel.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
  F:    drivers/net/wireless/realtek/rtl818x/rtl8187/
  
@@@ -14714,7 -14645,6 +14721,7 @@@ F:   drivers/iommu/s390-iommu.
  
  S390 IUCV NETWORK LAYER
  M:    Julian Wiedmann <[email protected]>
 +M:    Karsten Graul <[email protected]>
  M:    Ursula Braun <[email protected]>
  L:    [email protected]
  S:    Supported
@@@ -14725,7 -14655,6 +14732,7 @@@ F:   net/iucv
  
  S390 NETWORK DRIVERS
  M:    Julian Wiedmann <[email protected]>
 +M:    Karsten Graul <[email protected]>
  M:    Ursula Braun <[email protected]>
  L:    [email protected]
  S:    Supported
@@@ -15546,15 -15475,6 +15553,15 @@@ M: Nicolas Pitre <[email protected]
  S:    Odd Fixes
  F:    drivers/net/ethernet/smsc/smc91x.*
  
 +SECURE MONITOR CALL(SMC) CALLING CONVENTION (SMCCC)
 +M:    Mark Rutland <[email protected]>
 +M:    Lorenzo Pieralisi <[email protected]>
 +M:    Sudeep Holla <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/firmware/smccc/
 +F:    include/linux/arm-smccc.h
 +
  SMIA AND SMIA++ IMAGE SENSOR DRIVER
  M:    Sakari Ailus <[email protected]>
  L:    [email protected]
@@@ -15731,7 -15651,7 +15738,7 @@@ F:   drivers/ssb
  F:    include/linux/ssb/
  
  SONY IMX214 SENSOR DRIVER
 -M:    Ricardo Ribalda <ri[email protected]>
 +M:    Ricardo Ribalda <ri[email protected]>
  L:    [email protected]
  S:    Maintained
  T:    git git://linuxtv.org/media_tree.git
@@@ -15971,7 -15891,7 +15978,7 @@@ M:   Jeremy Kerr <[email protected]
  L:    [email protected]
  S:    Supported
  W:    http://www.ibm.com/developerworks/power/cell/
 -F:    Documentation/filesystems/spufs.txt
 +F:    Documentation/filesystems/spufs/spufs.rst
  F:    arch/powerpc/platforms/cell/spufs/
  
  SQUASHFS FILE SYSTEM
@@@ -16718,7 -16638,7 +16725,7 @@@ S:   Maintaine
  F:    sound/soc/ti/
  
  TEXAS INSTRUMENTS' DAC7612 DAC DRIVER
 -M:    Ricardo Ribalda <ri[email protected]>
 +M:    Ricardo Ribalda <ri[email protected]>
  L:    [email protected]
  S:    Supported
  F:    Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
@@@ -17012,8 -16932,8 +17019,8 @@@ F:   drivers/media/platform/ti-vpe
  TI WILINK WIRELESS DRIVERS
  L:    [email protected]
  S:    Orphan
 -W:    http://wireless.kernel.org/en/users/Drivers/wl12xx
 -W:    http://wireless.kernel.org/en/users/Drivers/wl1251
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/wl12xx
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/wl1251
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/luca/wl12xx.git
  F:    drivers/net/wireless/ti/
  F:    include/linux/wl12xx.h
@@@ -18295,7 -18215,7 +18302,7 @@@ M:   Maya Erez <[email protected]
  L:    [email protected]
  L:    [email protected]
  S:    Supported
 -W:    http://wireless.kernel.org/en/users/Drivers/wil6210
 +W:    https://wireless.wiki.kernel.org/en/users/Drivers/wil6210
  F:    drivers/net/wireless/ath/wil6210/
  
  WIMAX STACK
@@@ -18622,8 -18542,8 +18629,8 @@@ W:   http://xfs.org
  T:    git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git
  F:    Documentation/ABI/testing/sysfs-fs-xfs
  F:    Documentation/admin-guide/xfs.rst
 -F:    Documentation/filesystems/xfs-delayed-logging-design.txt
 -F:    Documentation/filesystems/xfs-self-describing-metadata.txt
 +F:    Documentation/filesystems/xfs-delayed-logging-design.rst
 +F:    Documentation/filesystems/xfs-self-describing-metadata.rst
  F:    fs/xfs/
  F:    include/uapi/linux/dqblk_xfs.h
  F:    include/uapi/linux/fsmap.h
index 07df88f2e3057e0c9def11f24b3d430823d30350,570c923023e65dba5b83b78b7963f7315ca06cb0..01ce125f8e8d8a864b82657f095923da4cfa2715
@@@ -388,8 -388,7 +388,8 @@@ static long dma_buf_ioctl(struct file *
  
                return ret;
  
 -      case DMA_BUF_SET_NAME:
 +      case DMA_BUF_SET_NAME_A:
 +      case DMA_BUF_SET_NAME_B:
                return dma_buf_set_name(dmabuf, (const char __user *)arg);
  
        default:
@@@ -656,8 -655,8 +656,8 @@@ EXPORT_SYMBOL_GPL(dma_buf_put)
   * calls attach() of dma_buf_ops to allow device-specific attach functionality
   * @dmabuf:           [in]    buffer to attach device to.
   * @dev:              [in]    device to be attached.
 - * @importer_ops      [in]    importer operations for the attachment
 - * @importer_priv     [in]    importer private pointer for the attachment
 + * @importer_ops:     [in]    importer operations for the attachment
 + * @importer_priv:    [in]    importer private pointer for the attachment
   *
   * Returns struct dma_buf_attachment pointer for this attachment. Attachments
   * must be cleaned up by calling dma_buf_detach().
@@@ -691,6 -690,8 +691,8 @@@ dma_buf_dynamic_attach(struct dma_buf *
  
        attach->dev = dev;
        attach->dmabuf = dmabuf;
+       if (importer_ops)
+               attach->peer2peer = importer_ops->allow_peer2peer;
        attach->importer_ops = importer_ops;
        attach->importer_priv = importer_priv;
  
diff --combined drivers/gpu/drm/Kconfig
index fb92be7e8aa71b2d4f5bfa7f70fa9058a6f45240,4f4e7fa001c15b0b47272772096a8d7865b1b31e..c4fd57d8b717cefe95042561a1f9c3ac24775d82
@@@ -161,7 -161,7 +161,7 @@@ config DRM_LOAD_EDID_FIRMWAR
          monitor are unable to provide appropriate EDID data. Since this
          feature is provided as a workaround for broken hardware, the
          default case is N. Details and instructions how to build your own
 -        EDID data are given in Documentation/driver-api/edid.rst.
 +        EDID data are given in Documentation/admin-guide/edid.rst.
  
  config DRM_DP_CEC
        bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support"
@@@ -310,8 -310,6 +310,6 @@@ source "drivers/gpu/drm/ast/Kconfig
  
  source "drivers/gpu/drm/mgag200/Kconfig"
  
- source "drivers/gpu/drm/cirrus/Kconfig"
  source "drivers/gpu/drm/armada/Kconfig"
  
  source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
index a9086ea1ab60e9bd0047942a7fde7fbaa773d831,682a514f17944c6a2edd72467c5f2a44caf4023e..d7e17e34fee171a2d103fe79a2fc27ac9d68c95c
@@@ -183,18 -183,18 +183,18 @@@ int amdgpu_driver_load_kms(struct drm_d
        /* Call ACPI methods: require modeset init
         * but failure is not fatal
         */
-       if (!r) {
-               acpi_status = amdgpu_acpi_init(adev);
-               if (acpi_status)
-                       dev_dbg(&dev->pdev->dev,
-                               "Error during ACPI methods call\n");
-       }
+       acpi_status = amdgpu_acpi_init(adev);
+       if (acpi_status)
+               dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n");
  
        if (adev->runpm) {
-               dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
+               /* only need to skip on ATPX */
+               if (amdgpu_device_supports_boco(dev) &&
+                   !amdgpu_is_atpx_hybrid())
 -                      dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NEVER_SKIP);
++                      dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
                pm_runtime_use_autosuspend(dev->dev);
                pm_runtime_set_autosuspend_delay(dev->dev, 5000);
-               pm_runtime_set_active(dev->dev);
                pm_runtime_allow(dev->dev);
                pm_runtime_mark_last_busy(dev->dev);
                pm_runtime_put_autosuspend(dev->dev);
index b1c62da527c59bf742e75d2a1b4a28b731941ae8,eff1f73302de9da22ef1e3b8456b304c81c16bed..9cbecd5ba814be0bc5a499dd1bcb54d16374bdd0
  
  #define AMDGPU_TTM_VRAM_MAX_DW_READ   (size_t)128
  
- static int amdgpu_map_buffer(struct ttm_buffer_object *bo,
-                            struct ttm_mem_reg *mem, unsigned num_pages,
-                            uint64_t offset, unsigned window,
-                            struct amdgpu_ring *ring,
-                            uint64_t *addr);
  
  /**
   * amdgpu_init_mem_type - Initialize a memory manager for a specific type of
@@@ -277,7 -272,7 +272,7 @@@ static uint64_t amdgpu_mm_node_addr(str
   *
   */
  static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_mem_reg *mem,
-                                              unsigned long *offset)
+                                              uint64_t *offset)
  {
        struct drm_mm_node *mm_node = mem->mm_node;
  
        return mm_node;
  }
  
+ /**
+  * amdgpu_ttm_map_buffer - Map memory into the GART windows
+  * @bo: buffer object to map
+  * @mem: memory object to map
+  * @mm_node: drm_mm node object to map
+  * @num_pages: number of pages to map
+  * @offset: offset into @mm_node where to start
+  * @window: which GART window to use
+  * @ring: DMA ring to use for the copy
+  * @tmz: if we should setup a TMZ enabled mapping
+  * @addr: resulting address inside the MC address space
+  *
+  * Setup one of the GART windows to access a specific piece of memory or return
+  * the physical address for local memory.
+  */
+ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
+                                struct ttm_mem_reg *mem,
+                                struct drm_mm_node *mm_node,
+                                unsigned num_pages, uint64_t offset,
+                                unsigned window, struct amdgpu_ring *ring,
+                                bool tmz, uint64_t *addr)
+ {
+       struct amdgpu_device *adev = ring->adev;
+       struct amdgpu_job *job;
+       unsigned num_dw, num_bytes;
+       struct dma_fence *fence;
+       uint64_t src_addr, dst_addr;
+       void *cpu_addr;
+       uint64_t flags;
+       unsigned int i;
+       int r;
+       BUG_ON(adev->mman.buffer_funcs->copy_max_bytes <
+              AMDGPU_GTT_MAX_TRANSFER_SIZE * 8);
+       /* Map only what can't be accessed directly */
+       if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) {
+               *addr = amdgpu_mm_node_addr(bo, mm_node, mem) + offset;
+               return 0;
+       }
+       *addr = adev->gmc.gart_start;
+       *addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE *
+               AMDGPU_GPU_PAGE_SIZE;
+       *addr += offset & ~PAGE_MASK;
+       num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
+       num_bytes = num_pages * 8;
+       r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes,
+                                    AMDGPU_IB_POOL_DELAYED, &job);
+       if (r)
+               return r;
+       src_addr = num_dw * 4;
+       src_addr += job->ibs[0].gpu_addr;
+       dst_addr = amdgpu_bo_gpu_offset(adev->gart.bo);
+       dst_addr += window * AMDGPU_GTT_MAX_TRANSFER_SIZE * 8;
+       amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr,
+                               dst_addr, num_bytes, false);
+       amdgpu_ring_pad_ib(ring, &job->ibs[0]);
+       WARN_ON(job->ibs[0].length_dw > num_dw);
+       flags = amdgpu_ttm_tt_pte_flags(adev, bo->ttm, mem);
+       if (tmz)
+               flags |= AMDGPU_PTE_TMZ;
+       cpu_addr = &job->ibs[0].ptr[num_dw];
+       if (mem->mem_type == TTM_PL_TT) {
+               struct ttm_dma_tt *dma;
+               dma_addr_t *dma_address;
+               dma = container_of(bo->ttm, struct ttm_dma_tt, ttm);
+               dma_address = &dma->dma_address[offset >> PAGE_SHIFT];
+               r = amdgpu_gart_map(adev, 0, num_pages, dma_address, flags,
+                                   cpu_addr);
+               if (r)
+                       goto error_free;
+       } else {
+               dma_addr_t dma_address;
+               dma_address = (mm_node->start << PAGE_SHIFT) + offset;
+               dma_address += adev->vm_manager.vram_base_offset;
+               for (i = 0; i < num_pages; ++i) {
+                       r = amdgpu_gart_map(adev, i << PAGE_SHIFT, 1,
+                                           &dma_address, flags, cpu_addr);
+                       if (r)
+                               goto error_free;
+                       dma_address += PAGE_SIZE;
+               }
+       }
+       r = amdgpu_job_submit(job, &adev->mman.entity,
+                             AMDGPU_FENCE_OWNER_UNDEFINED, &fence);
+       if (r)
+               goto error_free;
+       dma_fence_put(fence);
+       return r;
+ error_free:
+       amdgpu_job_free(job);
+       return r;
+ }
  /**
   * amdgpu_copy_ttm_mem_to_mem - Helper function for copy
+  * @adev: amdgpu device
+  * @src: buffer/address where to read from
+  * @dst: buffer/address where to write to
+  * @size: number of bytes to copy
+  * @tmz: if a secure copy should be used
+  * @resv: resv object to sync to
+  * @f: Returns the last fence if multiple jobs are submitted.
   *
   * The function copies @size bytes from {src->mem + src->offset} to
   * {dst->mem + dst->offset}. src->bo and dst->bo could be same BO for a
   * move and different for a BO to BO copy.
   *
-  * @f: Returns the last fence if multiple jobs are submitted.
   */
  int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
-                              struct amdgpu_copy_mem *src,
-                              struct amdgpu_copy_mem *dst,
-                              uint64_t size,
+                              const struct amdgpu_copy_mem *src,
+                              const struct amdgpu_copy_mem *dst,
+                              uint64_t size, bool tmz,
                               struct dma_resv *resv,
                               struct dma_fence **f)
  {
+       const uint32_t GTT_MAX_BYTES = (AMDGPU_GTT_MAX_TRANSFER_SIZE *
+                                       AMDGPU_GPU_PAGE_SIZE);
+       uint64_t src_node_size, dst_node_size, src_offset, dst_offset;
        struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
        struct drm_mm_node *src_mm, *dst_mm;
-       uint64_t src_node_start, dst_node_start, src_node_size,
-                dst_node_size, src_page_offset, dst_page_offset;
        struct dma_fence *fence = NULL;
        int r = 0;
-       const uint64_t GTT_MAX_BYTES = (AMDGPU_GTT_MAX_TRANSFER_SIZE *
-                                       AMDGPU_GPU_PAGE_SIZE);
  
        if (!adev->mman.buffer_funcs_enabled) {
                DRM_ERROR("Trying to move memory with ring turned off.\n");
                return -EINVAL;
        }
  
-       src_mm = amdgpu_find_mm_node(src->mem, &src->offset);
-       src_node_start = amdgpu_mm_node_addr(src->bo, src_mm, src->mem) +
-                                            src->offset;
-       src_node_size = (src_mm->size << PAGE_SHIFT) - src->offset;
-       src_page_offset = src_node_start & (PAGE_SIZE - 1);
+       src_offset = src->offset;
+       src_mm = amdgpu_find_mm_node(src->mem, &src_offset);
+       src_node_size = (src_mm->size << PAGE_SHIFT) - src_offset;
  
-       dst_mm = amdgpu_find_mm_node(dst->mem, &dst->offset);
-       dst_node_start = amdgpu_mm_node_addr(dst->bo, dst_mm, dst->mem) +
-                                            dst->offset;
-       dst_node_size = (dst_mm->size << PAGE_SHIFT) - dst->offset;
-       dst_page_offset = dst_node_start & (PAGE_SIZE - 1);
+       dst_offset = dst->offset;
+       dst_mm = amdgpu_find_mm_node(dst->mem, &dst_offset);
+       dst_node_size = (dst_mm->size << PAGE_SHIFT) - dst_offset;
  
        mutex_lock(&adev->mman.gtt_window_lock);
  
        while (size) {
-               unsigned long cur_size;
-               uint64_t from = src_node_start, to = dst_node_start;
+               uint32_t src_page_offset = src_offset & ~PAGE_MASK;
+               uint32_t dst_page_offset = dst_offset & ~PAGE_MASK;
                struct dma_fence *next;
+               uint32_t cur_size;
+               uint64_t from, to;
  
                /* Copy size cannot exceed GTT_MAX_BYTES. So if src or dst
                 * begins at an offset, then adjust the size accordingly
                 */
-               cur_size = min3(min(src_node_size, dst_node_size), size,
-                               GTT_MAX_BYTES);
-               if (cur_size + src_page_offset > GTT_MAX_BYTES ||
-                   cur_size + dst_page_offset > GTT_MAX_BYTES)
-                       cur_size -= max(src_page_offset, dst_page_offset);
-               /* Map only what needs to be accessed. Map src to window 0 and
-                * dst to window 1
-                */
-               if (src->mem->start == AMDGPU_BO_INVALID_OFFSET) {
-                       r = amdgpu_map_buffer(src->bo, src->mem,
-                                       PFN_UP(cur_size + src_page_offset),
-                                       src_node_start, 0, ring,
-                                       &from);
-                       if (r)
-                               goto error;
-                       /* Adjust the offset because amdgpu_map_buffer returns
-                        * start of mapped page
-                        */
-                       from += src_page_offset;
-               }
+               cur_size = max(src_page_offset, dst_page_offset);
+               cur_size = min(min3(src_node_size, dst_node_size, size),
+                              (uint64_t)(GTT_MAX_BYTES - cur_size));
+               /* Map src to window 0 and dst to window 1. */
+               r = amdgpu_ttm_map_buffer(src->bo, src->mem, src_mm,
+                                         PFN_UP(cur_size + src_page_offset),
+                                         src_offset, 0, ring, tmz, &from);
+               if (r)
+                       goto error;
  
-               if (dst->mem->start == AMDGPU_BO_INVALID_OFFSET) {
-                       r = amdgpu_map_buffer(dst->bo, dst->mem,
-                                       PFN_UP(cur_size + dst_page_offset),
-                                       dst_node_start, 1, ring,
-                                       &to);
-                       if (r)
-                               goto error;
-                       to += dst_page_offset;
-               }
+               r = amdgpu_ttm_map_buffer(dst->bo, dst->mem, dst_mm,
+                                         PFN_UP(cur_size + dst_page_offset),
+                                         dst_offset, 1, ring, tmz, &to);
+               if (r)
+                       goto error;
  
                r = amdgpu_copy_buffer(ring, from, to, cur_size,
-                                      resv, &next, false, true);
+                                      resv, &next, false, true, tmz);
                if (r)
                        goto error;
  
  
                src_node_size -= cur_size;
                if (!src_node_size) {
-                       src_node_start = amdgpu_mm_node_addr(src->bo, ++src_mm,
-                                                            src->mem);
-                       src_node_size = (src_mm->size << PAGE_SHIFT);
-                       src_page_offset = 0;
+                       ++src_mm;
+                       src_node_size = src_mm->size << PAGE_SHIFT;
+                       src_offset = 0;
                } else {
-                       src_node_start += cur_size;
-                       src_page_offset = src_node_start & (PAGE_SIZE - 1);
+                       src_offset += cur_size;
                }
                dst_node_size -= cur_size;
                if (!dst_node_size) {
-                       dst_node_start = amdgpu_mm_node_addr(dst->bo, ++dst_mm,
-                                                            dst->mem);
-                       dst_node_size = (dst_mm->size << PAGE_SHIFT);
-                       dst_page_offset = 0;
+                       ++dst_mm;
+                       dst_node_size = dst_mm->size << PAGE_SHIFT;
+                       dst_offset = 0;
                } else {
-                       dst_node_start += cur_size;
-                       dst_page_offset = dst_node_start & (PAGE_SIZE - 1);
+                       dst_offset += cur_size;
                }
        }
  error:
@@@ -425,6 -517,7 +517,7 @@@ static int amdgpu_move_blit(struct ttm_
                            struct ttm_mem_reg *old_mem)
  {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
+       struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
        struct amdgpu_copy_mem src, dst;
        struct dma_fence *fence = NULL;
        int r;
  
        r = amdgpu_ttm_copy_mem_to_mem(adev, &src, &dst,
                                       new_mem->num_pages << PAGE_SHIFT,
+                                      amdgpu_bo_encrypted(abo),
                                       bo->base.resv, &fence);
        if (r)
                goto error;
  
        /* clear the space being freed */
        if (old_mem->mem_type == TTM_PL_VRAM &&
-           (ttm_to_amdgpu_bo(bo)->flags &
-            AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) {
+           (abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) {
                struct dma_fence *wipe_fence = NULL;
  
                r = amdgpu_fill_buffer(ttm_to_amdgpu_bo(bo), AMDGPU_POISON,
@@@ -742,8 -835,8 +835,8 @@@ static void amdgpu_ttm_io_mem_free(stru
  static unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
                                           unsigned long page_offset)
  {
+       uint64_t offset = (page_offset << PAGE_SHIFT);
        struct drm_mm_node *mm;
-       unsigned long offset = (page_offset << PAGE_SHIFT);
  
        mm = amdgpu_find_mm_node(&bo->mem, &offset);
        return (bo->mem.bus.base >> PAGE_SHIFT) + mm->start +
@@@ -766,6 -859,18 +859,6 @@@ struct amdgpu_ttm_tt 
  };
  
  #ifdef CONFIG_DRM_AMDGPU_USERPTR
 -/* flags used by HMM internal, not related to CPU/GPU PTE flags */
 -static const uint64_t hmm_range_flags[HMM_PFN_FLAG_MAX] = {
 -      (1 << 0), /* HMM_PFN_VALID */
 -      (1 << 1), /* HMM_PFN_WRITE */
 -};
 -
 -static const uint64_t hmm_range_values[HMM_PFN_VALUE_MAX] = {
 -      0xfffffffffffffffeUL, /* HMM_PFN_ERROR */
 -      0, /* HMM_PFN_NONE */
 -      0xfffffffffffffffcUL /* HMM_PFN_SPECIAL */
 -};
 -
  /**
   * amdgpu_ttm_tt_get_user_pages - get device accessible pages that back user
   * memory and start HMM tracking CPU page table update
@@@ -804,15 -909,18 +897,15 @@@ int amdgpu_ttm_tt_get_user_pages(struc
                goto out;
        }
        range->notifier = &bo->notifier;
 -      range->flags = hmm_range_flags;
 -      range->values = hmm_range_values;
 -      range->pfn_shift = PAGE_SHIFT;
        range->start = bo->notifier.interval_tree.start;
        range->end = bo->notifier.interval_tree.last + 1;
 -      range->default_flags = hmm_range_flags[HMM_PFN_VALID];
 +      range->default_flags = HMM_PFN_REQ_FAULT;
        if (!amdgpu_ttm_tt_is_readonly(ttm))
 -              range->default_flags |= range->flags[HMM_PFN_WRITE];
 +              range->default_flags |= HMM_PFN_REQ_WRITE;
  
 -      range->pfns = kvmalloc_array(ttm->num_pages, sizeof(*range->pfns),
 -                                   GFP_KERNEL);
 -      if (unlikely(!range->pfns)) {
 +      range->hmm_pfns = kvmalloc_array(ttm->num_pages,
 +                                       sizeof(*range->hmm_pfns), GFP_KERNEL);
 +      if (unlikely(!range->hmm_pfns)) {
                r = -ENOMEM;
                goto out_free_ranges;
        }
@@@ -837,23 -945,27 +930,23 @@@ retry
        down_read(&mm->mmap_sem);
        r = hmm_range_fault(range);
        up_read(&mm->mmap_sem);
 -      if (unlikely(r <= 0)) {
 +      if (unlikely(r)) {
                /*
                 * FIXME: This timeout should encompass the retry from
                 * mmu_interval_read_retry() as well.
                 */
 -              if ((r == 0 || r == -EBUSY) && !time_after(jiffies, timeout))
 +              if (r == -EBUSY && !time_after(jiffies, timeout))
                        goto retry;
                goto out_free_pfns;
        }
  
 -      for (i = 0; i < ttm->num_pages; i++) {
 -              /* FIXME: The pages cannot be touched outside the notifier_lock */
 -              pages[i] = hmm_device_entry_to_page(range, range->pfns[i]);
 -              if (unlikely(!pages[i])) {
 -                      pr_err("Page fault failed for pfn[%lu] = 0x%llx\n",
 -                             i, range->pfns[i]);
 -                      r = -ENOMEM;
 -
 -                      goto out_free_pfns;
 -              }
 -      }
 +      /*
 +       * Due to default_flags, all pages are HMM_PFN_VALID or
 +       * hmm_range_fault() fails. FIXME: The pages cannot be touched outside
 +       * the notifier_lock, and mmu_interval_read_retry() must be done first.
 +       */
 +      for (i = 0; i < ttm->num_pages; i++)
 +              pages[i] = hmm_pfn_to_page(range->hmm_pfns[i]);
  
        gtt->range = range;
        mmput(mm);
  out_unlock:
        up_read(&mm->mmap_sem);
  out_free_pfns:
 -      kvfree(range->pfns);
 +      kvfree(range->hmm_pfns);
  out_free_ranges:
        kfree(range);
  out:
@@@ -888,7 -1000,7 +981,7 @@@ bool amdgpu_ttm_tt_get_user_pages_done(
        DRM_DEBUG_DRIVER("user_pages_done 0x%llx pages 0x%lx\n",
                gtt->userptr, ttm->num_pages);
  
 -      WARN_ONCE(!gtt->range || !gtt->range->pfns,
 +      WARN_ONCE(!gtt->range || !gtt->range->hmm_pfns,
                "No user pages to check\n");
  
        if (gtt->range) {
                 */
                r = mmu_interval_read_retry(gtt->range->notifier,
                                         gtt->range->notifier_seq);
 -              kvfree(gtt->range->pfns);
 +              kvfree(gtt->range->hmm_pfns);
                kfree(gtt->range);
                gtt->range = NULL;
        }
@@@ -989,7 -1101,8 +1082,7 @@@ static void amdgpu_ttm_tt_unpin_userptr
  
                for (i = 0; i < ttm->num_pages; i++) {
                        if (ttm->pages[i] !=
 -                              hmm_device_entry_to_page(gtt->range,
 -                                            gtt->range->pfns[i]))
 +                          hmm_pfn_to_page(gtt->range->hmm_pfns[i]))
                                break;
                }
  
@@@ -1007,6 -1120,9 +1100,9 @@@ int amdgpu_ttm_gart_bind(struct amdgpu_
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
        int r;
  
+       if (amdgpu_bo_encrypted(abo))
+               flags |= AMDGPU_PTE_TMZ;
        if (abo->flags & AMDGPU_GEM_CREATE_CP_MQD_GFX9) {
                uint64_t page_idx = 1;
  
@@@ -1519,6 -1635,9 +1615,9 @@@ static bool amdgpu_ttm_bo_eviction_valu
  
        switch (bo->mem.mem_type) {
        case TTM_PL_TT:
+               if (amdgpu_bo_is_amdgpu_bo(bo) &&
+                   amdgpu_bo_encrypted(ttm_to_amdgpu_bo(bo)))
+                       return false;
                return true;
  
        case TTM_PL_VRAM:
@@@ -1567,8 -1686,9 +1666,9 @@@ static int amdgpu_ttm_access_memory(str
        if (bo->mem.mem_type != TTM_PL_VRAM)
                return -EIO;
  
-       nodes = amdgpu_find_mm_node(&abo->tbo.mem, &offset);
-       pos = (nodes->start << PAGE_SHIFT) + offset;
+       pos = offset;
+       nodes = amdgpu_find_mm_node(&abo->tbo.mem, &pos);
+       pos += (nodes->start << PAGE_SHIFT);
  
        while (len && pos < adev->gmc.mc_vram_size) {
                uint64_t aligned_pos = pos & ~(uint64_t)3;
@@@ -1837,17 -1957,19 +1937,19 @@@ int amdgpu_ttm_init(struct amdgpu_devic
                return r;
  
        /*
-        * reserve one TMR (64K) memory at the top of VRAM which holds
+        * reserve TMR memory at the top of VRAM which holds
         * IP Discovery data and is protected by PSP.
         */
-       r = amdgpu_bo_create_kernel_at(adev,
-                                      adev->gmc.real_vram_size - DISCOVERY_TMR_SIZE,
-                                      DISCOVERY_TMR_SIZE,
-                                      AMDGPU_GEM_DOMAIN_VRAM,
-                                      &adev->discovery_memory,
-                                      NULL);
-       if (r)
-               return r;
+       if (adev->discovery_tmr_size > 0) {
+               r = amdgpu_bo_create_kernel_at(adev,
+                       adev->gmc.real_vram_size - adev->discovery_tmr_size,
+                       adev->discovery_tmr_size,
+                       AMDGPU_GEM_DOMAIN_VRAM,
+                       &adev->discovery_memory,
+                       NULL);
+               if (r)
+                       return r;
+       }
  
        DRM_INFO("amdgpu: %uM of VRAM memory ready\n",
                 (unsigned) (adev->gmc.real_vram_size / (1024 * 1024)));
@@@ -1995,75 -2117,14 +2097,14 @@@ int amdgpu_mmap(struct file *filp, stru
        return ttm_bo_mmap(filp, vma, &adev->mman.bdev);
  }
  
- static int amdgpu_map_buffer(struct ttm_buffer_object *bo,
-                            struct ttm_mem_reg *mem, unsigned num_pages,
-                            uint64_t offset, unsigned window,
-                            struct amdgpu_ring *ring,
-                            uint64_t *addr)
- {
-       struct amdgpu_ttm_tt *gtt = (void *)bo->ttm;
-       struct amdgpu_device *adev = ring->adev;
-       struct ttm_tt *ttm = bo->ttm;
-       struct amdgpu_job *job;
-       unsigned num_dw, num_bytes;
-       dma_addr_t *dma_address;
-       struct dma_fence *fence;
-       uint64_t src_addr, dst_addr;
-       uint64_t flags;
-       int r;
-       BUG_ON(adev->mman.buffer_funcs->copy_max_bytes <
-              AMDGPU_GTT_MAX_TRANSFER_SIZE * 8);
-       *addr = adev->gmc.gart_start;
-       *addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE *
-               AMDGPU_GPU_PAGE_SIZE;
-       num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
-       num_bytes = num_pages * 8;
-       r = amdgpu_job_alloc_with_ib(adev, num_dw * 4 + num_bytes, &job);
-       if (r)
-               return r;
-       src_addr = num_dw * 4;
-       src_addr += job->ibs[0].gpu_addr;
-       dst_addr = amdgpu_bo_gpu_offset(adev->gart.bo);
-       dst_addr += window * AMDGPU_GTT_MAX_TRANSFER_SIZE * 8;
-       amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr,
-                               dst_addr, num_bytes);
-       amdgpu_ring_pad_ib(ring, &job->ibs[0]);
-       WARN_ON(job->ibs[0].length_dw > num_dw);
-       dma_address = &gtt->ttm.dma_address[offset >> PAGE_SHIFT];
-       flags = amdgpu_ttm_tt_pte_flags(adev, ttm, mem);
-       r = amdgpu_gart_map(adev, 0, num_pages, dma_address, flags,
-                           &job->ibs[0].ptr[num_dw]);
-       if (r)
-               goto error_free;
-       r = amdgpu_job_submit(job, &adev->mman.entity,
-                             AMDGPU_FENCE_OWNER_UNDEFINED, &fence);
-       if (r)
-               goto error_free;
-       dma_fence_put(fence);
-       return r;
- error_free:
-       amdgpu_job_free(job);
-       return r;
- }
  int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
                       uint64_t dst_offset, uint32_t byte_count,
                       struct dma_resv *resv,
                       struct dma_fence **fence, bool direct_submit,
-                      bool vm_needs_flush)
+                      bool vm_needs_flush, bool tmz)
  {
+       enum amdgpu_ib_pool_type pool = direct_submit ? AMDGPU_IB_POOL_DIRECT :
+               AMDGPU_IB_POOL_DELAYED;
        struct amdgpu_device *adev = ring->adev;
        struct amdgpu_job *job;
  
        num_loops = DIV_ROUND_UP(byte_count, max_bytes);
        num_dw = ALIGN(num_loops * adev->mman.buffer_funcs->copy_num_dw, 8);
  
-       r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, &job);
+       r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, pool, &job);
        if (r)
                return r;
  
                uint32_t cur_size_in_bytes = min(byte_count, max_bytes);
  
                amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_offset,
-                                       dst_offset, cur_size_in_bytes);
+                                       dst_offset, cur_size_in_bytes, tmz);
  
                src_offset += cur_size_in_bytes;
                dst_offset += cur_size_in_bytes;
@@@ -2170,7 -2231,8 +2211,8 @@@ int amdgpu_fill_buffer(struct amdgpu_b
        /* for IB padding */
        num_dw += 64;
  
-       r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, &job);
+       r = amdgpu_job_alloc_with_ib(adev, num_dw * 4, AMDGPU_IB_POOL_DELAYED,
+                                    &job);
        if (r)
                return r;
  
index c24cad3c64ed250ee280f68bae38152637b78fee,cde5e4c7caa166e9a648596d234d9c0913c66247..f0587d94294d7e71ff759932ad5108c833065bf2
@@@ -282,6 -282,7 +282,7 @@@ struct kfd_dev 
  
        /* Firmware versions */
        uint16_t mec_fw_version;
+       uint16_t mec2_fw_version;
        uint16_t sdma_fw_version;
  
        /* Maximum process number mapped to HW scheduler */
@@@ -410,6 -411,10 +411,10 @@@ enum KFD_QUEUE_PRIORITY 
   * @is_active: Defines if the queue is active or not. @is_active and
   * @is_evicted are protected by the DQM lock.
   *
+  * @is_gws: Defines if the queue has been updated to be GWS-capable or not.
+  * @is_gws should be protected by the DQM lock, since changing it can yield the
+  * possibility of updating DQM state on number of GWS queues.
+  *
   * @vmid: If the scheduling mode is no cp scheduling the field defines the vmid
   * of the queue.
   *
@@@ -432,6 -437,7 +437,7 @@@ struct queue_properties 
        bool is_interop;
        bool is_evicted;
        bool is_active;
+       bool is_gws;
        /* Not relevant for user mode queues in cp scheduling */
        unsigned int vmid;
        /* Relevant only for sdma queues*/
@@@ -563,6 -569,14 +569,14 @@@ struct qcm_process_device 
         */
        bool reset_wavefronts;
  
+       /* This flag tells us if this process has a GWS-capable
+        * queue that will be mapped into the runlist. It's
+        * possible to request a GWS BO, but not have the queue
+        * currently mapped, and this changes how the MAP_PROCESS
+        * PM4 packet is configured.
+        */
+       bool mapped_gws_queue;
        /*
         * All the memory management data should be here too
         */
@@@ -615,6 -629,8 +629,8 @@@ enum kfd_pdd_bound 
        PDD_BOUND_SUSPENDED,
  };
  
+ #define MAX_VRAM_FILENAME_LEN 11
  /* Data that is per-process-per device. */
  struct kfd_process_device {
        /*
  
        /* Is this process/pasid bound to this device? (amd_iommu_bind_pasid) */
        enum kfd_pdd_bound bound;
+       /* VRAM usage */
+       uint64_t vram_usage;
+       struct attribute attr_vram;
+       char vram_filename[MAX_VRAM_FILENAME_LEN];
  };
  
  #define qpd_to_pdd(x) container_of(x, struct kfd_process_device, qpd)
@@@ -923,6 -944,8 +944,8 @@@ int pqm_set_gws(struct process_queue_ma
                        void *gws);
  struct kernel_queue *pqm_get_kernel_queue(struct process_queue_manager *pqm,
                                                unsigned int qid);
+ struct queue *pqm_get_user_queue(struct process_queue_manager *pqm,
+                                               unsigned int qid);
  int pqm_get_wave_state(struct process_queue_manager *pqm,
                       unsigned int qid,
                       void __user *ctl_stack,
@@@ -1050,7 -1073,7 +1073,7 @@@ void kfd_dec_compute_active(struct kfd_
  /* Check with device cgroup if @kfd device is accessible */
  static inline int kfd_devcgroup_check_permission(struct kfd_dev *kfd)
  {
 -#if defined(CONFIG_CGROUP_DEVICE)
 +#if defined(CONFIG_CGROUP_DEVICE) || defined(CONFIG_CGROUP_BPF)
        struct drm_device *ddev = kfd->ddev;
  
        return devcgroup_check_permission(DEVCG_DEV_CHAR, ddev->driver->major,
index 7fc15b82fe48afad1d276e416b1d8271d3953631,d53c60b37cc6f2f7d9e75978a0a112695f2bbd93..bdba0bfd6df1beebf875efc2c1d680edac599763
@@@ -30,7 -30,7 +30,7 @@@
  #include "dc.h"
  #include "dc/inc/core_types.h"
  #include "dal_asic_id.h"
- #include "dmub/inc/dmub_srv.h"
+ #include "dmub/dmub_srv.h"
  #include "dc/inc/hw/dmcu.h"
  #include "dc/inc/hw/abm.h"
  #include "dc/dc_dmub_srv.h"
@@@ -774,8 -774,9 +774,9 @@@ static int dm_dmub_hw_init(struct amdgp
                                fw_inst_const_size);
        }
  
-       memcpy(fb_info->fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr, fw_bss_data,
-              fw_bss_data_size);
+       if (fw_bss_data_size)
+               memcpy(fb_info->fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr,
+                      fw_bss_data, fw_bss_data_size);
  
        /* Copy firmware bios info into FB memory. */
        memcpy(fb_info->fb[DMUB_WINDOW_3_VBIOS].cpu_addr, adev->bios,
@@@ -917,6 -918,23 +918,23 @@@ static int amdgpu_dm_init(struct amdgpu
                goto error;
        }
  
+       if (amdgpu_dc_debug_mask & DC_DISABLE_PIPE_SPLIT) {
+               adev->dm.dc->debug.force_single_disp_pipe_split = false;
+               adev->dm.dc->debug.pipe_split_policy = MPC_SPLIT_AVOID;
+       }
+       if (adev->asic_type != CHIP_CARRIZO && adev->asic_type != CHIP_STONEY)
+               adev->dm.dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true;
+       if (amdgpu_dc_debug_mask & DC_DISABLE_STUTTER)
+               adev->dm.dc->debug.disable_stutter = true;
+       if (amdgpu_dc_debug_mask & DC_DISABLE_DSC)
+               adev->dm.dc->debug.disable_dsc = true;
+       if (amdgpu_dc_debug_mask & DC_DISABLE_CLOCK_GATING)
+               adev->dm.dc->debug.disable_clock_gate = true;
        r = dm_dmub_hw_init(adev);
        if (r) {
                DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
@@@ -1214,6 -1232,10 +1232,10 @@@ static int dm_dmub_sw_init(struct amdgp
                adev->dm.dmub_fw->data +
                le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
                le32_to_cpu(hdr->inst_const_bytes);
+       region_params.fw_inst_const =
+               adev->dm.dmub_fw->data +
+               le32_to_cpu(hdr->header.ucode_array_offset_bytes) +
+               PSP_HEADER_BYTES;
  
        status = dmub_srv_calc_region_info(dmub_srv, &region_params,
                                           &region_info);
@@@ -1333,9 -1355,14 +1355,14 @@@ static int dm_late_init(void *handle
        struct dmcu_iram_parameters params;
        unsigned int linear_lut[16];
        int i;
-       struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu;
+       struct dmcu *dmcu = NULL;
        bool ret = false;
  
+       if (!adev->dm.fw_dmcu)
+               return detect_mst_link_for_all_connectors(adev->ddev);
+       dmcu = adev->dm.dc->res_pool->dmcu;
        for (i = 0; i < 16; i++)
                linear_lut[i] = 0xFFFF * i / 15;
  
@@@ -1511,12 -1538,115 +1538,115 @@@ static int dm_hw_fini(void *handle
        return 0;
  }
  
+ static int dm_enable_vblank(struct drm_crtc *crtc);
+ static void dm_disable_vblank(struct drm_crtc *crtc);
+ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
+                                struct dc_state *state, bool enable)
+ {
+       enum dc_irq_source irq_source;
+       struct amdgpu_crtc *acrtc;
+       int rc = -EBUSY;
+       int i = 0;
+       for (i = 0; i < state->stream_count; i++) {
+               acrtc = get_crtc_by_otg_inst(
+                               adev, state->stream_status[i].primary_otg_inst);
+               if (acrtc && state->stream_status[i].plane_count != 0) {
+                       irq_source = IRQ_TYPE_PFLIP + acrtc->otg_inst;
+                       rc = dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+                       DRM_DEBUG("crtc %d - vupdate irq %sabling: r=%d\n",
+                                 acrtc->crtc_id, enable ? "en" : "dis", rc);
+                       if (rc)
+                               DRM_WARN("Failed to %s pflip interrupts\n",
+                                        enable ? "enable" : "disable");
+                       if (enable) {
+                               rc = dm_enable_vblank(&acrtc->base);
+                               if (rc)
+                                       DRM_WARN("Failed to enable vblank interrupts\n");
+                       } else {
+                               dm_disable_vblank(&acrtc->base);
+                       }
+               }
+       }
+ }
+ enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
+ {
+       struct dc_state *context = NULL;
+       enum dc_status res = DC_ERROR_UNEXPECTED;
+       int i;
+       struct dc_stream_state *del_streams[MAX_PIPES];
+       int del_streams_count = 0;
+       memset(del_streams, 0, sizeof(del_streams));
+       context = dc_create_state(dc);
+       if (context == NULL)
+               goto context_alloc_fail;
+       dc_resource_state_copy_construct_current(dc, context);
+       /* First remove from context all streams */
+       for (i = 0; i < context->stream_count; i++) {
+               struct dc_stream_state *stream = context->streams[i];
+               del_streams[del_streams_count++] = stream;
+       }
+       /* Remove all planes for removed streams and then remove the streams */
+       for (i = 0; i < del_streams_count; i++) {
+               if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) {
+                       res = DC_FAIL_DETACH_SURFACES;
+                       goto fail;
+               }
+               res = dc_remove_stream_from_ctx(dc, context, del_streams[i]);
+               if (res != DC_OK)
+                       goto fail;
+       }
+       res = dc_validate_global_state(dc, context, false);
+       if (res != DC_OK) {
+               DRM_ERROR("%s:resource validation failed, dc_status:%d\n", __func__, res);
+               goto fail;
+       }
+       res = dc_commit_state(dc, context);
+ fail:
+       dc_release_state(context);
+ context_alloc_fail:
+       return res;
+ }
  static int dm_suspend(void *handle)
  {
        struct amdgpu_device *adev = handle;
        struct amdgpu_display_manager *dm = &adev->dm;
        int ret = 0;
  
+       if (adev->in_gpu_reset) {
+               mutex_lock(&dm->dc_lock);
+               dm->cached_dc_state = dc_copy_state(dm->dc->current_state);
+               dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false);
+               amdgpu_dm_commit_zero_streams(dm->dc);
+               amdgpu_dm_irq_suspend(adev);
+               return ret;
+       }
        WARN_ON(adev->dm.cached_state);
        adev->dm.cached_state = drm_atomic_helper_suspend(adev->ddev);
  
  
        dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
  
-       return ret;
+       return 0;
  }
  
  static struct amdgpu_dm_connector *
@@@ -1631,6 -1761,46 +1761,46 @@@ static void emulated_link_detect(struc
  
  }
  
+ static void dm_gpureset_commit_state(struct dc_state *dc_state,
+                                    struct amdgpu_display_manager *dm)
+ {
+       struct {
+               struct dc_surface_update surface_updates[MAX_SURFACES];
+               struct dc_plane_info plane_infos[MAX_SURFACES];
+               struct dc_scaling_info scaling_infos[MAX_SURFACES];
+               struct dc_flip_addrs flip_addrs[MAX_SURFACES];
+               struct dc_stream_update stream_update;
+       } * bundle;
+       int k, m;
+       bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
+       if (!bundle) {
+               dm_error("Failed to allocate update bundle\n");
+               goto cleanup;
+       }
+       for (k = 0; k < dc_state->stream_count; k++) {
+               bundle->stream_update.stream = dc_state->streams[k];
+               for (m = 0; m < dc_state->stream_status->plane_count; m++) {
+                       bundle->surface_updates[m].surface =
+                               dc_state->stream_status->plane_states[m];
+                       bundle->surface_updates[m].surface->force_full_update =
+                               true;
+               }
+               dc_commit_updates_for_stream(
+                       dm->dc, bundle->surface_updates,
+                       dc_state->stream_status->plane_count,
+                       dc_state->streams[k], &bundle->stream_update, dc_state);
+       }
+ cleanup:
+       kfree(bundle);
+       return;
+ }
  static int dm_resume(void *handle)
  {
        struct amdgpu_device *adev = handle;
        struct dm_plane_state *dm_new_plane_state;
        struct dm_atomic_state *dm_state = to_dm_atomic_state(dm->atomic_obj.state);
        enum dc_connection_type new_connection_type = dc_connection_none;
-       int i, r;
+       struct dc_state *dc_state;
+       int i, r, j;
+       if (adev->in_gpu_reset) {
+               dc_state = dm->cached_dc_state;
+               r = dm_dmub_hw_init(adev);
+               if (r)
+                       DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
+               dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
+               dc_resume(dm->dc);
+               amdgpu_dm_irq_resume_early(adev);
+               for (i = 0; i < dc_state->stream_count; i++) {
+                       dc_state->streams[i]->mode_changed = true;
+                       for (j = 0; j < dc_state->stream_status->plane_count; j++) {
+                               dc_state->stream_status->plane_states[j]->update_flags.raw
+                                       = 0xffffffff;
+                       }
+               }
+               WARN_ON(!dc_commit_state(dm->dc, dc_state));
  
+               dm_gpureset_commit_state(dm->cached_dc_state, dm);
+               dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, true);
+               dc_release_state(dm->cached_dc_state);
+               dm->cached_dc_state = NULL;
+               amdgpu_dm_irq_resume_late(adev);
+               mutex_unlock(&dm->dc_lock);
+               return 0;
+       }
        /* Recreate dc_state - DC invalidates it when setting power state to S3. */
        dc_release_state(dm_state->context);
        dm_state->context = dc_create_state(dm->dc);
@@@ -3013,9 -3219,6 +3219,6 @@@ static int amdgpu_dm_initialize_drm_dev
                goto fail;
        }
  
-       if (adev->asic_type != CHIP_CARRIZO && adev->asic_type != CHIP_STONEY)
-               dm->dc->debug.disable_stutter = amdgpu_pp_feature_mask & PP_STUTTER_MODE ? false : true;
        /* No userspace support. */
        dm->dc->debug.disable_tri_buf = true;
  
@@@ -3286,7 -3489,7 +3489,7 @@@ static int fill_dc_scaling_info(const s
  }
  
  static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb,
-                      uint64_t *tiling_flags)
+                      uint64_t *tiling_flags, bool *tmz_surface)
  {
        struct amdgpu_bo *rbo = gem_to_amdgpu_bo(amdgpu_fb->base.obj[0]);
        int r = amdgpu_bo_reserve(rbo, false);
        if (tiling_flags)
                amdgpu_bo_get_tiling_flags(rbo, tiling_flags);
  
+       if (tmz_surface)
+               *tmz_surface = amdgpu_bo_encrypted(rbo);
        amdgpu_bo_unreserve(rbo);
  
        return r;
@@@ -3388,6 -3594,7 +3594,7 @@@ fill_plane_buffer_attributes(struct amd
                             struct plane_size *plane_size,
                             struct dc_plane_dcc_param *dcc,
                             struct dc_plane_address *address,
+                            bool tmz_surface,
                             bool force_disable_dcc)
  {
        const struct drm_framebuffer *fb = &afb->base;
        memset(dcc, 0, sizeof(*dcc));
        memset(address, 0, sizeof(*address));
  
+       address->tmz_surface = tmz_surface;
        if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
                plane_size->surface_size.x = 0;
                plane_size->surface_size.y = 0;
@@@ -3588,6 -3797,7 +3797,7 @@@ fill_dc_plane_info_and_addr(struct amdg
                            const uint64_t tiling_flags,
                            struct dc_plane_info *plane_info,
                            struct dc_plane_address *address,
+                           bool tmz_surface,
                            bool force_disable_dcc)
  {
        const struct drm_framebuffer *fb = plane_state->fb;
        case DRM_FORMAT_P010:
                plane_info->format = SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb;
                break;
+       case DRM_FORMAT_XRGB16161616F:
+       case DRM_FORMAT_ARGB16161616F:
+               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F;
+               break;
+       case DRM_FORMAT_XBGR16161616F:
+       case DRM_FORMAT_ABGR16161616F:
+               plane_info->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F;
+               break;
        default:
                DRM_ERROR(
                        "Unsupported screen format %s\n",
                                           plane_info->rotation, tiling_flags,
                                           &plane_info->tiling_info,
                                           &plane_info->plane_size,
-                                          &plane_info->dcc, address,
+                                          &plane_info->dcc, address, tmz_surface,
                                           force_disable_dcc);
        if (ret)
                return ret;
@@@ -3694,6 -3912,7 +3912,7 @@@ static int fill_dc_plane_attributes(str
        struct dc_plane_info plane_info;
        uint64_t tiling_flags;
        int ret;
+       bool tmz_surface = false;
        bool force_disable_dcc = false;
  
        ret = fill_dc_scaling_info(plane_state, &scaling_info);
        dc_plane_state->clip_rect = scaling_info.clip_rect;
        dc_plane_state->scaling_quality = scaling_info.scaling_quality;
  
-       ret = get_fb_info(amdgpu_fb, &tiling_flags);
+       ret = get_fb_info(amdgpu_fb, &tiling_flags, &tmz_surface);
        if (ret)
                return ret;
  
        ret = fill_dc_plane_info_and_addr(adev, plane_state, tiling_flags,
                                          &plane_info,
                                          &dc_plane_state->address,
+                                         tmz_surface,
                                          force_disable_dcc);
        if (ret)
                return ret;
@@@ -3800,8 -4020,7 +4020,7 @@@ static void update_stream_scaling_setti
  
  static enum dc_color_depth
  convert_color_depth_from_display_info(const struct drm_connector *connector,
-                                     const struct drm_connector_state *state,
-                                     bool is_y420)
+                                     bool is_y420, int requested_bpc)
  {
        uint8_t bpc;
  
                bpc = bpc ? bpc : 8;
        }
  
-       if (!state)
-               state = connector->state;
-       if (state) {
+       if (requested_bpc > 0) {
                /*
                 * Cap display bpc based on the user requested value.
                 *
                 * or if this was called outside of atomic check, so it
                 * can't be used directly.
                 */
-               bpc = min(bpc, state->max_requested_bpc);
+               bpc = min_t(u8, bpc, requested_bpc);
  
                /* Round down to the nearest even number. */
                bpc = bpc - (bpc & 1);
@@@ -3955,7 -4171,8 +4171,8 @@@ static void fill_stream_properties_from
        const struct drm_display_mode *mode_in,
        const struct drm_connector *connector,
        const struct drm_connector_state *connector_state,
-       const struct dc_stream_state *old_stream)
+       const struct dc_stream_state *old_stream,
+       int requested_bpc)
  {
        struct dc_crtc_timing *timing_out = &stream->timing;
        const struct drm_display_info *info = &connector->display_info;
  
        timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
        timing_out->display_color_depth = convert_color_depth_from_display_info(
-               connector, connector_state,
-               (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420));
+               connector,
+               (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420),
+               requested_bpc);
        timing_out->scan_type = SCANNING_TYPE_NODATA;
        timing_out->hdmi_vic = 0;
  
@@@ -4192,7 -4410,8 +4410,8 @@@ static struct dc_stream_state 
  create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                       const struct drm_display_mode *drm_mode,
                       const struct dm_connector_state *dm_state,
-                      const struct dc_stream_state *old_stream)
+                      const struct dc_stream_state *old_stream,
+                      int requested_bpc)
  {
        struct drm_display_mode *preferred_mode = NULL;
        struct drm_connector *drm_connector;
        */
        if (!scale || mode_refresh != preferred_refresh)
                fill_stream_properties_from_drm_display_mode(stream,
-                       &mode, &aconnector->base, con_state, NULL);
+                       &mode, &aconnector->base, con_state, NULL, requested_bpc);
        else
                fill_stream_properties_from_drm_display_mode(stream,
-                       &mode, &aconnector->base, con_state, old_stream);
+                       &mode, &aconnector->base, con_state, old_stream, requested_bpc);
  
        stream->timing.flags.DSC = 0;
  
  
        if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
                mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false);
-       if (stream->link->psr_feature_enabled)  {
+       if (stream->link->psr_settings.psr_feature_enabled)     {
                struct dc  *core_dc = stream->link->ctx->dc;
  
                if (dc_is_dmcu_initialized(core_dc)) {
-                       struct dmcu *dmcu = core_dc->res_pool->dmcu;
-                       stream->psr_version = dmcu->dmcu_version.psr_version;
                        //
                        // should decide stream support vsc sdp colorimetry capability
                        // before building vsc info packet
@@@ -4713,6 -4928,7 +4928,6 @@@ amdgpu_dm_connector_atomic_duplicate_st
  static int
  amdgpu_dm_connector_late_register(struct drm_connector *connector)
  {
 -#if defined(CONFIG_DEBUG_FS)
        struct amdgpu_dm_connector *amdgpu_dm_connector =
                to_amdgpu_dm_connector(connector);
        int r;
                        return r;
        }
  
 +#if defined(CONFIG_DEBUG_FS)
        connector_debugfs_init(amdgpu_dm_connector);
  #endif
  
@@@ -4803,16 -5018,54 +5018,54 @@@ static void handle_edid_mgmt(struct amd
        create_eml_sink(aconnector);
  }
  
+ static struct dc_stream_state *
+ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+                               const struct drm_display_mode *drm_mode,
+                               const struct dm_connector_state *dm_state,
+                               const struct dc_stream_state *old_stream)
+ {
+       struct drm_connector *connector = &aconnector->base;
+       struct amdgpu_device *adev = connector->dev->dev_private;
+       struct dc_stream_state *stream;
+       int requested_bpc = connector->state ? connector->state->max_requested_bpc : 8;
+       enum dc_status dc_result = DC_OK;
+       do {
+               stream = create_stream_for_sink(aconnector, drm_mode,
+                                               dm_state, old_stream,
+                                               requested_bpc);
+               if (stream == NULL) {
+                       DRM_ERROR("Failed to create stream for sink!\n");
+                       break;
+               }
+               dc_result = dc_validate_stream(adev->dm.dc, stream);
+               if (dc_result != DC_OK) {
+                       DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d\n",
+                                     drm_mode->hdisplay,
+                                     drm_mode->vdisplay,
+                                     drm_mode->clock,
+                                     dc_result);
+                       dc_stream_release(stream);
+                       stream = NULL;
+                       requested_bpc -= 2; /* lower bpc to retry validation */
+               }
+       } while (stream == NULL && requested_bpc >= 6);
+       return stream;
+ }
  enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
                                   struct drm_display_mode *mode)
  {
        int result = MODE_ERROR;
        struct dc_sink *dc_sink;
-       struct amdgpu_device *adev = connector->dev->dev_private;
        /* TODO: Unhardcode stream count */
        struct dc_stream_state *stream;
        struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
-       enum dc_status dc_result = DC_OK;
  
        if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
                        (mode->flags & DRM_MODE_FLAG_DBLSCAN))
                goto fail;
        }
  
-       stream = create_stream_for_sink(aconnector, mode, NULL, NULL);
-       if (stream == NULL) {
-               DRM_ERROR("Failed to create stream for sink!\n");
-               goto fail;
-       }
-       dc_result = dc_validate_stream(adev->dm.dc, stream);
-       if (dc_result == DC_OK)
+       stream = create_validate_stream_for_sink(aconnector, mode, NULL, NULL);
+       if (stream) {
+               dc_stream_release(stream);
                result = MODE_OK;
-       else
-               DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d\n",
-                             mode->hdisplay,
-                             mode->vdisplay,
-                             mode->clock,
-                             dc_result);
-       dc_stream_release(stream);
+       }
  
  fail:
        /* TODO: error handling*/
@@@ -5173,10 -5413,12 +5413,12 @@@ static int dm_encoder_helper_atomic_che
                return 0;
  
        if (!state->duplicated) {
+               int max_bpc = conn_state->max_requested_bpc;
                is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
                                aconnector->force_yuv420_output;
-               color_depth = convert_color_depth_from_display_info(connector, conn_state,
-                                                                   is_y420);
+               color_depth = convert_color_depth_from_display_info(connector,
+                                                                   is_y420,
+                                                                   max_bpc);
                bpp = convert_dc_color_depth_into_bpc(color_depth) * 3;
                clock = adjusted_mode->clock;
                dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false);
@@@ -5331,6 -5573,7 +5573,7 @@@ static int dm_plane_helper_prepare_fb(s
        uint64_t tiling_flags;
        uint32_t domain;
        int r;
+       bool tmz_surface = false;
        bool force_disable_dcc = false;
  
        dm_plane_state_old = to_dm_plane_state(plane->state);
  
        amdgpu_bo_get_tiling_flags(rbo, &tiling_flags);
  
+       tmz_surface = amdgpu_bo_encrypted(rbo);
        ttm_eu_backoff_reservation(&ticket, &list);
  
        afb->address = amdgpu_bo_gpu_offset(rbo);
                        adev, afb, plane_state->format, plane_state->rotation,
                        tiling_flags, &plane_state->tiling_info,
                        &plane_state->plane_size, &plane_state->dcc,
-                       &plane_state->address,
+                       &plane_state->address, tmz_surface,
                        force_disable_dcc);
        }
  
@@@ -5542,6 -5787,12 +5787,12 @@@ static int get_plane_formats(const stru
                        formats[num_formats++] = DRM_FORMAT_NV12;
                if (plane_cap && plane_cap->pixel_format_support.p010)
                        formats[num_formats++] = DRM_FORMAT_P010;
+               if (plane_cap && plane_cap->pixel_format_support.fp16) {
+                       formats[num_formats++] = DRM_FORMAT_XRGB16161616F;
+                       formats[num_formats++] = DRM_FORMAT_ARGB16161616F;
+                       formats[num_formats++] = DRM_FORMAT_XBGR16161616F;
+                       formats[num_formats++] = DRM_FORMAT_ABGR16161616F;
+               }
                break;
  
        case DRM_PLANE_TYPE_OVERLAY:
@@@ -6569,6 -6820,7 +6820,7 @@@ static void amdgpu_dm_commit_planes(str
        unsigned long flags;
        struct amdgpu_bo *abo;
        uint64_t tiling_flags;
+       bool tmz_surface = false;
        uint32_t target_vblank, last_flip_vblank;
        bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
        bool pflip_present = false;
                if (new_pcrtc_state->color_mgmt_changed) {
                        bundle->surface_updates[planes_count].gamma = dc_plane->gamma_correction;
                        bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func;
+                       bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix;
                }
  
                fill_dc_scaling_info(new_plane_state,
  
                amdgpu_bo_get_tiling_flags(abo, &tiling_flags);
  
+               tmz_surface = amdgpu_bo_encrypted(abo);
                amdgpu_bo_unreserve(abo);
  
                fill_dc_plane_info_and_addr(
                        dm->adev, new_plane_state, tiling_flags,
                        &bundle->plane_infos[planes_count],
                        &bundle->flip_addrs[planes_count].address,
+                       tmz_surface,
                        false);
  
                DRM_DEBUG_DRIVER("plane: id=%d dcc_en=%d\n",
                }
                mutex_lock(&dm->dc_lock);
                if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
-                               acrtc_state->stream->link->psr_allow_active)
+                               acrtc_state->stream->link->psr_settings.psr_allow_active)
                        amdgpu_dm_psr_disable(acrtc_state->stream);
  
                dc_commit_updates_for_stream(dm->dc,
                                                     dc_state);
  
                if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
-                                               acrtc_state->stream->psr_version &&
-                                               !acrtc_state->stream->link->psr_feature_enabled)
+                               acrtc_state->stream->link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED &&
+                               !acrtc_state->stream->link->psr_settings.psr_feature_enabled)
                        amdgpu_dm_link_setup_psr(acrtc_state->stream);
                else if ((acrtc_state->update_type == UPDATE_TYPE_FAST) &&
-                                               acrtc_state->stream->link->psr_feature_enabled &&
-                                               !acrtc_state->stream->link->psr_allow_active) {
+                               acrtc_state->stream->link->psr_settings.psr_feature_enabled &&
+                               !acrtc_state->stream->link->psr_settings.psr_allow_active) {
                        amdgpu_dm_psr_enable(acrtc_state->stream);
                }
  
@@@ -7144,7 -7400,7 +7400,7 @@@ static void amdgpu_dm_atomic_commit_tai
                        DRM_DEBUG_DRIVER("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc);
                        /* i.e. reset mode */
                        if (dm_old_crtc_state->stream) {
-                               if (dm_old_crtc_state->stream->link->psr_allow_active)
+                               if (dm_old_crtc_state->stream->link->psr_settings.psr_allow_active)
                                        amdgpu_dm_psr_disable(dm_old_crtc_state->stream);
  
                                remove_stream(adev, acrtc, dm_old_crtc_state->stream);
@@@ -7592,10 -7848,10 +7848,10 @@@ static int dm_update_crtc_state(struct 
                if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
                        goto skip_modeset;
  
-               new_stream = create_stream_for_sink(aconnector,
-                                                    &new_crtc_state->mode,
-                                                   dm_new_conn_state,
-                                                   dm_old_crtc_state->stream);
+               new_stream = create_validate_stream_for_sink(aconnector,
+                                                            &new_crtc_state->mode,
+                                                            dm_new_conn_state,
+                                                            dm_old_crtc_state->stream);
  
                /*
                 * we can have no stream on ACTION_SET if a display
@@@ -8056,6 -8312,7 +8312,7 @@@ dm_determine_update_type_for_commit(str
                        struct dc_flip_addrs *flip_addr = &bundle->flip_addrs[num_plane];
                        struct dc_scaling_info *scaling_info = &bundle->scaling_infos[num_plane];
                        uint64_t tiling_flags;
+                       bool tmz_surface = false;
  
                        new_plane_crtc = new_plane_state->crtc;
                        new_dm_plane_state = to_dm_plane_state(new_plane_state);
                                                new_dm_plane_state->dc_state->gamma_correction;
                                bundle->surface_updates[num_plane].in_transfer_func =
                                                new_dm_plane_state->dc_state->in_transfer_func;
+                               bundle->surface_updates[num_plane].gamut_remap_matrix =
+                                               &new_dm_plane_state->dc_state->gamut_remap_matrix;
                                bundle->stream_update.gamut_remap =
                                                &new_dm_crtc_state->stream->gamut_remap_matrix;
                                bundle->stream_update.output_csc_transform =
                        bundle->surface_updates[num_plane].scaling_info = scaling_info;
  
                        if (amdgpu_fb) {
-                               ret = get_fb_info(amdgpu_fb, &tiling_flags);
+                               ret = get_fb_info(amdgpu_fb, &tiling_flags, &tmz_surface);
                                if (ret)
                                        goto cleanup;
  
                                ret = fill_dc_plane_info_and_addr(
                                        dm->adev, new_plane_state, tiling_flags,
                                        plane_info,
-                                       &flip_addr->address,
+                                       &flip_addr->address, tmz_surface,
                                        false);
                                if (ret)
                                        goto cleanup;
@@@ -8609,8 -8868,17 +8868,17 @@@ static void amdgpu_dm_set_psr_caps(stru
                return;
        if (dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT,
                                        dpcd_data, sizeof(dpcd_data))) {
-               link->psr_feature_enabled = dpcd_data[0] ? true:false;
-               DRM_INFO("PSR support:%d\n", link->psr_feature_enabled);
+               link->dpcd_caps.psr_caps.psr_version = dpcd_data[0];
+               if (dpcd_data[0] == 0) {
+                       link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
+                       link->psr_settings.psr_feature_enabled = false;
+               } else {
+                       link->psr_settings.psr_version = DC_PSR_VERSION_1;
+                       link->psr_settings.psr_feature_enabled = true;
+               }
+               DRM_INFO("PSR support:%d\n", link->psr_settings.psr_feature_enabled);
        }
  }
  
@@@ -8625,16 -8893,14 +8893,14 @@@ static bool amdgpu_dm_link_setup_psr(st
        struct dc_link *link = NULL;
        struct psr_config psr_config = {0};
        struct psr_context psr_context = {0};
-       struct dc *dc = NULL;
        bool ret = false;
  
        if (stream == NULL)
                return false;
  
        link = stream->link;
-       dc = link->ctx->dc;
  
-       psr_config.psr_version = dc->res_pool->dmcu->dmcu_version.psr_version;
+       psr_config.psr_version = link->dpcd_caps.psr_caps.psr_version;
  
        if (psr_config.psr_version > 0) {
                psr_config.psr_exit_link_training_required = 0x1;
                ret = dc_link_setup_psr(link, stream, &psr_config, &psr_context);
  
        }
-       DRM_DEBUG_DRIVER("PSR link: %d\n",      link->psr_feature_enabled);
+       DRM_DEBUG_DRIVER("PSR link: %d\n",      link->psr_settings.psr_feature_enabled);
  
        return ret;
  }
index 5232f81c16a57579e672e15894f98c2274428efb,dd9ed71ed942811d6ae958b1f26cadfd6fe26a17..5fc25c3f445c22be12ac4a53df43248584366d6f
@@@ -12,6 -12,7 +12,7 @@@
  #include <drm/drm_atomic_helper.h>
  #include <drm/drm_drv.h>
  #include <drm/drm_ioctl.h>
+ #include <drm/drm_managed.h>
  #include <drm/drm_prime.h>
  #include <drm/drm_probe_helper.h>
  #include <drm/drm_fb_helper.h>
@@@ -103,6 -104,7 +104,7 @@@ static int armada_drm_bind(struct devic
                kfree(priv);
                return ret;
        }
+       drmm_add_final_kfree(&priv->drm, priv);
  
        /* Remove early framebuffers */
        ret = drm_fb_helper_remove_conflicting_framebuffers(NULL,
@@@ -311,7 -313,7 +313,7 @@@ static void __exit armada_drm_exit(void
  }
  module_exit(armada_drm_exit);
  
 -MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
 +MODULE_AUTHOR("Russell King <[email protected]>");
  MODULE_DESCRIPTION("Armada DRM Driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:armada-drm");
index 35b62c5d18b40dfe2a28b2c0fd26ce437605e2fb,b90cca361afedeb506a08947a117220af28c6ead..1e26b89628f98c7d4e4b3bed44078c6c088165fb
@@@ -27,6 -27,7 +27,7 @@@
  #include <linux/kernel.h>
  #include <linux/sched.h>
  #include <linux/seq_file.h>
+ #include <linux/iopoll.h>
  
  #if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS)
  #include <linux/stacktrace.h>
@@@ -687,51 -688,45 +688,45 @@@ static void drm_dp_encode_sideband_repl
        raw->cur_len = idx;
  }
  
- /* this adds a chunk of msg to the builder to get the final msg */
static bool drm_dp_sideband_msg_build(struct drm_dp_sideband_msg_rx *msg,
-                                     u8 *replybuf, u8 replybuflen, bool hdr)
+ static int drm_dp_sideband_msg_set_header(struct drm_dp_sideband_msg_rx *msg,
                                        struct drm_dp_sideband_msg_hdr *hdr,
+                                         u8 hdrlen)
  {
-       int ret;
-       u8 crc4;
+       /*
+        * ignore out-of-order messages or messages that are part of a
+        * failed transaction
+        */
+       if (!hdr->somt && !msg->have_somt)
+               return false;
  
-       if (hdr) {
-               u8 hdrlen;
-               struct drm_dp_sideband_msg_hdr recv_hdr;
-               ret = drm_dp_decode_sideband_msg_hdr(&recv_hdr, replybuf, replybuflen, &hdrlen);
-               if (ret == false) {
-                       print_hex_dump(KERN_DEBUG, "failed hdr", DUMP_PREFIX_NONE, 16, 1, replybuf, replybuflen, false);
-                       return false;
-               }
+       /* get length contained in this portion */
+       msg->curchunk_idx = 0;
+       msg->curchunk_len = hdr->msg_len;
+       msg->curchunk_hdrlen = hdrlen;
  
-               /*
-                * ignore out-of-order messages or messages that are part of a
-                * failed transaction
-                */
-               if (!recv_hdr.somt && !msg->have_somt)
-                       return false;
+       /* we have already gotten an somt - don't bother parsing */
+       if (hdr->somt && msg->have_somt)
+               return false;
  
-               /* get length contained in this portion */
-               msg->curchunk_len = recv_hdr.msg_len;
-               msg->curchunk_hdrlen = hdrlen;
+       if (hdr->somt) {
+               memcpy(&msg->initial_hdr, hdr,
+                      sizeof(struct drm_dp_sideband_msg_hdr));
+               msg->have_somt = true;
+       }
+       if (hdr->eomt)
+               msg->have_eomt = true;
  
-               /* we have already gotten an somt - don't bother parsing */
-               if (recv_hdr.somt && msg->have_somt)
-                       return false;
+       return true;
+ }
  
-               if (recv_hdr.somt) {
-                       memcpy(&msg->initial_hdr, &recv_hdr, sizeof(struct drm_dp_sideband_msg_hdr));
-                       msg->have_somt = true;
-               }
-               if (recv_hdr.eomt)
-                       msg->have_eomt = true;
+ /* this adds a chunk of msg to the builder to get the final msg */
+ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg,
+                                          u8 *replybuf, u8 replybuflen)
+ {
+       u8 crc4;
  
-               /* copy the bytes for the remainder of this header chunk */
-               msg->curchunk_idx = min(msg->curchunk_len, (u8)(replybuflen - hdrlen));
-               memcpy(&msg->chunk[0], replybuf + hdrlen, msg->curchunk_idx);
-       } else {
-               memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen);
-               msg->curchunk_idx += replybuflen;
-       }
+       memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen);
+       msg->curchunk_idx += replybuflen;
  
        if (msg->curchunk_idx >= msg->curchunk_len) {
                /* do CRC */
@@@ -1060,13 -1055,12 +1055,12 @@@ static void build_link_address(struct d
        drm_dp_encode_sideband_req(&req, msg);
  }
  
- static int build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg)
+ static void build_clear_payload_id_table(struct drm_dp_sideband_msg_tx *msg)
  {
        struct drm_dp_sideband_msg_req_body req;
  
        req.req_type = DP_CLEAR_PAYLOAD_ID_TABLE;
        drm_dp_encode_sideband_req(&req, msg);
-       return 0;
  }
  
  static int build_enum_path_resources(struct drm_dp_sideband_msg_tx *msg,
@@@ -1203,16 -1197,8 +1197,8 @@@ static int drm_dp_mst_wait_tx_reply(str
  
                /* remove from q */
                if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED ||
-                   txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND) {
+                   txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND)
                        list_del(&txmsg->next);
-               }
-               if (txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND ||
-                   txmsg->state == DRM_DP_SIDEBAND_TX_SENT) {
-                       mstb->tx_slots[txmsg->seqno] = NULL;
-               }
-               mgr->is_waiting_for_dwn_reply = false;
        }
  out:
        if (unlikely(ret == -EIO) && drm_debug_enabled(DRM_UT_DP)) {
@@@ -2691,22 -2677,6 +2677,6 @@@ static int set_hdr_from_dst_qlock(struc
        struct drm_dp_mst_branch *mstb = txmsg->dst;
        u8 req_type;
  
-       /* both msg slots are full */
-       if (txmsg->seqno == -1) {
-               if (mstb->tx_slots[0] && mstb->tx_slots[1]) {
-                       DRM_DEBUG_KMS("%s: failed to find slot\n", __func__);
-                       return -EAGAIN;
-               }
-               if (mstb->tx_slots[0] == NULL && mstb->tx_slots[1] == NULL) {
-                       txmsg->seqno = mstb->last_seqno;
-                       mstb->last_seqno ^= 1;
-               } else if (mstb->tx_slots[0] == NULL)
-                       txmsg->seqno = 0;
-               else
-                       txmsg->seqno = 1;
-               mstb->tx_slots[txmsg->seqno] = txmsg;
-       }
        req_type = txmsg->msg[0] & 0x7f;
        if (req_type == DP_CONNECTION_STATUS_NOTIFY ||
                req_type == DP_RESOURCE_STATUS_NOTIFY)
        hdr->lcr = mstb->lct - 1;
        if (mstb->lct > 1)
                memcpy(hdr->rad, mstb->rad, mstb->lct / 2);
-       hdr->seqno = txmsg->seqno;
        return 0;
  }
  /*
@@@ -2733,15 -2703,15 +2703,15 @@@ static int process_single_tx_qlock(stru
        int len, space, idx, tosend;
        int ret;
  
+       if (txmsg->state == DRM_DP_SIDEBAND_TX_SENT)
+               return 0;
        memset(&hdr, 0, sizeof(struct drm_dp_sideband_msg_hdr));
  
-       if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED) {
-               txmsg->seqno = -1;
+       if (txmsg->state == DRM_DP_SIDEBAND_TX_QUEUED)
                txmsg->state = DRM_DP_SIDEBAND_TX_START_SEND;
-       }
  
-       /* make hdr from dst mst - for replies use seqno
-          otherwise assign one */
+       /* make hdr from dst mst */
        ret = set_hdr_from_dst_qlock(&hdr, txmsg);
        if (ret < 0)
                return ret;
@@@ -2794,42 -2764,17 +2764,17 @@@ static void process_single_down_tx_qloc
        if (list_empty(&mgr->tx_msg_downq))
                return;
  
-       txmsg = list_first_entry(&mgr->tx_msg_downq, struct drm_dp_sideband_msg_tx, next);
+       txmsg = list_first_entry(&mgr->tx_msg_downq,
+                                struct drm_dp_sideband_msg_tx, next);
        ret = process_single_tx_qlock(mgr, txmsg, false);
-       if (ret == 1) {
-               /* txmsg is sent it should be in the slots now */
-               mgr->is_waiting_for_dwn_reply = true;
-               list_del(&txmsg->next);
-       } else if (ret) {
+       if (ret < 0) {
                DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
-               mgr->is_waiting_for_dwn_reply = false;
                list_del(&txmsg->next);
-               if (txmsg->seqno != -1)
-                       txmsg->dst->tx_slots[txmsg->seqno] = NULL;
                txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
                wake_up_all(&mgr->tx_waitq);
        }
  }
  
- /* called holding qlock */
- static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr,
-                                      struct drm_dp_sideband_msg_tx *txmsg)
- {
-       int ret;
-       /* construct a chunk from the first msg in the tx_msg queue */
-       ret = process_single_tx_qlock(mgr, txmsg, true);
-       if (ret != 1)
-               DRM_DEBUG_KMS("failed to send msg in q %d\n", ret);
-       if (txmsg->seqno != -1) {
-               WARN_ON((unsigned int)txmsg->seqno >
-                       ARRAY_SIZE(txmsg->dst->tx_slots));
-               txmsg->dst->tx_slots[txmsg->seqno] = NULL;
-       }
- }
  static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,
                                 struct drm_dp_sideband_msg_tx *txmsg)
  {
                drm_dp_mst_dump_sideband_msg_tx(&p, txmsg);
        }
  
-       if (list_is_singular(&mgr->tx_msg_downq) &&
-           !mgr->is_waiting_for_dwn_reply)
+       if (list_is_singular(&mgr->tx_msg_downq))
                process_single_down_tx_qlock(mgr);
        mutex_unlock(&mgr->qlock);
  }
@@@ -3442,12 -3386,8 +3386,12 @@@ static int drm_dp_send_dpcd_write(struc
        drm_dp_queue_down_tx(mgr, txmsg);
  
        ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
 -      if (ret > 0 && txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
 -              ret = -EIO;
 +      if (ret > 0) {
 +              if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
 +                      ret = -EIO;
 +              else
 +                      ret = size;
 +      }
  
        kfree(txmsg);
  fail_put:
@@@ -3467,7 -3407,7 +3411,7 @@@ static int drm_dp_encode_up_ack_reply(s
  
  static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr,
                                    struct drm_dp_mst_branch *mstb,
-                                   int req_type, int seqno, bool broadcast)
+                                   int req_type, bool broadcast)
  {
        struct drm_dp_sideband_msg_tx *txmsg;
  
                return -ENOMEM;
  
        txmsg->dst = mstb;
-       txmsg->seqno = seqno;
        drm_dp_encode_up_ack_reply(txmsg, req_type);
  
        mutex_lock(&mgr->qlock);
-       process_single_up_tx_qlock(mgr, txmsg);
+       /* construct a chunk from the first msg in the tx_msg queue */
+       process_single_tx_qlock(mgr, txmsg, true);
        mutex_unlock(&mgr->qlock);
  
        kfree(txmsg);
@@@ -3707,31 -3645,63 +3649,63 @@@ out_fail
  }
  EXPORT_SYMBOL(drm_dp_mst_topology_mgr_resume);
  
- static bool drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up)
+ static bool
+ drm_dp_get_one_sb_msg(struct drm_dp_mst_topology_mgr *mgr, bool up,
+                     struct drm_dp_mst_branch **mstb)
  {
        int len;
        u8 replyblock[32];
        int replylen, curreply;
        int ret;
-       struct drm_dp_sideband_msg_rx *msg;
-       int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE : DP_SIDEBAND_MSG_DOWN_REP_BASE;
-       msg = up ? &mgr->up_req_recv : &mgr->down_rep_recv;
+       u8 hdrlen;
+       struct drm_dp_sideband_msg_hdr hdr;
+       struct drm_dp_sideband_msg_rx *msg =
+               up ? &mgr->up_req_recv : &mgr->down_rep_recv;
+       int basereg = up ? DP_SIDEBAND_MSG_UP_REQ_BASE :
+                          DP_SIDEBAND_MSG_DOWN_REP_BASE;
+       if (!up)
+               *mstb = NULL;
  
        len = min(mgr->max_dpcd_transaction_bytes, 16);
-       ret = drm_dp_dpcd_read(mgr->aux, basereg,
-                              replyblock, len);
+       ret = drm_dp_dpcd_read(mgr->aux, basereg, replyblock, len);
        if (ret != len) {
                DRM_DEBUG_KMS("failed to read DPCD down rep %d %d\n", len, ret);
                return false;
        }
-       ret = drm_dp_sideband_msg_build(msg, replyblock, len, true);
+       ret = drm_dp_decode_sideband_msg_hdr(&hdr, replyblock, len, &hdrlen);
+       if (ret == false) {
+               print_hex_dump(KERN_DEBUG, "failed hdr", DUMP_PREFIX_NONE, 16,
+                              1, replyblock, len, false);
+               DRM_DEBUG_KMS("ERROR: failed header\n");
+               return false;
+       }
+       if (!up) {
+               /* Caller is responsible for giving back this reference */
+               *mstb = drm_dp_get_mst_branch_device(mgr, hdr.lct, hdr.rad);
+               if (!*mstb) {
+                       DRM_DEBUG_KMS("Got MST reply from unknown device %d\n",
+                                     hdr.lct);
+                       return false;
+               }
+       }
+       if (!drm_dp_sideband_msg_set_header(msg, &hdr, hdrlen)) {
+               DRM_DEBUG_KMS("sideband msg set header failed %d\n",
+                             replyblock[0]);
+               return false;
+       }
+       replylen = min(msg->curchunk_len, (u8)(len - hdrlen));
+       ret = drm_dp_sideband_append_payload(msg, replyblock + hdrlen, replylen);
        if (!ret) {
                DRM_DEBUG_KMS("sideband msg build failed %d\n", replyblock[0]);
                return false;
        }
-       replylen = msg->curchunk_len + msg->curchunk_hdrlen;
  
-       replylen -= len;
+       replylen = msg->curchunk_len + msg->curchunk_hdrlen - len;
        curreply = len;
        while (replylen > 0) {
                len = min3(replylen, mgr->max_dpcd_transaction_bytes, 16);
                        return false;
                }
  
-               ret = drm_dp_sideband_msg_build(msg, replyblock, len, false);
+               ret = drm_dp_sideband_append_payload(msg, replyblock, len);
                if (!ret) {
                        DRM_DEBUG_KMS("failed to build sideband msg\n");
                        return false;
  static int drm_dp_mst_handle_down_rep(struct drm_dp_mst_topology_mgr *mgr)
  {
        struct drm_dp_sideband_msg_tx *txmsg;
-       struct drm_dp_mst_branch *mstb;
-       struct drm_dp_sideband_msg_hdr *hdr = &mgr->down_rep_recv.initial_hdr;
-       int slot = -1;
-       if (!drm_dp_get_one_sb_msg(mgr, false))
-               goto clear_down_rep_recv;
+       struct drm_dp_mst_branch *mstb = NULL;
+       struct drm_dp_sideband_msg_rx *msg = &mgr->down_rep_recv;
  
-       if (!mgr->down_rep_recv.have_eomt)
-               return 0;
+       if (!drm_dp_get_one_sb_msg(mgr, false, &mstb))
+               goto out;
  
-       mstb = drm_dp_get_mst_branch_device(mgr, hdr->lct, hdr->rad);
-       if (!mstb) {
-               DRM_DEBUG_KMS("Got MST reply from unknown device %d\n",
-                             hdr->lct);
-               goto clear_down_rep_recv;
-       }
+       /* Multi-packet message transmission, don't clear the reply */
+       if (!msg->have_eomt)
+               goto out;
  
        /* find the message */
-       slot = hdr->seqno;
        mutex_lock(&mgr->qlock);
-       txmsg = mstb->tx_slots[slot];
-       /* remove from slots */
+       txmsg = list_first_entry_or_null(&mgr->tx_msg_downq,
+                                        struct drm_dp_sideband_msg_tx, next);
        mutex_unlock(&mgr->qlock);
  
-       if (!txmsg) {
+       /* Were we actually expecting a response, and from this mstb? */
+       if (!txmsg || txmsg->dst != mstb) {
+               struct drm_dp_sideband_msg_hdr *hdr;
+               hdr = &msg->initial_hdr;
                DRM_DEBUG_KMS("Got MST reply with no msg %p %d %d %02x %02x\n",
                              mstb, hdr->seqno, hdr->lct, hdr->rad[0],
-                             mgr->down_rep_recv.msg[0]);
-               goto no_msg;
+                             msg->msg[0]);
+               goto out_clear_reply;
        }
  
-       drm_dp_sideband_parse_reply(&mgr->down_rep_recv, &txmsg->reply);
+       drm_dp_sideband_parse_reply(msg, &txmsg->reply);
  
-       if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK)
+       if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
                DRM_DEBUG_KMS("Got NAK reply: req 0x%02x (%s), reason 0x%02x (%s), nak data 0x%02x\n",
                              txmsg->reply.req_type,
                              drm_dp_mst_req_type_str(txmsg->reply.req_type),
                              txmsg->reply.u.nak.reason,
                              drm_dp_mst_nak_reason_str(txmsg->reply.u.nak.reason),
                              txmsg->reply.u.nak.nak_data);
+       }
  
-       memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+       memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx));
        drm_dp_mst_topology_put_mstb(mstb);
  
        mutex_lock(&mgr->qlock);
        txmsg->state = DRM_DP_SIDEBAND_TX_RX;
-       mstb->tx_slots[slot] = NULL;
-       mgr->is_waiting_for_dwn_reply = false;
+       list_del(&txmsg->next);
        mutex_unlock(&mgr->qlock);
  
        wake_up_all(&mgr->tx_waitq);
  
        return 0;
  
- no_msg:
-       drm_dp_mst_topology_put_mstb(mstb);
- clear_down_rep_recv:
-       mutex_lock(&mgr->qlock);
-       mgr->is_waiting_for_dwn_reply = false;
-       mutex_unlock(&mgr->qlock);
-       memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
+ out_clear_reply:
+       memset(msg, 0, sizeof(struct drm_dp_sideband_msg_rx));
+ out:
+       if (mstb)
+               drm_dp_mst_topology_put_mstb(mstb);
  
        return 0;
  }
@@@ -3894,11 -3857,9 +3861,9 @@@ static void drm_dp_mst_up_req_work(stru
  
  static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
  {
-       struct drm_dp_sideband_msg_hdr *hdr = &mgr->up_req_recv.initial_hdr;
        struct drm_dp_pending_up_req *up_req;
-       bool seqno;
  
-       if (!drm_dp_get_one_sb_msg(mgr, true))
+       if (!drm_dp_get_one_sb_msg(mgr, true, NULL))
                goto out;
  
        if (!mgr->up_req_recv.have_eomt)
        }
        INIT_LIST_HEAD(&up_req->next);
  
-       seqno = hdr->seqno;
        drm_dp_sideband_parse_req(&mgr->up_req_recv, &up_req->msg);
  
        if (up_req->msg.req_type != DP_CONNECTION_STATUS_NOTIFY &&
        }
  
        drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, up_req->msg.req_type,
-                                seqno, false);
+                                false);
  
        if (up_req->msg.req_type == DP_CONNECTION_STATUS_NOTIFY) {
                const struct drm_dp_connection_status_notify *conn_stat =
                              res_stat->available_pbn);
        }
  
-       up_req->hdr = *hdr;
+       up_req->hdr = mgr->up_req_recv.initial_hdr;
        mutex_lock(&mgr->up_req_lock);
        list_add_tail(&up_req->next, &mgr->up_req_list);
        mutex_unlock(&mgr->up_req_lock);
@@@ -4050,27 -4010,6 +4014,6 @@@ out
  }
  EXPORT_SYMBOL(drm_dp_mst_detect_port);
  
- /**
-  * drm_dp_mst_port_has_audio() - Check whether port has audio capability or not
-  * @mgr: manager for this port
-  * @port: unverified pointer to a port.
-  *
-  * This returns whether the port supports audio or not.
-  */
- bool drm_dp_mst_port_has_audio(struct drm_dp_mst_topology_mgr *mgr,
-                                       struct drm_dp_mst_port *port)
- {
-       bool ret = false;
-       port = drm_dp_mst_topology_get_port_validated(mgr, port);
-       if (!port)
-               return ret;
-       ret = port->has_audio;
-       drm_dp_mst_topology_put_port(port);
-       return ret;
- }
- EXPORT_SYMBOL(drm_dp_mst_port_has_audio);
  /**
   * drm_dp_mst_get_edid() - get EDID for an MST port
   * @connector: toplevel connector to get EDID for
@@@ -4299,7 -4238,6 +4242,7 @@@ int drm_dp_atomic_release_vcpi_slots(st
        if (pos->vcpi) {
                drm_dp_mst_put_port_malloc(port);
                pos->vcpi = 0;
 +              pos->pbn = 0;
        }
  
        return 0;
@@@ -4448,42 -4386,58 +4391,58 @@@ fail
        return ret;
  }
  
+ static int do_get_act_status(struct drm_dp_aux *aux)
+ {
+       int ret;
+       u8 status;
+       ret = drm_dp_dpcd_readb(aux, DP_PAYLOAD_TABLE_UPDATE_STATUS, &status);
+       if (ret < 0)
+               return ret;
+       return status;
+ }
  
  /**
-  * drm_dp_check_act_status() - Check ACT handled status.
+  * drm_dp_check_act_status() - Polls for ACT handled status.
   * @mgr: manager to use
   *
-  * Check the payload status bits in the DPCD for ACT handled completion.
+  * Tries waiting for the MST hub to finish updating it's payload table by
+  * polling for the ACT handled bit for up to 3 seconds (yes-some hubs really
+  * take that long).
+  *
+  * Returns:
+  * 0 if the ACT was handled in time, negative error code on failure.
   */
  int drm_dp_check_act_status(struct drm_dp_mst_topology_mgr *mgr)
  {
-       u8 status;
-       int ret;
-       int count = 0;
-       do {
-               ret = drm_dp_dpcd_readb(mgr->aux, DP_PAYLOAD_TABLE_UPDATE_STATUS, &status);
-               if (ret < 0) {
-                       DRM_DEBUG_KMS("failed to read payload table status %d\n", ret);
-                       goto fail;
-               }
-               if (status & DP_PAYLOAD_ACT_HANDLED)
-                       break;
-               count++;
-               udelay(100);
-       } while (count < 30);
-       if (!(status & DP_PAYLOAD_ACT_HANDLED)) {
-               DRM_DEBUG_KMS("failed to get ACT bit %d after %d retries\n", status, count);
-               ret = -EINVAL;
-               goto fail;
+       /*
+        * There doesn't seem to be any recommended retry count or timeout in
+        * the MST specification. Since some hubs have been observed to take
+        * over 1 second to update their payload allocations under certain
+        * conditions, we use a rather large timeout value.
+        */
+       const int timeout_ms = 3000;
+       int ret, status;
+       ret = readx_poll_timeout(do_get_act_status, mgr->aux, status,
+                                status & DP_PAYLOAD_ACT_HANDLED || status < 0,
+                                200, timeout_ms * USEC_PER_MSEC);
+       if (ret < 0 && status >= 0) {
+               DRM_ERROR("Failed to get ACT after %dms, last status: %02x\n",
+                         timeout_ms, status);
+               return -EINVAL;
+       } else if (status < 0) {
+               /*
+                * Failure here isn't unexpected - the hub may have
+                * just been unplugged
+                */
+               DRM_DEBUG_KMS("Failed to read payload table status: %d\n",
+                             status);
+               return status;
        }
        return 0;
- fail:
-       return ret;
  }
  EXPORT_SYMBOL(drm_dp_check_act_status);
  
@@@ -4674,28 -4628,18 +4633,18 @@@ static void drm_dp_tx_work(struct work_
        struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, tx_work);
  
        mutex_lock(&mgr->qlock);
-       if (!list_empty(&mgr->tx_msg_downq) && !mgr->is_waiting_for_dwn_reply)
+       if (!list_empty(&mgr->tx_msg_downq))
                process_single_down_tx_qlock(mgr);
        mutex_unlock(&mgr->qlock);
  }
  
- static inline void drm_dp_destroy_connector(struct drm_dp_mst_port *port)
+ static inline void
+ drm_dp_delayed_destroy_port(struct drm_dp_mst_port *port)
  {
-       if (!port->connector)
-               return;
-       if (port->mgr->cbs->destroy_connector) {
-               port->mgr->cbs->destroy_connector(port->mgr, port->connector);
-       } else {
+       if (port->connector) {
                drm_connector_unregister(port->connector);
                drm_connector_put(port->connector);
        }
- }
- static inline void
- drm_dp_delayed_destroy_port(struct drm_dp_mst_port *port)
- {
-       drm_dp_destroy_connector(port);
  
        drm_dp_port_set_pdt(port, DP_PEER_DEVICE_NONE, port->mcs);
        drm_dp_mst_put_port_malloc(port);
@@@ -4705,26 -4649,25 +4654,25 @@@ static inline voi
  drm_dp_delayed_destroy_mstb(struct drm_dp_mst_branch *mstb)
  {
        struct drm_dp_mst_topology_mgr *mgr = mstb->mgr;
-       struct drm_dp_mst_port *port, *tmp;
+       struct drm_dp_mst_port *port, *port_tmp;
+       struct drm_dp_sideband_msg_tx *txmsg, *txmsg_tmp;
        bool wake_tx = false;
  
        mutex_lock(&mgr->lock);
-       list_for_each_entry_safe(port, tmp, &mstb->ports, next) {
+       list_for_each_entry_safe(port, port_tmp, &mstb->ports, next) {
                list_del(&port->next);
                drm_dp_mst_topology_put_port(port);
        }
        mutex_unlock(&mgr->lock);
  
-       /* drop any tx slots msg */
+       /* drop any tx slot msg */
        mutex_lock(&mstb->mgr->qlock);
-       if (mstb->tx_slots[0]) {
-               mstb->tx_slots[0]->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
-               mstb->tx_slots[0] = NULL;
-               wake_tx = true;
-       }
-       if (mstb->tx_slots[1]) {
-               mstb->tx_slots[1]->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
-               mstb->tx_slots[1] = NULL;
+       list_for_each_entry_safe(txmsg, txmsg_tmp, &mgr->tx_msg_downq, next) {
+               if (txmsg->dst != mstb)
+                       continue;
+               txmsg->state = DRM_DP_SIDEBAND_TX_TIMEOUT;
+               list_del(&txmsg->next);
                wake_tx = true;
        }
        mutex_unlock(&mstb->mgr->qlock);
@@@ -5499,7 -5442,7 +5447,7 @@@ struct drm_dp_aux *drm_dp_mst_dsc_aux_f
  {
        struct drm_dp_mst_port *immediate_upstream_port;
        struct drm_dp_mst_port *fec_port;
 -      struct drm_dp_desc desc = { };
 +      struct drm_dp_desc desc = { };
        u8 endpoint_fec;
        u8 endpoint_dsc;
  
index d96e3ce3e5359ef5d96438cfdd74500246fff621,3bd95c4b02eba92a5d8cac88f95647509fb54146..fed653f13c266ce8ad3f748b1d1971660ea9893f
@@@ -191,11 -191,10 +191,11 @@@ static const struct edid_quirk 
        { "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP },
        { "HVR", 0xaa02, EDID_QUIRK_NON_DESKTOP },
  
 -      /* Oculus Rift DK1, DK2, and CV1 VR Headsets */
 +      /* Oculus Rift DK1, DK2, CV1 and Rift S VR Headsets */
        { "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP },
        { "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP },
        { "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP },
 +      { "OVR", 0x0012, EDID_QUIRK_NON_DESKTOP },
  
        /* Windows Mixed Reality Headsets */
        { "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP },
@@@ -1584,8 -1583,6 +1584,6 @@@ module_param_named(edid_fixup, edid_fix
  MODULE_PARM_DESC(edid_fixup,
                 "Minimum number of valid EDID header bytes (0-8, default 6)");
  
- static void drm_get_displayid(struct drm_connector *connector,
-                             struct edid *edid);
  static int validate_displayid(u8 *displayid, int length, int idx);
  
  static int drm_edid_block_checksum(const u8 *raw_edid)
@@@ -2019,18 -2016,13 +2017,13 @@@ EXPORT_SYMBOL(drm_probe_ddc)
  struct edid *drm_get_edid(struct drm_connector *connector,
                          struct i2c_adapter *adapter)
  {
-       struct edid *edid;
        if (connector->force == DRM_FORCE_OFF)
                return NULL;
  
        if (connector->force == DRM_FORCE_UNSPECIFIED && !drm_probe_ddc(adapter))
                return NULL;
  
-       edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
-       if (edid)
-               drm_get_displayid(connector, edid);
-       return edid;
+       return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
  }
  EXPORT_SYMBOL(drm_get_edid);
  
@@@ -2388,6 -2380,14 +2381,14 @@@ bad_std_timing(u8 a, u8 b
               (a == 0x20 && b == 0x20);
  }
  
+ static int drm_mode_hsync(const struct drm_display_mode *mode)
+ {
+       if (mode->htotal <= 0)
+               return 0;
+       return DIV_ROUND_CLOSEST(mode->clock, mode->htotal);
+ }
  /**
   * drm_mode_std - convert standard mode info (width, height, refresh) into mode
   * @connector: connector of for the EDID block
@@@ -3213,16 -3213,33 +3214,33 @@@ static u8 *drm_find_edid_extension(cons
  }
  
  
- static u8 *drm_find_displayid_extension(const struct edid *edid)
+ static u8 *drm_find_displayid_extension(const struct edid *edid,
+                                       int *length, int *idx)
  {
-       return drm_find_edid_extension(edid, DISPLAYID_EXT);
+       u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT);
+       struct displayid_hdr *base;
+       int ret;
+       if (!displayid)
+               return NULL;
+       /* EDID extensions block checksum isn't for us */
+       *length = EDID_LENGTH - 1;
+       *idx = 1;
+       ret = validate_displayid(displayid, *length, *idx);
+       if (ret)
+               return NULL;
+       base = (struct displayid_hdr *)&displayid[*idx];
+       *length = *idx + sizeof(*base) + base->bytes;
+       return displayid;
  }
  
  static u8 *drm_find_cea_extension(const struct edid *edid)
  {
-       int ret;
-       int idx = 1;
-       int length = EDID_LENGTH;
+       int length, idx;
        struct displayid_block *block;
        u8 *cea;
        u8 *displayid;
                return cea;
  
        /* CEA blocks can also be found embedded in a DisplayID block */
-       displayid = drm_find_displayid_extension(edid);
+       displayid = drm_find_displayid_extension(edid, &length, &idx);
        if (!displayid)
                return NULL;
  
-       ret = validate_displayid(displayid, length, idx);
-       if (ret)
-               return NULL;
        idx += sizeof(struct displayid_hdr);
        for_each_displayid_db(displayid, block, idx, length) {
                if (block->tag == DATA_BLOCK_CTA) {
@@@ -5085,7 -5098,7 +5099,7 @@@ u32 drm_add_display_info(struct drm_con
  
  static int validate_displayid(u8 *displayid, int length, int idx)
  {
-       int i;
+       int i, dispid_length;
        u8 csum = 0;
        struct displayid_hdr *base;
  
        DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
                      base->rev, base->bytes, base->prod_id, base->ext_count);
  
-       if (base->bytes + 5 > length - idx)
+       /* +1 for DispID checksum */
+       dispid_length = sizeof(*base) + base->bytes + 1;
+       if (dispid_length > length - idx)
                return -EINVAL;
-       for (i = idx; i <= base->bytes + 5; i++) {
-               csum += displayid[i];
-       }
+       for (i = 0; i < dispid_length; i++)
+               csum += displayid[idx + i];
        if (csum) {
                DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
                return -EINVAL;
        }
        return 0;
  }
  
@@@ -5112,7 -5128,7 +5129,7 @@@ static struct drm_display_mode *drm_mod
        struct drm_display_mode *mode;
        unsigned pixel_clock = (timings->pixel_clock[0] |
                                (timings->pixel_clock[1] << 8) |
 -                              (timings->pixel_clock[2] << 16));
 +                              (timings->pixel_clock[2] << 16)) + 1;
        unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1;
        unsigned hblank = (timings->hblank[0] | timings->hblank[1] << 8) + 1;
        unsigned hsync = (timings->hsync[0] | (timings->hsync[1] & 0x7f) << 8) + 1;
@@@ -5181,20 -5197,14 +5198,14 @@@ static int add_displayid_detailed_modes
                                        struct edid *edid)
  {
        u8 *displayid;
-       int ret;
-       int idx = 1;
-       int length = EDID_LENGTH;
+       int length, idx;
        struct displayid_block *block;
        int num_modes = 0;
  
-       displayid = drm_find_displayid_extension(edid);
+       displayid = drm_find_displayid_extension(edid, &length, &idx);
        if (!displayid)
                return 0;
  
-       ret = validate_displayid(displayid, length, idx);
-       if (ret)
-               return 0;
        idx += sizeof(struct displayid_hdr);
        for_each_displayid_db(displayid, block, idx, length) {
                switch (block->tag) {
@@@ -5783,9 -5793,9 +5794,9 @@@ drm_hdmi_vendor_infoframe_from_display_
  EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode);
  
  static int drm_parse_tiled_block(struct drm_connector *connector,
-                                struct displayid_block *block)
+                                const struct displayid_block *block)
  {
-       struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block;
+       const struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block;
        u16 w, h;
        u8 tile_v_loc, tile_h_loc;
        u8 num_v_tile, num_h_tile;
        return 0;
  }
  
- static int drm_parse_display_id(struct drm_connector *connector,
-                               u8 *displayid, int length,
-                               bool is_edid_extension)
+ static int drm_displayid_parse_tiled(struct drm_connector *connector,
+                                    const u8 *displayid, int length, int idx)
  {
-       /* if this is an EDID extension the first byte will be 0x70 */
-       int idx = 0;
-       struct displayid_block *block;
+       const struct displayid_block *block;
        int ret;
  
-       if (is_edid_extension)
-               idx = 1;
-       ret = validate_displayid(displayid, length, idx);
-       if (ret)
-               return ret;
        idx += sizeof(struct displayid_hdr);
        for_each_displayid_db(displayid, block, idx, length) {
                DRM_DEBUG_KMS("block id 0x%x, rev %d, len %d\n",
                        if (ret)
                                return ret;
                        break;
-               case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
-                       /* handled in mode gathering code. */
-                       break;
-               case DATA_BLOCK_CTA:
-                       /* handled in the cea parser code. */
-                       break;
                default:
                        DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag);
                        break;
        return 0;
  }
  
static void drm_get_displayid(struct drm_connector *connector,
-                             struct edid *edid)
void drm_update_tile_info(struct drm_connector *connector,
+                         const struct edid *edid)
  {
-       void *displayid = NULL;
+       const void *displayid = NULL;
+       int length, idx;
        int ret;
        connector->has_tile = false;
-       displayid = drm_find_displayid_extension(edid);
+       displayid = drm_find_displayid_extension(edid, &length, &idx);
        if (!displayid) {
                /* drop reference to any tile group we had */
                goto out_drop_ref;
        }
  
-       ret = drm_parse_display_id(connector, displayid, EDID_LENGTH, true);
+       ret = drm_displayid_parse_tiled(connector, displayid, length, idx);
        if (ret < 0)
                goto out_drop_ref;
        if (!connector->has_tile)
index 6a1f6c802415518319b1393c9d954a82f7af231e,7194e67e78bd2412bad54eab4dc5e1b5eeced463..2f12b8c1d01c13ec8d97304beeb51fad42e0e04c
@@@ -569,6 -569,9 +569,6 @@@ ssize_t drm_read(struct file *filp, cha
        struct drm_device *dev = file_priv->minor->dev;
        ssize_t ret;
  
 -      if (!access_ok(buffer, count))
 -              return -EFAULT;
 -
        ret = mutex_lock_interruptible(&file_priv->event_read_lock);
        if (ret)
                return ret;
@@@ -610,7 -613,8 +610,8 @@@ put_back_event
                                file_priv->event_space -= length;
                                list_add(&e->link, &file_priv->event_list);
                                spin_unlock_irq(&dev->event_lock);
-                               wake_up_interruptible(&file_priv->event_wait);
+                               wake_up_interruptible_poll(&file_priv->event_wait,
+                                       EPOLLIN | EPOLLRDNORM);
                                break;
                        }
  
@@@ -806,7 -810,8 +807,8 @@@ void drm_send_event_locked(struct drm_d
        list_del(&e->pending_link);
        list_add_tail(&e->link,
                      &e->file_priv->event_list);
-       wake_up_interruptible(&e->file_priv->event_wait);
+       wake_up_interruptible_poll(&e->file_priv->event_wait,
+               EPOLLIN | EPOLLRDNORM);
  }
  EXPORT_SYMBOL(drm_send_event_locked);
  
index c2b8d2a953aea7d30e65da7814e3c10331d3410c,73e31dd4e442ac7130bb6f2be6ad37598bbf2576..328502aafaf7235bd8ae864cc06ba52e50c7bc8d
@@@ -599,8 -599,8 +599,8 @@@ static const struct drm_ioctl_desc drm_
        DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH),
  
-       DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, 0),
  
        DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY),
        DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
   *     };
   *
   * Please make sure that you follow all the best practices from
 - * ``Documentation/ioctl/botching-up-ioctls.rst``. Note that drm_ioctl()
 + * ``Documentation/process/botching-up-ioctls.rst``. Note that drm_ioctl()
   * automatically zero-extends structures, hence make sure you can add more stuff
   * at the end, i.e. don't put a variable sized array there.
   *
index 7585d8f68fb94ee7dfd55528132c48c2184de0e8,27c948f5dfeb7ea0baf55339a19aa2727b35f50f..f9afe11c50f0c7c26eb44b0ab86791b6c25cdd0c
@@@ -231,21 -231,11 +231,11 @@@ static struct drm_info_list etnaviv_deb
                {"ring", show_each_gpu, 0, etnaviv_ring_show},
  };
  
- static int etnaviv_debugfs_init(struct drm_minor *minor)
+ static void etnaviv_debugfs_init(struct drm_minor *minor)
  {
-       struct drm_device *dev = minor->dev;
-       int ret;
-       ret = drm_debugfs_create_files(etnaviv_debugfs_list,
-                       ARRAY_SIZE(etnaviv_debugfs_list),
-                       minor->debugfs_root, minor);
-       if (ret) {
-               dev_err(dev->dev, "could not install etnaviv_debugfs_list\n");
-               return ret;
-       }
-       return ret;
+       drm_debugfs_create_files(etnaviv_debugfs_list,
+                                ARRAY_SIZE(etnaviv_debugfs_list),
+                                minor->debugfs_root, minor);
  }
  #endif
  
@@@ -736,7 -726,7 +726,7 @@@ static void __exit etnaviv_exit(void
  module_exit(etnaviv_exit);
  
  MODULE_AUTHOR("Christian Gmeiner <[email protected]>");
 -MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
 +MODULE_AUTHOR("Russell King <[email protected]>");
  MODULE_AUTHOR("Lucas Stach <[email protected]>");
  MODULE_DESCRIPTION("etnaviv DRM Driver");
  MODULE_LICENSE("GPL v2");
index 8a4e9c1cbf6c1262d9e68e85760b899e502d46bf,c0d59d48e1986aee468d76cee45e78340cf5ae0c..3ce185670ca47da9304999ce658fad991d237941
@@@ -15,8 -15,8 +15,8 @@@
  
  #include "gem/i915_gem_ioctls.h"
  #include "gt/intel_context.h"
- #include "gt/intel_engine_pool.h"
  #include "gt/intel_gt.h"
+ #include "gt/intel_gt_buffer_pool.h"
  #include "gt/intel_gt_pm.h"
  #include "gt/intel_ring.h"
  
@@@ -40,6 -40,11 +40,11 @@@ struct eb_vma 
        u32 handle;
  };
  
+ struct eb_vma_array {
+       struct kref kref;
+       struct eb_vma vma[];
+ };
  enum {
        FORCE_CPU_RELOC = 1,
        FORCE_GTT_RELOC,
@@@ -52,7 -57,6 +57,6 @@@
  #define __EXEC_OBJECT_NEEDS_MAP               BIT(29)
  #define __EXEC_OBJECT_NEEDS_BIAS      BIT(28)
  #define __EXEC_OBJECT_INTERNAL_FLAGS  (~0u << 28) /* all of the above */
- #define __EXEC_OBJECT_RESERVED (__EXEC_OBJECT_HAS_PIN | __EXEC_OBJECT_HAS_FENCE)
  
  #define __EXEC_HAS_RELOC      BIT(31)
  #define __EXEC_INTERNAL_FLAGS (~0u << 31)
@@@ -264,7 -268,9 +268,9 @@@ struct i915_execbuffer 
                bool has_fence : 1;
                bool needs_unfenced : 1;
  
+               struct i915_vma *target;
                struct i915_request *rq;
+               struct i915_vma *rq_vma;
                u32 *rq_cmd;
                unsigned int rq_size;
        } reloc_cache;
         */
        int lut_size;
        struct hlist_head *buckets; /** ht for relocation handles */
+       struct eb_vma_array *array;
  };
  
  static inline bool eb_use_cmdparser(const struct i915_execbuffer *eb)
                 eb->args->batch_len);
  }
  
+ static struct eb_vma_array *eb_vma_array_create(unsigned int count)
+ {
+       struct eb_vma_array *arr;
+       arr = kvmalloc(struct_size(arr, vma, count), GFP_KERNEL | __GFP_NOWARN);
+       if (!arr)
+               return NULL;
+       kref_init(&arr->kref);
+       arr->vma[0].vma = NULL;
+       return arr;
+ }
+ static inline void eb_unreserve_vma(struct eb_vma *ev)
+ {
+       struct i915_vma *vma = ev->vma;
+       if (unlikely(ev->flags & __EXEC_OBJECT_HAS_FENCE))
+               __i915_vma_unpin_fence(vma);
+       if (ev->flags & __EXEC_OBJECT_HAS_PIN)
+               __i915_vma_unpin(vma);
+       ev->flags &= ~(__EXEC_OBJECT_HAS_PIN |
+                      __EXEC_OBJECT_HAS_FENCE);
+ }
+ static void eb_vma_array_destroy(struct kref *kref)
+ {
+       struct eb_vma_array *arr = container_of(kref, typeof(*arr), kref);
+       struct eb_vma *ev = arr->vma;
+       while (ev->vma) {
+               eb_unreserve_vma(ev);
+               i915_vma_put(ev->vma);
+               ev++;
+       }
+       kvfree(arr);
+ }
+ static void eb_vma_array_put(struct eb_vma_array *arr)
+ {
+       kref_put(&arr->kref, eb_vma_array_destroy);
+ }
  static int eb_create(struct i915_execbuffer *eb)
  {
+       /* Allocate an extra slot for use by the command parser + sentinel */
+       eb->array = eb_vma_array_create(eb->buffer_count + 2);
+       if (!eb->array)
+               return -ENOMEM;
+       eb->vma = eb->array->vma;
        if (!(eb->args->flags & I915_EXEC_HANDLE_LUT)) {
                unsigned int size = 1 + ilog2(eb->buffer_count);
  
                                break;
                } while (--size);
  
-               if (unlikely(!size))
+               if (unlikely(!size)) {
+                       eb_vma_array_put(eb->array);
                        return -ENOMEM;
+               }
  
                eb->lut_size = size;
        } else {
@@@ -368,6 -431,32 +431,32 @@@ eb_vma_misplaced(const struct drm_i915_
        return false;
  }
  
+ static u64 eb_pin_flags(const struct drm_i915_gem_exec_object2 *entry,
+                       unsigned int exec_flags)
+ {
+       u64 pin_flags = 0;
+       if (exec_flags & EXEC_OBJECT_NEEDS_GTT)
+               pin_flags |= PIN_GLOBAL;
+       /*
+        * Wa32bitGeneralStateOffset & Wa32bitInstructionBaseOffset,
+        * limit address to the first 4GBs for unflagged objects.
+        */
+       if (!(exec_flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS))
+               pin_flags |= PIN_ZONE_4G;
+       if (exec_flags & __EXEC_OBJECT_NEEDS_MAP)
+               pin_flags |= PIN_MAPPABLE;
+       if (exec_flags & EXEC_OBJECT_PINNED)
+               pin_flags |= entry->offset | PIN_OFFSET_FIXED;
+       else if (exec_flags & __EXEC_OBJECT_NEEDS_BIAS)
+               pin_flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
+       return pin_flags;
+ }
  static inline bool
  eb_pin_vma(struct i915_execbuffer *eb,
           const struct drm_i915_gem_exec_object2 *entry,
        if (unlikely(ev->flags & EXEC_OBJECT_NEEDS_GTT))
                pin_flags |= PIN_GLOBAL;
  
-       if (unlikely(i915_vma_pin(vma, 0, 0, pin_flags)))
-               return false;
+       /* Attempt to reuse the current location if available */
+       if (unlikely(i915_vma_pin(vma, 0, 0, pin_flags))) {
+               if (entry->flags & EXEC_OBJECT_PINNED)
+                       return false;
+               /* Failing that pick any _free_ space if suitable */
+               if (unlikely(i915_vma_pin(vma,
+                                         entry->pad_to_size,
+                                         entry->alignment,
+                                         eb_pin_flags(entry, ev->flags) |
+                                         PIN_USER | PIN_NOEVICT)))
+                       return false;
+       }
  
        if (unlikely(ev->flags & EXEC_OBJECT_NEEDS_FENCE)) {
                if (unlikely(i915_vma_pin_fence(vma))) {
        return !eb_vma_misplaced(entry, vma, ev->flags);
  }
  
- static inline void __eb_unreserve_vma(struct i915_vma *vma, unsigned int flags)
- {
-       GEM_BUG_ON(!(flags & __EXEC_OBJECT_HAS_PIN));
-       if (unlikely(flags & __EXEC_OBJECT_HAS_FENCE))
-               __i915_vma_unpin_fence(vma);
-       __i915_vma_unpin(vma);
- }
- static inline void
- eb_unreserve_vma(struct eb_vma *ev)
- {
-       if (!(ev->flags & __EXEC_OBJECT_HAS_PIN))
-               return;
-       __eb_unreserve_vma(ev->vma, ev->flags);
-       ev->flags &= ~__EXEC_OBJECT_RESERVED;
- }
  static int
  eb_validate_vma(struct i915_execbuffer *eb,
                struct drm_i915_gem_exec_object2 *entry,
@@@ -481,7 -561,7 +561,7 @@@ eb_add_vma(struct i915_execbuffer *eb
  
        GEM_BUG_ON(i915_vma_is_closed(vma));
  
-       ev->vma = i915_vma_get(vma);
+       ev->vma = vma;
        ev->exec = entry;
        ev->flags = entry->flags;
  
@@@ -547,28 -627,9 +627,9 @@@ static int eb_reserve_vma(const struct 
                          u64 pin_flags)
  {
        struct drm_i915_gem_exec_object2 *entry = ev->exec;
-       unsigned int exec_flags = ev->flags;
        struct i915_vma *vma = ev->vma;
        int err;
  
-       if (exec_flags & EXEC_OBJECT_NEEDS_GTT)
-               pin_flags |= PIN_GLOBAL;
-       /*
-        * Wa32bitGeneralStateOffset & Wa32bitInstructionBaseOffset,
-        * limit address to the first 4GBs for unflagged objects.
-        */
-       if (!(exec_flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS))
-               pin_flags |= PIN_ZONE_4G;
-       if (exec_flags & __EXEC_OBJECT_NEEDS_MAP)
-               pin_flags |= PIN_MAPPABLE;
-       if (exec_flags & EXEC_OBJECT_PINNED)
-               pin_flags |= entry->offset | PIN_OFFSET_FIXED;
-       else if (exec_flags & __EXEC_OBJECT_NEEDS_BIAS)
-               pin_flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
        if (drm_mm_node_allocated(&vma->node) &&
            eb_vma_misplaced(entry, vma, ev->flags)) {
                err = i915_vma_unbind(vma);
  
        err = i915_vma_pin(vma,
                           entry->pad_to_size, entry->alignment,
-                          pin_flags);
+                          eb_pin_flags(entry, ev->flags) | pin_flags);
        if (err)
                return err;
  
                eb->args->flags |= __EXEC_HAS_RELOC;
        }
  
-       if (unlikely(exec_flags & EXEC_OBJECT_NEEDS_FENCE)) {
+       if (unlikely(ev->flags & EXEC_OBJECT_NEEDS_FENCE)) {
                err = i915_vma_pin_fence(vma);
                if (unlikely(err)) {
                        i915_vma_unpin(vma);
                }
  
                if (vma->fence)
-                       exec_flags |= __EXEC_OBJECT_HAS_FENCE;
+                       ev->flags |= __EXEC_OBJECT_HAS_FENCE;
        }
  
-       ev->flags = exec_flags | __EXEC_OBJECT_HAS_PIN;
+       ev->flags |= __EXEC_OBJECT_HAS_PIN;
        GEM_BUG_ON(eb_vma_misplaced(entry, vma, ev->flags));
  
        return 0;
@@@ -728,77 -789,117 +789,117 @@@ static int eb_select_context(struct i91
        return 0;
  }
  
- static int eb_lookup_vmas(struct i915_execbuffer *eb)
+ static int __eb_add_lut(struct i915_execbuffer *eb,
+                       u32 handle, struct i915_vma *vma)
  {
-       struct radix_tree_root *handles_vma = &eb->gem_context->handles_vma;
-       struct drm_i915_gem_object *obj;
-       unsigned int i, batch;
+       struct i915_gem_context *ctx = eb->gem_context;
+       struct i915_lut_handle *lut;
        int err;
  
-       if (unlikely(i915_gem_context_is_closed(eb->gem_context)))
-               return -ENOENT;
+       lut = i915_lut_handle_alloc();
+       if (unlikely(!lut))
+               return -ENOMEM;
  
-       INIT_LIST_HEAD(&eb->relocs);
-       INIT_LIST_HEAD(&eb->unbound);
+       i915_vma_get(vma);
+       if (!atomic_fetch_inc(&vma->open_count))
+               i915_vma_reopen(vma);
+       lut->handle = handle;
+       lut->ctx = ctx;
+       /* Check that the context hasn't been closed in the meantime */
+       err = -EINTR;
+       if (!mutex_lock_interruptible(&ctx->mutex)) {
+               err = -ENOENT;
+               if (likely(!i915_gem_context_is_closed(ctx)))
+                       err = radix_tree_insert(&ctx->handles_vma, handle, vma);
+               if (err == 0) { /* And nor has this handle */
+                       struct drm_i915_gem_object *obj = vma->obj;
+                       i915_gem_object_lock(obj);
+                       if (idr_find(&eb->file->object_idr, handle) == obj) {
+                               list_add(&lut->obj_link, &obj->lut_list);
+                       } else {
+                               radix_tree_delete(&ctx->handles_vma, handle);
+                               err = -ENOENT;
+                       }
+                       i915_gem_object_unlock(obj);
+               }
+               mutex_unlock(&ctx->mutex);
+       }
+       if (unlikely(err))
+               goto err;
  
-       batch = eb_batch_index(eb);
+       return 0;
  
-       for (i = 0; i < eb->buffer_count; i++) {
-               u32 handle = eb->exec[i].handle;
-               struct i915_lut_handle *lut;
+ err:
+       i915_vma_close(vma);
+       i915_vma_put(vma);
+       i915_lut_handle_free(lut);
+       return err;
+ }
+ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle)
+ {
+       do {
+               struct drm_i915_gem_object *obj;
                struct i915_vma *vma;
+               int err;
  
-               vma = radix_tree_lookup(handles_vma, handle);
+               rcu_read_lock();
+               vma = radix_tree_lookup(&eb->gem_context->handles_vma, handle);
                if (likely(vma))
-                       goto add_vma;
+                       vma = i915_vma_tryget(vma);
+               rcu_read_unlock();
+               if (likely(vma))
+                       return vma;
  
                obj = i915_gem_object_lookup(eb->file, handle);
-               if (unlikely(!obj)) {
-                       err = -ENOENT;
-                       goto err_vma;
-               }
+               if (unlikely(!obj))
+                       return ERR_PTR(-ENOENT);
  
                vma = i915_vma_instance(obj, eb->context->vm, NULL);
                if (IS_ERR(vma)) {
-                       err = PTR_ERR(vma);
-                       goto err_obj;
+                       i915_gem_object_put(obj);
+                       return vma;
                }
  
-               lut = i915_lut_handle_alloc();
-               if (unlikely(!lut)) {
-                       err = -ENOMEM;
-                       goto err_obj;
-               }
+               err = __eb_add_lut(eb, handle, vma);
+               if (likely(!err))
+                       return vma;
  
-               err = radix_tree_insert(handles_vma, handle, vma);
-               if (unlikely(err)) {
-                       i915_lut_handle_free(lut);
-                       goto err_obj;
              }
+               i915_gem_object_put(obj);
+               if (err != -EEXIST)
+                       return ERR_PTR(err);
+       } while (1);
+ }
  
-               /* transfer ref to lut */
-               if (!atomic_fetch_inc(&vma->open_count))
-                       i915_vma_reopen(vma);
-               lut->handle = handle;
-               lut->ctx = eb->gem_context;
+ static int eb_lookup_vmas(struct i915_execbuffer *eb)
+ {
+       unsigned int batch = eb_batch_index(eb);
+       unsigned int i;
+       int err = 0;
  
-               i915_gem_object_lock(obj);
-               list_add(&lut->obj_link, &obj->lut_list);
-               i915_gem_object_unlock(obj);
+       INIT_LIST_HEAD(&eb->relocs);
+       INIT_LIST_HEAD(&eb->unbound);
+       for (i = 0; i < eb->buffer_count; i++) {
+               struct i915_vma *vma;
+               vma = eb_lookup_vma(eb, eb->exec[i].handle);
+               if (IS_ERR(vma)) {
+                       err = PTR_ERR(vma);
+                       break;
+               }
  
- add_vma:
                err = eb_validate_vma(eb, &eb->exec[i], vma);
-               if (unlikely(err))
-                       goto err_vma;
+               if (unlikely(err)) {
+                       i915_vma_put(vma);
+                       break;
+               }
  
                eb_add_vma(eb, i, batch, vma);
        }
  
-       return 0;
- err_obj:
-       i915_gem_object_put(obj);
- err_vma:
        eb->vma[i].vma = NULL;
        return err;
  }
@@@ -823,31 -924,13 +924,13 @@@ eb_get_vma(const struct i915_execbuffe
        }
  }
  
- static void eb_release_vmas(const struct i915_execbuffer *eb)
- {
-       const unsigned int count = eb->buffer_count;
-       unsigned int i;
-       for (i = 0; i < count; i++) {
-               struct eb_vma *ev = &eb->vma[i];
-               struct i915_vma *vma = ev->vma;
-               if (!vma)
-                       break;
-               eb->vma[i].vma = NULL;
-               if (ev->flags & __EXEC_OBJECT_HAS_PIN)
-                       __eb_unreserve_vma(vma, ev->flags);
-               i915_vma_put(vma);
-       }
- }
  static void eb_destroy(const struct i915_execbuffer *eb)
  {
        GEM_BUG_ON(eb->reloc_cache.rq);
  
+       if (eb->array)
+               eb_vma_array_put(eb->array);
        if (eb->lut_size > 0)
                kfree(eb->buckets);
  }
@@@ -872,7 -955,7 +955,7 @@@ static void reloc_cache_init(struct rel
        cache->needs_unfenced = INTEL_INFO(i915)->unfenced_needs_alignment;
        cache->node.flags = 0;
        cache->rq = NULL;
-       cache->rq_size = 0;
+       cache->target = NULL;
  }
  
  static inline void *unmask_page(unsigned long p)
@@@ -894,29 -977,122 +977,122 @@@ static inline struct i915_ggtt *cache_t
        return &i915->ggtt;
  }
  
- static void reloc_gpu_flush(struct reloc_cache *cache)
+ #define RELOC_TAIL 4
+ static int reloc_gpu_chain(struct reloc_cache *cache)
+ {
+       struct intel_gt_buffer_pool_node *pool;
+       struct i915_request *rq = cache->rq;
+       struct i915_vma *batch;
+       u32 *cmd;
+       int err;
+       pool = intel_gt_get_buffer_pool(rq->engine->gt, PAGE_SIZE);
+       if (IS_ERR(pool))
+               return PTR_ERR(pool);
+       batch = i915_vma_instance(pool->obj, rq->context->vm, NULL);
+       if (IS_ERR(batch)) {
+               err = PTR_ERR(batch);
+               goto out_pool;
+       }
+       err = i915_vma_pin(batch, 0, 0, PIN_USER | PIN_NONBLOCK);
+       if (err)
+               goto out_pool;
+       GEM_BUG_ON(cache->rq_size + RELOC_TAIL > PAGE_SIZE  / sizeof(u32));
+       cmd = cache->rq_cmd + cache->rq_size;
+       *cmd++ = MI_ARB_CHECK;
+       if (cache->gen >= 8)
+               *cmd++ = MI_BATCH_BUFFER_START_GEN8;
+       else if (cache->gen >= 6)
+               *cmd++ = MI_BATCH_BUFFER_START;
+       else
+               *cmd++ = MI_BATCH_BUFFER_START | MI_BATCH_GTT;
+       *cmd++ = lower_32_bits(batch->node.start);
+       *cmd++ = upper_32_bits(batch->node.start); /* Always 0 for gen<8 */
+       i915_gem_object_flush_map(cache->rq_vma->obj);
+       i915_gem_object_unpin_map(cache->rq_vma->obj);
+       cache->rq_vma = NULL;
+       err = intel_gt_buffer_pool_mark_active(pool, rq);
+       if (err == 0) {
+               i915_vma_lock(batch);
+               err = i915_request_await_object(rq, batch->obj, false);
+               if (err == 0)
+                       err = i915_vma_move_to_active(batch, rq, 0);
+               i915_vma_unlock(batch);
+       }
+       i915_vma_unpin(batch);
+       if (err)
+               goto out_pool;
+       cmd = i915_gem_object_pin_map(batch->obj,
+                                     cache->has_llc ?
+                                     I915_MAP_FORCE_WB :
+                                     I915_MAP_FORCE_WC);
+       if (IS_ERR(cmd)) {
+               err = PTR_ERR(cmd);
+               goto out_pool;
+       }
+       /* Return with batch mapping (cmd) still pinned */
+       cache->rq_cmd = cmd;
+       cache->rq_size = 0;
+       cache->rq_vma = batch;
+ out_pool:
+       intel_gt_buffer_pool_put(pool);
+       return err;
+ }
+ static unsigned int reloc_bb_flags(const struct reloc_cache *cache)
  {
-       struct drm_i915_gem_object *obj = cache->rq->batch->obj;
+       return cache->gen > 5 ? 0 : I915_DISPATCH_SECURE;
+ }
+ static int reloc_gpu_flush(struct reloc_cache *cache)
+ {
+       struct i915_request *rq;
+       int err;
  
-       GEM_BUG_ON(cache->rq_size >= obj->base.size / sizeof(u32));
-       cache->rq_cmd[cache->rq_size] = MI_BATCH_BUFFER_END;
+       rq = fetch_and_zero(&cache->rq);
+       if (!rq)
+               return 0;
  
-       __i915_gem_object_flush_map(obj, 0, sizeof(u32) * (cache->rq_size + 1));
-       i915_gem_object_unpin_map(obj);
+       if (cache->rq_vma) {
+               struct drm_i915_gem_object *obj = cache->rq_vma->obj;
  
-       intel_gt_chipset_flush(cache->rq->engine->gt);
+               GEM_BUG_ON(cache->rq_size >= obj->base.size / sizeof(u32));
+               cache->rq_cmd[cache->rq_size++] = MI_BATCH_BUFFER_END;
  
-       i915_request_add(cache->rq);
-       cache->rq = NULL;
+               __i915_gem_object_flush_map(obj,
+                                           0, sizeof(u32) * cache->rq_size);
+               i915_gem_object_unpin_map(obj);
+       }
+       err = 0;
+       if (rq->engine->emit_init_breadcrumb)
+               err = rq->engine->emit_init_breadcrumb(rq);
+       if (!err)
+               err = rq->engine->emit_bb_start(rq,
+                                               rq->batch->node.start,
+                                               PAGE_SIZE,
+                                               reloc_bb_flags(cache));
+       if (err)
+               i915_request_set_error_once(rq, err);
+       intel_gt_chipset_flush(rq->engine->gt);
+       i915_request_add(rq);
+       return err;
  }
  
  static void reloc_cache_reset(struct reloc_cache *cache)
  {
        void *vaddr;
  
-       if (cache->rq)
-               reloc_gpu_flush(cache);
        if (!cache->vaddr)
                return;
  
@@@ -1109,17 -1285,17 +1285,17 @@@ static int reloc_move_to_gpu(struct i91
  }
  
  static int __reloc_gpu_alloc(struct i915_execbuffer *eb,
-                            struct i915_vma *vma,
+                            struct intel_engine_cs *engine,
                             unsigned int len)
  {
        struct reloc_cache *cache = &eb->reloc_cache;
-       struct intel_engine_pool_node *pool;
+       struct intel_gt_buffer_pool_node *pool;
        struct i915_request *rq;
        struct i915_vma *batch;
        u32 *cmd;
        int err;
  
-       pool = intel_engine_get_pool(eb->engine, PAGE_SIZE);
+       pool = intel_gt_get_buffer_pool(engine->gt, PAGE_SIZE);
        if (IS_ERR(pool))
                return PTR_ERR(pool);
  
                goto out_pool;
        }
  
-       batch = i915_vma_instance(pool->obj, vma->vm, NULL);
+       batch = i915_vma_instance(pool->obj, eb->context->vm, NULL);
        if (IS_ERR(batch)) {
                err = PTR_ERR(batch);
                goto err_unmap;
        if (err)
                goto err_unmap;
  
-       rq = i915_request_create(eb->context);
+       if (engine == eb->context->engine) {
+               rq = i915_request_create(eb->context);
+       } else {
+               struct intel_context *ce;
+               ce = intel_context_create(engine);
+               if (IS_ERR(ce)) {
+                       err = PTR_ERR(ce);
+                       goto err_unpin;
+               }
+               i915_vm_put(ce->vm);
+               ce->vm = i915_vm_get(eb->context->vm);
+               rq = intel_context_create_request(ce);
+               intel_context_put(ce);
+       }
        if (IS_ERR(rq)) {
                err = PTR_ERR(rq);
                goto err_unpin;
        }
  
-       err = intel_engine_pool_mark_active(pool, rq);
+       err = intel_gt_buffer_pool_mark_active(pool, rq);
        if (err)
                goto err_request;
  
-       err = reloc_move_to_gpu(rq, vma);
-       if (err)
-               goto err_request;
-       err = eb->engine->emit_bb_start(rq,
-                                       batch->node.start, PAGE_SIZE,
-                                       cache->gen > 5 ? 0 : I915_DISPATCH_SECURE);
-       if (err)
-               goto skip_request;
        i915_vma_lock(batch);
        err = i915_request_await_object(rq, batch->obj, false);
        if (err == 0)
        cache->rq = rq;
        cache->rq_cmd = cmd;
        cache->rq_size = 0;
+       cache->rq_vma = batch;
  
        /* Return with batch mapping (cmd) still pinned */
        goto out_pool;
@@@ -1189,124 -1372,206 +1372,206 @@@ err_unpin
  err_unmap:
        i915_gem_object_unpin_map(pool->obj);
  out_pool:
-       intel_engine_pool_put(pool);
+       intel_gt_buffer_pool_put(pool);
        return err;
  }
  
+ static bool reloc_can_use_engine(const struct intel_engine_cs *engine)
+ {
+       return engine->class != VIDEO_DECODE_CLASS || !IS_GEN(engine->i915, 6);
+ }
  static u32 *reloc_gpu(struct i915_execbuffer *eb,
                      struct i915_vma *vma,
                      unsigned int len)
  {
        struct reloc_cache *cache = &eb->reloc_cache;
        u32 *cmd;
-       if (cache->rq_size > PAGE_SIZE/sizeof(u32) - (len + 1))
-               reloc_gpu_flush(cache);
+       int err;
  
        if (unlikely(!cache->rq)) {
-               int err;
+               struct intel_engine_cs *engine = eb->engine;
  
-               if (!intel_engine_can_store_dword(eb->engine))
-                       return ERR_PTR(-ENODEV);
+               if (!reloc_can_use_engine(engine)) {
+                       engine = engine->gt->engine_class[COPY_ENGINE_CLASS][0];
+                       if (!engine)
+                               return ERR_PTR(-ENODEV);
+               }
  
-               err = __reloc_gpu_alloc(eb, vma, len);
+               err = __reloc_gpu_alloc(eb, engine, len);
                if (unlikely(err))
                        return ERR_PTR(err);
        }
  
+       if (vma != cache->target) {
+               err = reloc_move_to_gpu(cache->rq, vma);
+               if (unlikely(err)) {
+                       i915_request_set_error_once(cache->rq, err);
+                       return ERR_PTR(err);
+               }
+               cache->target = vma;
+       }
+       if (unlikely(cache->rq_size + len >
+                    PAGE_SIZE / sizeof(u32) - RELOC_TAIL)) {
+               err = reloc_gpu_chain(cache);
+               if (unlikely(err)) {
+                       i915_request_set_error_once(cache->rq, err);
+                       return ERR_PTR(err);
+               }
+       }
+       GEM_BUG_ON(cache->rq_size + len >= PAGE_SIZE  / sizeof(u32));
        cmd = cache->rq_cmd + cache->rq_size;
        cache->rq_size += len;
  
        return cmd;
  }
  
- static u64
- relocate_entry(struct i915_vma *vma,
-              const struct drm_i915_gem_relocation_entry *reloc,
-              struct i915_execbuffer *eb,
-              const struct i915_vma *target)
+ static inline bool use_reloc_gpu(struct i915_vma *vma)
  {
-       u64 offset = reloc->offset;
-       u64 target_offset = relocation_target(reloc, target);
-       bool wide = eb->reloc_cache.use_64bit_reloc;
-       void *vaddr;
+       if (DBG_FORCE_RELOC == FORCE_GPU_RELOC)
+               return true;
  
-       if (!eb->reloc_cache.vaddr &&
-           (DBG_FORCE_RELOC == FORCE_GPU_RELOC ||
-            !dma_resv_test_signaled_rcu(vma->resv, true))) {
-               const unsigned int gen = eb->reloc_cache.gen;
-               unsigned int len;
-               u32 *batch;
-               u64 addr;
-               if (wide)
-                       len = offset & 7 ? 8 : 5;
-               else if (gen >= 4)
-                       len = 4;
-               else
-                       len = 3;
+       if (DBG_FORCE_RELOC)
+               return false;
  
-               batch = reloc_gpu(eb, vma, len);
-               if (IS_ERR(batch))
-                       goto repeat;
+       return !dma_resv_test_signaled_rcu(vma->resv, true);
+ }
  
-               addr = gen8_canonical_addr(vma->node.start + offset);
-               if (wide) {
-                       if (offset & 7) {
-                               *batch++ = MI_STORE_DWORD_IMM_GEN4;
-                               *batch++ = lower_32_bits(addr);
-                               *batch++ = upper_32_bits(addr);
-                               *batch++ = lower_32_bits(target_offset);
-                               addr = gen8_canonical_addr(addr + 4);
-                               *batch++ = MI_STORE_DWORD_IMM_GEN4;
-                               *batch++ = lower_32_bits(addr);
-                               *batch++ = upper_32_bits(addr);
-                               *batch++ = upper_32_bits(target_offset);
-                       } else {
-                               *batch++ = (MI_STORE_DWORD_IMM_GEN4 | (1 << 21)) + 1;
-                               *batch++ = lower_32_bits(addr);
-                               *batch++ = upper_32_bits(addr);
-                               *batch++ = lower_32_bits(target_offset);
-                               *batch++ = upper_32_bits(target_offset);
-                       }
-               } else if (gen >= 6) {
+ static unsigned long vma_phys_addr(struct i915_vma *vma, u32 offset)
+ {
+       struct page *page;
+       unsigned long addr;
+       GEM_BUG_ON(vma->pages != vma->obj->mm.pages);
+       page = i915_gem_object_get_page(vma->obj, offset >> PAGE_SHIFT);
+       addr = PFN_PHYS(page_to_pfn(page));
+       GEM_BUG_ON(overflows_type(addr, u32)); /* expected dma32 */
+       return addr + offset_in_page(offset);
+ }
+ static bool __reloc_entry_gpu(struct i915_execbuffer *eb,
+                             struct i915_vma *vma,
+                             u64 offset,
+                             u64 target_addr)
+ {
+       const unsigned int gen = eb->reloc_cache.gen;
+       unsigned int len;
+       u32 *batch;
+       u64 addr;
+       if (gen >= 8)
+               len = offset & 7 ? 8 : 5;
+       else if (gen >= 4)
+               len = 4;
+       else
+               len = 3;
+       batch = reloc_gpu(eb, vma, len);
+       if (IS_ERR(batch))
+               return false;
+       addr = gen8_canonical_addr(vma->node.start + offset);
+       if (gen >= 8) {
+               if (offset & 7) {
                        *batch++ = MI_STORE_DWORD_IMM_GEN4;
-                       *batch++ = 0;
-                       *batch++ = addr;
-                       *batch++ = target_offset;
-               } else if (gen >= 4) {
-                       *batch++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
-                       *batch++ = 0;
-                       *batch++ = addr;
-                       *batch++ = target_offset;
+                       *batch++ = lower_32_bits(addr);
+                       *batch++ = upper_32_bits(addr);
+                       *batch++ = lower_32_bits(target_addr);
+                       addr = gen8_canonical_addr(addr + 4);
+                       *batch++ = MI_STORE_DWORD_IMM_GEN4;
+                       *batch++ = lower_32_bits(addr);
+                       *batch++ = upper_32_bits(addr);
+                       *batch++ = upper_32_bits(target_addr);
                } else {
-                       *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
-                       *batch++ = addr;
-                       *batch++ = target_offset;
+                       *batch++ = (MI_STORE_DWORD_IMM_GEN4 | (1 << 21)) + 1;
+                       *batch++ = lower_32_bits(addr);
+                       *batch++ = upper_32_bits(addr);
+                       *batch++ = lower_32_bits(target_addr);
+                       *batch++ = upper_32_bits(target_addr);
                }
-               goto out;
+       } else if (gen >= 6) {
+               *batch++ = MI_STORE_DWORD_IMM_GEN4;
+               *batch++ = 0;
+               *batch++ = addr;
+               *batch++ = target_addr;
+       } else if (IS_I965G(eb->i915)) {
+               *batch++ = MI_STORE_DWORD_IMM_GEN4;
+               *batch++ = 0;
+               *batch++ = vma_phys_addr(vma, offset);
+               *batch++ = target_addr;
+       } else if (gen >= 4) {
+               *batch++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
+               *batch++ = 0;
+               *batch++ = addr;
+               *batch++ = target_addr;
+       } else if (gen >= 3 &&
+                  !(IS_I915G(eb->i915) || IS_I915GM(eb->i915))) {
+               *batch++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
+               *batch++ = addr;
+               *batch++ = target_addr;
+       } else {
+               *batch++ = MI_STORE_DWORD_IMM;
+               *batch++ = vma_phys_addr(vma, offset);
+               *batch++ = target_addr;
        }
  
+       return true;
+ }
+ static bool reloc_entry_gpu(struct i915_execbuffer *eb,
+                           struct i915_vma *vma,
+                           u64 offset,
+                           u64 target_addr)
+ {
+       if (eb->reloc_cache.vaddr)
+               return false;
+       if (!use_reloc_gpu(vma))
+               return false;
+       return __reloc_entry_gpu(eb, vma, offset, target_addr);
+ }
+ static u64
+ relocate_entry(struct i915_vma *vma,
+              const struct drm_i915_gem_relocation_entry *reloc,
+              struct i915_execbuffer *eb,
+              const struct i915_vma *target)
+ {
+       u64 target_addr = relocation_target(reloc, target);
+       u64 offset = reloc->offset;
+       if (!reloc_entry_gpu(eb, vma, offset, target_addr)) {
+               bool wide = eb->reloc_cache.use_64bit_reloc;
+               void *vaddr;
  repeat:
-       vaddr = reloc_vaddr(vma->obj, &eb->reloc_cache, offset >> PAGE_SHIFT);
-       if (IS_ERR(vaddr))
-               return PTR_ERR(vaddr);
+               vaddr = reloc_vaddr(vma->obj,
+                                   &eb->reloc_cache,
+                                   offset >> PAGE_SHIFT);
+               if (IS_ERR(vaddr))
+                       return PTR_ERR(vaddr);
  
-       clflush_write32(vaddr + offset_in_page(offset),
-                       lower_32_bits(target_offset),
-                       eb->reloc_cache.vaddr);
+               GEM_BUG_ON(!IS_ALIGNED(offset, sizeof(u32)));
+               clflush_write32(vaddr + offset_in_page(offset),
+                               lower_32_bits(target_addr),
+                               eb->reloc_cache.vaddr);
  
-       if (wide) {
-               offset += sizeof(u32);
-               target_offset >>= 32;
-               wide = false;
-               goto repeat;
+               if (wide) {
+                       offset += sizeof(u32);
+                       target_addr >>= 32;
+                       wide = false;
+                       goto repeat;
+               }
        }
  
- out:
        return target->node.start | UPDATE;
  }
  
@@@ -1411,12 -1676,11 +1676,11 @@@ static int eb_relocate_vma(struct i915_
  {
  #define N_RELOC(x) ((x) / sizeof(struct drm_i915_gem_relocation_entry))
        struct drm_i915_gem_relocation_entry stack[N_RELOC(512)];
-       struct drm_i915_gem_relocation_entry __user *urelocs;
        const struct drm_i915_gem_exec_object2 *entry = ev->exec;
-       unsigned int remain;
+       struct drm_i915_gem_relocation_entry __user *urelocs =
+               u64_to_user_ptr(entry->relocs_ptr);
+       unsigned long remain = entry->relocation_count;
  
-       urelocs = u64_to_user_ptr(entry->relocs_ptr);
-       remain = entry->relocation_count;
        if (unlikely(remain > N_RELOC(ULONG_MAX)))
                return -EINVAL;
  
         * to read. However, if the array is not writable the user loses
         * the updated relocation values.
         */
-       if (unlikely(!access_ok(urelocs, remain*sizeof(*urelocs))))
+       if (unlikely(!access_ok(urelocs, remain * sizeof(*urelocs))))
                return -EFAULT;
  
        do {
                struct drm_i915_gem_relocation_entry *r = stack;
                unsigned int count =
-                       min_t(unsigned int, remain, ARRAY_SIZE(stack));
+                       min_t(unsigned long, remain, ARRAY_SIZE(stack));
                unsigned int copied;
  
                /*
@@@ -1494,9 -1758,7 +1758,7 @@@ static int eb_relocate(struct i915_exec
  {
        int err;
  
-       mutex_lock(&eb->gem_context->mutex);
        err = eb_lookup_vmas(eb);
-       mutex_unlock(&eb->gem_context->mutex);
        if (err)
                return err;
  
        /* The objects are in their final locations, apply the relocations. */
        if (eb->args->flags & __EXEC_HAS_RELOC) {
                struct eb_vma *ev;
+               int flush;
  
                list_for_each_entry(ev, &eb->relocs, reloc_link) {
                        err = eb_relocate_vma(eb, ev);
                        if (err)
-                               return err;
+                               break;
                }
+               flush = reloc_gpu_flush(&eb->reloc_cache);
+               if (!err)
+                       err = flush;
        }
  
-       return 0;
+       return err;
  }
  
  static int eb_move_to_gpu(struct i915_execbuffer *eb)
                        err = i915_vma_move_to_active(vma, eb->request, flags);
  
                i915_vma_unlock(vma);
-               __eb_unreserve_vma(vma, flags);
-               i915_vma_put(vma);
-               ev->vma = NULL;
+               eb_unreserve_vma(ev);
        }
        ww_acquire_fini(&acquire);
  
+       eb_vma_array_put(fetch_and_zero(&eb->array));
        if (unlikely(err))
                goto err_skip;
  
-       eb->exec = NULL;
        /* Unconditionally flush any chipset caches (for streaming writes). */
        intel_gt_chipset_flush(eb->engine->gt);
        return 0;
@@@ -1784,7 -2047,7 +2047,7 @@@ static int eb_parse_pipeline(struct i91
        dma_resv_add_excl_fence(shadow->resv, &pw->base.dma);
        dma_resv_unlock(shadow->resv);
  
-       dma_fence_work_commit(&pw->base);
+       dma_fence_work_commit_imm(&pw->base);
        return 0;
  
  err_batch_unlock:
@@@ -1804,7 -2067,7 +2067,7 @@@ err_free
  static int eb_parse(struct i915_execbuffer *eb)
  {
        struct drm_i915_private *i915 = eb->i915;
-       struct intel_engine_pool_node *pool;
+       struct intel_gt_buffer_pool_node *pool;
        struct i915_vma *shadow, *trampoline;
        unsigned int len;
        int err;
                len += I915_CMD_PARSER_TRAMPOLINE_SIZE;
        }
  
-       pool = intel_engine_get_pool(eb->engine, len);
+       pool = intel_gt_get_buffer_pool(eb->engine->gt, len);
        if (IS_ERR(pool))
                return PTR_ERR(pool);
  
        eb->vma[eb->buffer_count].vma = i915_vma_get(shadow);
        eb->vma[eb->buffer_count].flags = __EXEC_OBJECT_HAS_PIN;
        eb->batch = &eb->vma[eb->buffer_count++];
+       eb->vma[eb->buffer_count].vma = NULL;
  
        eb->trampoline = trampoline;
        eb->batch_start_offset = 0;
@@@ -1874,7 -2138,7 +2138,7 @@@ err_trampoline
  err_shadow:
        i915_vma_unpin(shadow);
  err:
-       intel_engine_pool_put(pool);
+       intel_gt_buffer_pool_put(pool);
        return err;
  }
  
@@@ -2318,39 -2582,13 +2582,13 @@@ static void eb_request_add(struct i915_
        /* Check that the context wasn't destroyed before submission */
        if (likely(!intel_context_is_closed(eb->context))) {
                attr = eb->gem_context->sched;
-               /*
-                * Boost actual workloads past semaphores!
-                *
-                * With semaphores we spin on one engine waiting for another,
-                * simply to reduce the latency of starting our work when
-                * the signaler completes. However, if there is any other
-                * work that we could be doing on this engine instead, that
-                * is better utilisation and will reduce the overall duration
-                * of the current work. To avoid PI boosting a semaphore
-                * far in the distance past over useful work, we keep a history
-                * of any semaphore use along our dependency chain.
-                */
-               if (!(rq->sched.flags & I915_SCHED_HAS_SEMAPHORE_CHAIN))
-                       attr.priority |= I915_PRIORITY_NOSEMAPHORE;
-               /*
-                * Boost priorities to new clients (new request flows).
-                *
-                * Allow interactive/synchronous clients to jump ahead of
-                * the bulk clients. (FQ_CODEL)
-                */
-               if (list_empty(&rq->sched.signalers_list))
-                       attr.priority |= I915_PRIORITY_WAIT;
        } else {
                /* Serialise with context_close via the add_to_timeline */
                i915_request_set_error_once(rq, -ENOENT);
                __i915_request_skip(rq);
        }
  
-       local_bh_disable();
        __i915_request_queue(rq, &attr);
-       local_bh_enable(); /* Kick the execlists tasklet if just scheduled */
  
        /* Try to clean up the client's timeline after submitting the request */
        if (prev)
@@@ -2369,7 -2607,6 +2607,6 @@@ i915_gem_do_execbuffer(struct drm_devic
        struct drm_i915_private *i915 = to_i915(dev);
        struct i915_execbuffer eb;
        struct dma_fence *in_fence = NULL;
-       struct dma_fence *exec_fence = NULL;
        struct sync_file *out_fence = NULL;
        struct i915_vma *batch;
        int out_fence_fd = -1;
                args->flags |= __EXEC_HAS_RELOC;
  
        eb.exec = exec;
-       eb.vma = (struct eb_vma *)(exec + args->buffer_count + 1);
-       eb.vma[0].vma = NULL;
  
        eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS;
        reloc_cache_init(&eb.reloc_cache, eb.i915);
        if (args->flags & I915_EXEC_IS_PINNED)
                eb.batch_flags |= I915_DISPATCH_PINNED;
  
-       if (args->flags & I915_EXEC_FENCE_IN) {
+ #define IN_FENCES (I915_EXEC_FENCE_IN | I915_EXEC_FENCE_SUBMIT)
+       if (args->flags & IN_FENCES) {
+               if ((args->flags & IN_FENCES) == IN_FENCES)
+                       return -EINVAL;
                in_fence = sync_file_get_fence(lower_32_bits(args->rsvd2));
                if (!in_fence)
                        return -EINVAL;
        }
-       if (args->flags & I915_EXEC_FENCE_SUBMIT) {
-               if (in_fence) {
-                       err = -EINVAL;
-                       goto err_in_fence;
-               }
-               exec_fence = sync_file_get_fence(lower_32_bits(args->rsvd2));
-               if (!exec_fence) {
-                       err = -EINVAL;
-                       goto err_in_fence;
-               }
-       }
+ #undef IN_FENCES
  
        if (args->flags & I915_EXEC_FENCE_OUT) {
                out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
                if (out_fence_fd < 0) {
                        err = out_fence_fd;
-                       goto err_exec_fence;
+                       goto err_in_fence;
                }
        }
  
        }
  
        if (in_fence) {
-               err = i915_request_await_dma_fence(eb.request, in_fence);
-               if (err < 0)
-                       goto err_request;
-       }
-       if (exec_fence) {
-               err = i915_request_await_execution(eb.request, exec_fence,
-                                                  eb.engine->bond_execute);
+               if (args->flags & I915_EXEC_FENCE_SUBMIT)
+                       err = i915_request_await_execution(eb.request,
+                                                          in_fence,
+                                                          eb.engine->bond_execute);
+               else
+                       err = i915_request_await_dma_fence(eb.request,
+                                                          in_fence);
                if (err < 0)
                        goto err_request;
        }
         */
        eb.request->batch = batch;
        if (batch->private)
-               intel_engine_pool_mark_active(batch->private, eb.request);
+               intel_gt_buffer_pool_mark_active(batch->private, eb.request);
  
        trace_i915_request_queue(eb.request, eb.batch_flags);
        err = eb_submit(&eb, batch);
@@@ -2592,10 -2818,8 +2818,8 @@@ err_batch_unpin
                i915_vma_unpin(batch);
  err_parse:
        if (batch->private)
-               intel_engine_pool_put(batch->private);
+               intel_gt_buffer_pool_put(batch->private);
  err_vma:
-       if (eb.exec)
-               eb_release_vmas(&eb);
        if (eb.trampoline)
                i915_vma_unpin(eb.trampoline);
        eb_unpin_engine(&eb);
@@@ -2606,8 -2830,6 +2830,6 @@@ err_destroy
  err_out_fence:
        if (out_fence_fd != -1)
                put_unused_fd(out_fence_fd);
- err_exec_fence:
-       dma_fence_put(exec_fence);
  err_in_fence:
        dma_fence_put(in_fence);
        return err;
  
  static size_t eb_element_size(void)
  {
-       return sizeof(struct drm_i915_gem_exec_object2) + sizeof(struct eb_vma);
+       return sizeof(struct drm_i915_gem_exec_object2);
  }
  
  static bool check_buffer_count(size_t count)
@@@ -2671,7 -2893,7 +2893,7 @@@ i915_gem_execbuffer_ioctl(struct drm_de
        /* Copy in the exec list from userland */
        exec_list = kvmalloc_array(count, sizeof(*exec_list),
                                   __GFP_NOWARN | GFP_KERNEL);
-       exec2_list = kvmalloc_array(count + 1, eb_element_size(),
+       exec2_list = kvmalloc_array(count, eb_element_size(),
                                    __GFP_NOWARN | GFP_KERNEL);
        if (exec_list == NULL || exec2_list == NULL) {
                drm_dbg(&i915->drm,
@@@ -2749,8 -2971,7 +2971,7 @@@ i915_gem_execbuffer2_ioctl(struct drm_d
        if (err)
                return err;
  
-       /* Allocate an extra slot for use by the command parser */
-       exec2_list = kvmalloc_array(count + 1, eb_element_size(),
+       exec2_list = kvmalloc_array(count, eb_element_size(),
                                    __GFP_NOWARN | GFP_KERNEL);
        if (exec2_list == NULL) {
                drm_dbg(&i915->drm, "Failed to allocate exec list for %zd buffers\n",
                 * And this range already got effectively checked earlier
                 * when we did the "copy_from_user()" above.
                 */
 -              if (!user_access_begin(user_exec_list, count * sizeof(*user_exec_list)))
 +              if (!user_write_access_begin(user_exec_list,
 +                                           count * sizeof(*user_exec_list)))
                        goto end;
  
                for (i = 0; i < args->buffer_count; i++) {
                                        end_user);
                }
  end_user:
 -              user_access_end();
 +              user_write_access_end();
  end:;
        }
  
        kvfree(exec2_list);
        return err;
  }
+ #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+ #include "selftests/i915_gem_execbuffer.c"
+ #endif
index e92ed96c9b239422776f18b7132f818fa04162fd,3a9bd8e4d8dbc15031c652db071f45dc5a529131..0fb1df71c637c088ad8292275ed6388dd7f85f6c
@@@ -58,10 -58,8 +58,8 @@@ static void set_context_pdp_root_pointe
  
  static void update_shadow_pdps(struct intel_vgpu_workload *workload)
  {
-       struct drm_i915_gem_object *ctx_obj =
-               workload->req->context->state->obj;
        struct execlist_ring_context *shadow_ring_context;
-       struct page *page;
+       struct intel_context *ctx = workload->req->context;
  
        if (WARN_ON(!workload->shadow_mm))
                return;
        if (WARN_ON(!atomic_read(&workload->shadow_mm->pincount)))
                return;
  
-       page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
-       shadow_ring_context = kmap(page);
+       shadow_ring_context = (struct execlist_ring_context *)ctx->lrc_reg_state;
        set_context_pdp_root_pointer(shadow_ring_context,
                        (void *)workload->shadow_mm->ppgtt_mm.shadow_pdps);
-       kunmap(page);
  }
  
  /*
@@@ -128,16 -124,24 +124,24 @@@ static int populate_shadow_context(stru
  {
        struct intel_vgpu *vgpu = workload->vgpu;
        struct intel_gvt *gvt = vgpu->gvt;
-       struct drm_i915_gem_object *ctx_obj =
-               workload->req->context->state->obj;
+       struct intel_context *ctx = workload->req->context;
        struct execlist_ring_context *shadow_ring_context;
-       struct page *page;
        void *dst;
+       void *context_base;
        unsigned long context_gpa, context_page_num;
+       unsigned long gpa_base; /* first gpa of consecutive GPAs */
+       unsigned long gpa_size; /* size of consecutive GPAs */
+       struct intel_vgpu_submission *s = &vgpu->submission;
        int i;
+       bool skip = false;
+       int ring_id = workload->engine->id;
+       GEM_BUG_ON(!intel_context_is_pinned(ctx));
+       context_base = (void *) ctx->lrc_reg_state -
+                               (LRC_STATE_PN << I915_GTT_PAGE_SHIFT);
  
-       page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
-       shadow_ring_context = kmap(page);
+       shadow_ring_context = (void *) ctx->lrc_reg_state;
  
        sr_oa_regs(workload, (u32 *)shadow_ring_context, true);
  #define COPY_REG(name) \
                        I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
  
        sr_oa_regs(workload, (u32 *)shadow_ring_context, false);
-       kunmap(page);
  
-       if (IS_RESTORE_INHIBIT(shadow_ring_context->ctx_ctrl.val))
-               return 0;
+       gvt_dbg_sched("ring %s workload lrca %x, ctx_id %x, ctx gpa %llx",
+                       workload->engine->name, workload->ctx_desc.lrca,
+                       workload->ctx_desc.context_id,
+                       workload->ring_context_gpa);
  
-       gvt_dbg_sched("ring %s workload lrca %x",
-                     workload->engine->name,
-                     workload->ctx_desc.lrca);
+       /* only need to ensure this context is not pinned/unpinned during the
+        * period from last submission to this this submission.
+        * Upon reaching this function, the currently submitted context is not
+        * supposed to get unpinned. If a misbehaving guest driver ever does
+        * this, it would corrupt itself.
+        */
+       if (s->last_ctx[ring_id].valid &&
+                       (s->last_ctx[ring_id].lrca ==
+                               workload->ctx_desc.lrca) &&
+                       (s->last_ctx[ring_id].ring_context_gpa ==
+                               workload->ring_context_gpa))
+               skip = true;
+       s->last_ctx[ring_id].lrca = workload->ctx_desc.lrca;
+       s->last_ctx[ring_id].ring_context_gpa = workload->ring_context_gpa;
  
+       if (IS_RESTORE_INHIBIT(shadow_ring_context->ctx_ctrl.val) || skip)
+               return 0;
+       s->last_ctx[ring_id].valid = false;
        context_page_num = workload->engine->context_size;
        context_page_num = context_page_num >> PAGE_SHIFT;
  
        if (IS_BROADWELL(gvt->gt->i915) && workload->engine->id == RCS0)
                context_page_num = 19;
  
-       i = 2;
-       while (i < context_page_num) {
+       /* find consecutive GPAs from gma until the first inconsecutive GPA.
+        * read from the continuous GPAs into dst virtual address
+        */
+       gpa_size = 0;
+       for (i = 2; i < context_page_num; i++) {
                context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
                                (u32)((workload->ctx_desc.lrca + i) <<
                                I915_GTT_PAGE_SHIFT));
                        return -EFAULT;
                }
  
-               page = i915_gem_object_get_page(ctx_obj, i);
-               dst = kmap(page);
-               intel_gvt_hypervisor_read_gpa(vgpu, context_gpa, dst,
-                               I915_GTT_PAGE_SIZE);
-               kunmap(page);
-               i++;
+               if (gpa_size == 0) {
+                       gpa_base = context_gpa;
+                       dst = context_base + (i << I915_GTT_PAGE_SHIFT);
+               } else if (context_gpa != gpa_base + gpa_size)
+                       goto read;
+               gpa_size += I915_GTT_PAGE_SIZE;
+               if (i == context_page_num - 1)
+                       goto read;
+               continue;
+ read:
+               intel_gvt_hypervisor_read_gpa(vgpu, gpa_base, dst, gpa_size);
+               gpa_base = context_gpa;
+               gpa_size = I915_GTT_PAGE_SIZE;
+               dst = context_base + (i << I915_GTT_PAGE_SHIFT);
        }
+       s->last_ctx[ring_id].valid = true;
        return 0;
  }
  
@@@ -379,11 -416,7 +416,11 @@@ static void set_context_ppgtt_from_shad
                for (i = 0; i < GVT_RING_CTX_NR_PDPS; i++) {
                        struct i915_page_directory * const pd =
                                i915_pd_entry(ppgtt->pd, i);
 -
 +                      /* skip now as current i915 ppgtt alloc won't allocate
 +                         top level pdp for non 4-level table, won't impact
 +                         shadow ppgtt. */
 +                      if (!pd)
 +                              break;
                        px_dma(pd) = mm->ppgtt_mm.shadow_pdps[i];
                }
        }
@@@ -599,10 -632,9 +636,9 @@@ static void release_shadow_batch_buffer
                        if (bb->va && !IS_ERR(bb->va))
                                i915_gem_object_unpin_map(bb->obj);
  
-                       if (bb->vma && !IS_ERR(bb->vma)) {
+                       if (bb->vma && !IS_ERR(bb->vma))
                                i915_vma_unpin(bb->vma);
-                               i915_vma_close(bb->vma);
-                       }
                        i915_gem_object_put(bb->obj);
                }
                list_del(&bb->list);
        }
  }
  
- static int prepare_workload(struct intel_vgpu_workload *workload)
+ static int
+ intel_vgpu_shadow_mm_pin(struct intel_vgpu_workload *workload)
  {
        struct intel_vgpu *vgpu = workload->vgpu;
-       struct intel_vgpu_submission *s = &vgpu->submission;
+       struct intel_vgpu_mm *m;
        int ret = 0;
  
        ret = intel_vgpu_pin_mm(workload->shadow_mm);
                return -EINVAL;
        }
  
+       if (!list_empty(&workload->lri_shadow_mm)) {
+               list_for_each_entry(m, &workload->lri_shadow_mm,
+                                   ppgtt_mm.link) {
+                       ret = intel_vgpu_pin_mm(m);
+                       if (ret) {
+                               list_for_each_entry_from_reverse(m,
+                                                                &workload->lri_shadow_mm,
+                                                                ppgtt_mm.link)
+                                       intel_vgpu_unpin_mm(m);
+                               gvt_vgpu_err("LRI shadow ppgtt fail to pin\n");
+                               break;
+                       }
+               }
+       }
+       if (ret)
+               intel_vgpu_unpin_mm(workload->shadow_mm);
+       return ret;
+ }
+ static void
+ intel_vgpu_shadow_mm_unpin(struct intel_vgpu_workload *workload)
+ {
+       struct intel_vgpu_mm *m;
+       if (!list_empty(&workload->lri_shadow_mm)) {
+               list_for_each_entry(m, &workload->lri_shadow_mm,
+                                   ppgtt_mm.link)
+                       intel_vgpu_unpin_mm(m);
+       }
+       intel_vgpu_unpin_mm(workload->shadow_mm);
+ }
+ static int prepare_workload(struct intel_vgpu_workload *workload)
+ {
+       struct intel_vgpu *vgpu = workload->vgpu;
+       struct intel_vgpu_submission *s = &vgpu->submission;
+       int ret = 0;
+       ret = intel_vgpu_shadow_mm_pin(workload);
+       if (ret) {
+               gvt_vgpu_err("fail to pin shadow mm\n");
+               return ret;
+       }
        update_shadow_pdps(workload);
  
        set_context_ppgtt_from_shadow(workload, s->shadow[workload->engine->id]);
@@@ -674,7 -753,7 +757,7 @@@ err_shadow_wa_ctx
  err_shadow_batch:
        release_shadow_batch_buffer(workload);
  err_unpin_mm:
-       intel_vgpu_unpin_mm(workload->shadow_mm);
+       intel_vgpu_shadow_mm_unpin(workload);
        return ret;
  }
  
@@@ -784,15 -863,48 +867,48 @@@ out
        return workload;
  }
  
+ static void update_guest_pdps(struct intel_vgpu *vgpu,
+                             u64 ring_context_gpa, u32 pdp[8])
+ {
+       u64 gpa;
+       int i;
+       gpa = ring_context_gpa + RING_CTX_OFF(pdps[0].val);
+       for (i = 0; i < 8; i++)
+               intel_gvt_hypervisor_write_gpa(vgpu,
+                               gpa + i * 8, &pdp[7 - i], 4);
+ }
+ static __maybe_unused bool
+ check_shadow_context_ppgtt(struct execlist_ring_context *c, struct intel_vgpu_mm *m)
+ {
+       if (m->ppgtt_mm.root_entry_type == GTT_TYPE_PPGTT_ROOT_L4_ENTRY) {
+               u64 shadow_pdp = c->pdps[7].val | (u64) c->pdps[6].val << 32;
+               if (shadow_pdp != m->ppgtt_mm.shadow_pdps[0]) {
+                       gvt_dbg_mm("4-level context ppgtt not match LRI command\n");
+                       return false;
+               }
+               return true;
+       } else {
+               /* see comment in LRI handler in cmd_parser.c */
+               gvt_dbg_mm("invalid shadow mm type\n");
+               return false;
+       }
+ }
  static void update_guest_context(struct intel_vgpu_workload *workload)
  {
        struct i915_request *rq = workload->req;
        struct intel_vgpu *vgpu = workload->vgpu;
-       struct drm_i915_gem_object *ctx_obj = rq->context->state->obj;
        struct execlist_ring_context *shadow_ring_context;
-       struct page *page;
+       struct intel_context *ctx = workload->req->context;
+       void *context_base;
        void *src;
        unsigned long context_gpa, context_page_num;
+       unsigned long gpa_base; /* first gpa of consecutive GPAs */
+       unsigned long gpa_size; /* size of consecutive GPAs*/
        int i;
        u32 ring_base;
        u32 head, tail;
        gvt_dbg_sched("ring id %d workload lrca %x\n", rq->engine->id,
                      workload->ctx_desc.lrca);
  
+       GEM_BUG_ON(!intel_context_is_pinned(ctx));
        head = workload->rb_head;
        tail = workload->rb_tail;
        wrap_count = workload->guest_rb_head >> RB_HEAD_WRAP_CNT_OFF;
        if (IS_BROADWELL(rq->i915) && rq->engine->id == RCS0)
                context_page_num = 19;
  
-       i = 2;
+       context_base = (void *) ctx->lrc_reg_state -
+                       (LRC_STATE_PN << I915_GTT_PAGE_SHIFT);
  
-       while (i < context_page_num) {
+       /* find consecutive GPAs from gma until the first inconsecutive GPA.
+        * write to the consecutive GPAs from src virtual address
+        */
+       gpa_size = 0;
+       for (i = 2; i < context_page_num; i++) {
                context_gpa = intel_vgpu_gma_to_gpa(vgpu->gtt.ggtt_mm,
                                (u32)((workload->ctx_desc.lrca + i) <<
                                        I915_GTT_PAGE_SHIFT));
                        return;
                }
  
-               page = i915_gem_object_get_page(ctx_obj, i);
-               src = kmap(page);
-               intel_gvt_hypervisor_write_gpa(vgpu, context_gpa, src,
-                               I915_GTT_PAGE_SIZE);
-               kunmap(page);
-               i++;
+               if (gpa_size == 0) {
+                       gpa_base = context_gpa;
+                       src = context_base + (i << I915_GTT_PAGE_SHIFT);
+               } else if (context_gpa != gpa_base + gpa_size)
+                       goto write;
+               gpa_size += I915_GTT_PAGE_SIZE;
+               if (i == context_page_num - 1)
+                       goto write;
+               continue;
+ write:
+               intel_gvt_hypervisor_write_gpa(vgpu, gpa_base, src, gpa_size);
+               gpa_base = context_gpa;
+               gpa_size = I915_GTT_PAGE_SIZE;
+               src = context_base + (i << I915_GTT_PAGE_SHIFT);
        }
  
        intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa +
                RING_CTX_OFF(ring_header.val), &workload->rb_tail, 4);
  
-       page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
-       shadow_ring_context = kmap(page);
+       shadow_ring_context = (void *) ctx->lrc_reg_state;
+       if (!list_empty(&workload->lri_shadow_mm)) {
+               struct intel_vgpu_mm *m = list_last_entry(&workload->lri_shadow_mm,
+                                                         struct intel_vgpu_mm,
+                                                         ppgtt_mm.link);
+               GEM_BUG_ON(!check_shadow_context_ppgtt(shadow_ring_context, m));
+               update_guest_pdps(vgpu, workload->ring_context_gpa,
+                                 (void *)m->ppgtt_mm.guest_pdps);
+       }
  
  #define COPY_REG(name) \
        intel_gvt_hypervisor_write_gpa(vgpu, workload->ring_context_gpa + \
                        (void *)shadow_ring_context +
                        sizeof(*shadow_ring_context),
                        I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
-       kunmap(page);
  }
  
  void intel_vgpu_clean_workloads(struct intel_vgpu *vgpu,
@@@ -959,6 -1096,9 +1100,9 @@@ static void complete_current_workload(s
  
        workload->complete(workload);
  
+       intel_vgpu_shadow_mm_unpin(workload);
+       intel_vgpu_destroy_workload(workload);
        atomic_dec(&s->running_workload_num);
        wake_up(&scheduler->workload_complete_wq);
  
@@@ -1264,6 -1404,8 +1408,8 @@@ int intel_vgpu_setup_submission(struct 
        atomic_set(&s->running_workload_num, 0);
        bitmap_zero(s->tlb_handle_pending, I915_NUM_ENGINES);
  
+       memset(s->last_ctx, 0, sizeof(s->last_ctx));
        i915_vm_put(&ppgtt->vm);
        return 0;
  
@@@ -1350,6 -1492,16 +1496,16 @@@ void intel_vgpu_destroy_workload(struc
        release_shadow_batch_buffer(workload);
        release_shadow_wa_ctx(&workload->wa_ctx);
  
+       if (!list_empty(&workload->lri_shadow_mm)) {
+               struct intel_vgpu_mm *m, *mm;
+               list_for_each_entry_safe(m, mm, &workload->lri_shadow_mm,
+                                        ppgtt_mm.link) {
+                       list_del(&m->ppgtt_mm.link);
+                       intel_vgpu_mm_put(m);
+               }
+       }
+       GEM_BUG_ON(!list_empty(&workload->lri_shadow_mm));
        if (workload->shadow_mm)
                intel_vgpu_mm_put(workload->shadow_mm);
  
@@@ -1368,6 -1520,7 +1524,7 @@@ alloc_workload(struct intel_vgpu *vgpu
  
        INIT_LIST_HEAD(&workload->list);
        INIT_LIST_HEAD(&workload->shadow_bb);
+       INIT_LIST_HEAD(&workload->lri_shadow_mm);
  
        init_waitqueue_head(&workload->shadow_ctx_status_wq);
        atomic_set(&workload->shadow_ctx_active, 0);
index 60da28d412d6d0dbf24743f44eb2099611a983ab,f35712d04ba499667e5a4f0ae7a3e4b00cd78683..75c60c2afb7ea280d4fcbea3dcdaed96d73bb2c1
  
  #include "i915_drv.h"
  #include "i915_perf.h"
- #include "oa/i915_oa_hsw.h"
- #include "oa/i915_oa_bdw.h"
- #include "oa/i915_oa_chv.h"
- #include "oa/i915_oa_sklgt2.h"
- #include "oa/i915_oa_sklgt3.h"
- #include "oa/i915_oa_sklgt4.h"
- #include "oa/i915_oa_bxt.h"
- #include "oa/i915_oa_kblgt2.h"
- #include "oa/i915_oa_kblgt3.h"
- #include "oa/i915_oa_glk.h"
- #include "oa/i915_oa_cflgt2.h"
- #include "oa/i915_oa_cflgt3.h"
- #include "oa/i915_oa_cnl.h"
- #include "oa/i915_oa_icl.h"
- #include "oa/i915_oa_tgl.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
   *
   * Although this can be observed explicitly while copying reports to userspace
   * by checking for a zeroed report-id field in tail reports, we want to account
-  * for this earlier, as part of the oa_buffer_check to avoid lots of redundant
-  * read() attempts.
-  *
-  * In effect we define a tail pointer for reading that lags the real tail
-  * pointer by at least %OA_TAIL_MARGIN_NSEC nanoseconds, which gives enough
-  * time for the corresponding reports to become visible to the CPU.
-  *
-  * To manage this we actually track two tail pointers:
-  *  1) An 'aging' tail with an associated timestamp that is tracked until we
-  *     can trust the corresponding data is visible to the CPU; at which point
-  *     it is considered 'aged'.
-  *  2) An 'aged' tail that can be used for read()ing.
-  *
-  * The two separate pointers let us decouple read()s from tail pointer aging.
-  *
-  * The tail pointers are checked and updated at a limited rate within a hrtimer
-  * callback (the same callback that is used for delivering EPOLLIN events)
-  *
-  * Initially the tails are marked invalid with %INVALID_TAIL_PTR which
-  * indicates that an updated tail pointer is needed.
+  * for this earlier, as part of the oa_buffer_check_unlocked to avoid lots of
+  * redundant read() attempts.
+  *
+  * We workaround this issue in oa_buffer_check_unlocked() by reading the reports
+  * in the OA buffer, starting from the tail reported by the HW until we find a
+  * report with its first 2 dwords not 0 meaning its previous report is
+  * completely in memory and ready to be read. Those dwords are also set to 0
+  * once read and the whole buffer is cleared upon OA buffer initialization. The
+  * first dword is the reason for this report while the second is the timestamp,
+  * making the chances of having those 2 fields at 0 fairly unlikely. A more
+  * detailed explanation is available in oa_buffer_check_unlocked().
   *
   * Most of the implementation details for this workaround are in
   * oa_buffer_check_unlocked() and _append_oa_reports()
  #define OA_TAIL_MARGIN_NSEC   100000ULL
  #define INVALID_TAIL_PTR      0xffffffff
  
- /* frequency for checking whether the OA unit has written new reports to the
-  * circular OA buffer...
+ /* The default frequency for checking whether the OA unit has written new
+  * reports to the circular OA buffer...
   */
- #define POLL_FREQUENCY 200
- #define POLL_PERIOD (NSEC_PER_SEC / POLL_FREQUENCY)
+ #define DEFAULT_POLL_FREQUENCY_HZ 200
+ #define DEFAULT_POLL_PERIOD_NS (NSEC_PER_SEC / DEFAULT_POLL_FREQUENCY_HZ)
  
  /* for sysctl proc_dointvec_minmax of dev.i915.perf_stream_paranoid */
  static u32 i915_perf_stream_paranoid = true;
@@@ -359,6 -335,12 +335,12 @@@ static const struct i915_oa_format gen1
   * @oa_periodic: Whether to enable periodic OA unit sampling
   * @oa_period_exponent: The OA unit sampling period is derived from this
   * @engine: The engine (typically rcs0) being monitored by the OA unit
+  * @has_sseu: Whether @sseu was specified by userspace
+  * @sseu: internal SSEU configuration computed either from the userspace
+  *        specified configuration in the opening parameters or a default value
+  *        (see get_default_sseu_config())
+  * @poll_oa_period: The period in nanoseconds at which the CPU will check for OA
+  * data availability
   *
   * As read_properties_unlocked() enumerates and validates the properties given
   * to open a stream of metrics the configuration is built up in the structure
@@@ -378,6 -360,11 +360,11 @@@ struct perf_open_properties 
        int oa_period_exponent;
  
        struct intel_engine_cs *engine;
+       bool has_sseu;
+       struct intel_sseu sseu;
+       u64 poll_oa_period;
  };
  
  struct i915_oa_config_bo {
@@@ -409,10 -396,7 +396,7 @@@ i915_perf_get_oa_config(struct i915_per
        struct i915_oa_config *oa_config;
  
        rcu_read_lock();
-       if (metrics_set == 1)
-               oa_config = &perf->test_config;
-       else
-               oa_config = idr_find(&perf->metrics_idr, metrics_set);
+       oa_config = idr_find(&perf->metrics_idr, metrics_set);
        if (oa_config)
                oa_config = i915_oa_config_get(oa_config);
        rcu_read_unlock();
@@@ -465,8 -449,8 +449,8 @@@ static u32 gen7_oa_hw_tail_read(struct 
   * (See description of OA_TAIL_MARGIN_NSEC above for further details.)
   *
   * Besides returning true when there is data available to read() this function
-  * also has the side effect of updating the oa_buffer.tails[], .aging_timestamp
-  * and .aged_tail_idx state used for reading.
+  * also updates the tail, aging_tail and aging_timestamp in the oa_buffer
+  * object.
   *
   * Note: It's safe to read OA config state here unlocked, assuming that this is
   * only called while the stream is enabled, while the global OA configuration
   */
  static bool oa_buffer_check_unlocked(struct i915_perf_stream *stream)
  {
+       u32 gtt_offset = i915_ggtt_offset(stream->oa_buffer.vma);
        int report_size = stream->oa_buffer.format_size;
        unsigned long flags;
-       unsigned int aged_idx;
-       u32 head, hw_tail, aged_tail, aging_tail;
+       bool pollin;
+       u32 hw_tail;
        u64 now;
  
        /* We have to consider the (unlikely) possibility that read() errors
-        * could result in an OA buffer reset which might reset the head,
-        * tails[] and aged_tail state.
+        * could result in an OA buffer reset which might reset the head and
+        * tail state.
         */
        spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags);
  
-       /* NB: The head we observe here might effectively be a little out of
-        * date (between head and tails[aged_idx].offset if there is currently
-        * a read() in progress.
-        */
-       head = stream->oa_buffer.head;
-       aged_idx = stream->oa_buffer.aged_tail_idx;
-       aged_tail = stream->oa_buffer.tails[aged_idx].offset;
-       aging_tail = stream->oa_buffer.tails[!aged_idx].offset;
        hw_tail = stream->perf->ops.oa_hw_tail_read(stream);
  
        /* The tail pointer increases in 64 byte increments,
  
        now = ktime_get_mono_fast_ns();
  
-       /* Update the aged tail
-        *
-        * Flip the tail pointer available for read()s once the aging tail is
-        * old enough to trust that the corresponding data will be visible to
-        * the CPU...
-        *
-        * Do this before updating the aging pointer in case we may be able to
-        * immediately start aging a new pointer too (if new data has become
-        * available) without needing to wait for a later hrtimer callback.
-        */
-       if (aging_tail != INVALID_TAIL_PTR &&
-           ((now - stream->oa_buffer.aging_timestamp) >
-            OA_TAIL_MARGIN_NSEC)) {
-               aged_idx ^= 1;
-               stream->oa_buffer.aged_tail_idx = aged_idx;
+       if (hw_tail == stream->oa_buffer.aging_tail &&
+           (now - stream->oa_buffer.aging_timestamp) > OA_TAIL_MARGIN_NSEC) {
+               /* If the HW tail hasn't move since the last check and the HW
+                * tail has been aging for long enough, declare it the new
+                * tail.
+                */
+               stream->oa_buffer.tail = stream->oa_buffer.aging_tail;
+       } else {
+               u32 head, tail, aged_tail;
  
-               aged_tail = aging_tail;
+               /* NB: The head we observe here might effectively be a little
+                * out of date. If a read() is in progress, the head could be
+                * anywhere between this head and stream->oa_buffer.tail.
+                */
+               head = stream->oa_buffer.head - gtt_offset;
+               aged_tail = stream->oa_buffer.tail - gtt_offset;
+               hw_tail -= gtt_offset;
+               tail = hw_tail;
+               /* Walk the stream backward until we find a report with dword 0
+                * & 1 not at 0. Since the circular buffer pointers progress by
+                * increments of 64 bytes and that reports can be up to 256
+                * bytes long, we can't tell whether a report has fully landed
+                * in memory before the first 2 dwords of the following report
+                * have effectively landed.
+                *
+                * This is assuming that the writes of the OA unit land in
+                * memory in the order they were written to.
+                * If not : (╯°□°)╯︵ ┻━┻
+                */
+               while (OA_TAKEN(tail, aged_tail) >= report_size) {
+                       u32 *report32 = (void *)(stream->oa_buffer.vaddr + tail);
  
-               /* Mark that we need a new pointer to start aging... */
-               stream->oa_buffer.tails[!aged_idx].offset = INVALID_TAIL_PTR;
-               aging_tail = INVALID_TAIL_PTR;
-       }
+                       if (report32[0] != 0 || report32[1] != 0)
+                               break;
  
-       /* Update the aging tail
-        *
-        * We throttle aging tail updates until we have a new tail that
-        * represents >= one report more data than is already available for
-        * reading. This ensures there will be enough data for a successful
-        * read once this new pointer has aged and ensures we will give the new
-        * pointer time to age.
-        */
-       if (aging_tail == INVALID_TAIL_PTR &&
-           (aged_tail == INVALID_TAIL_PTR ||
-            OA_TAKEN(hw_tail, aged_tail) >= report_size)) {
-               struct i915_vma *vma = stream->oa_buffer.vma;
-               u32 gtt_offset = i915_ggtt_offset(vma);
-               /* Be paranoid and do a bounds check on the pointer read back
-                * from hardware, just in case some spurious hardware condition
-                * could put the tail out of bounds...
-                */
-               if (hw_tail >= gtt_offset &&
-                   hw_tail < (gtt_offset + OA_BUFFER_SIZE)) {
-                       stream->oa_buffer.tails[!aged_idx].offset =
-                               aging_tail = hw_tail;
-                       stream->oa_buffer.aging_timestamp = now;
-               } else {
-                       drm_err(&stream->perf->i915->drm,
-                               "Ignoring spurious out of range OA buffer tail pointer = %x\n",
-                               hw_tail);
+                       tail = (tail - report_size) & (OA_BUFFER_SIZE - 1);
                }
+               if (OA_TAKEN(hw_tail, tail) > report_size &&
+                   __ratelimit(&stream->perf->tail_pointer_race))
+                       DRM_NOTE("unlanded report(s) head=0x%x "
+                                "tail=0x%x hw_tail=0x%x\n",
+                                head, tail, hw_tail);
+               stream->oa_buffer.tail = gtt_offset + tail;
+               stream->oa_buffer.aging_tail = gtt_offset + hw_tail;
+               stream->oa_buffer.aging_timestamp = now;
        }
  
+       pollin = OA_TAKEN(stream->oa_buffer.tail - gtt_offset,
+                         stream->oa_buffer.head - gtt_offset) >= report_size;
        spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
  
-       return aged_tail == INVALID_TAIL_PTR ?
-               false : OA_TAKEN(aged_tail, head) >= report_size;
+       return pollin;
  }
  
  /**
@@@ -682,7 -656,6 +656,6 @@@ static int gen8_append_oa_reports(struc
        u32 mask = (OA_BUFFER_SIZE - 1);
        size_t start_offset = *offset;
        unsigned long flags;
-       unsigned int aged_tail_idx;
        u32 head, tail;
        u32 taken;
        int ret = 0;
        spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags);
  
        head = stream->oa_buffer.head;
-       aged_tail_idx = stream->oa_buffer.aged_tail_idx;
-       tail = stream->oa_buffer.tails[aged_tail_idx].offset;
+       tail = stream->oa_buffer.tail;
  
        spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
  
-       /*
-        * An invalid tail pointer here means we're still waiting for the poll
-        * hrtimer callback to give us a pointer
-        */
-       if (tail == INVALID_TAIL_PTR)
-               return -EAGAIN;
        /*
         * NB: oa_buffer.head/tail include the gtt_offset which we don't want
         * while indexing relative to oa_buf_base.
                }
  
                /*
-                * The above reason field sanity check is based on
-                * the assumption that the OA buffer is initially
-                * zeroed and we reset the field after copying so the
-                * check is still meaningful once old reports start
-                * being overwritten.
+                * Clear out the first 2 dword as a mean to detect unlanded
+                * reports.
                 */
                report32[0] = 0;
+               report32[1] = 0;
        }
  
        if (start_offset != *offset) {
@@@ -985,7 -948,6 +948,6 @@@ static int gen7_append_oa_reports(struc
        u32 mask = (OA_BUFFER_SIZE - 1);
        size_t start_offset = *offset;
        unsigned long flags;
-       unsigned int aged_tail_idx;
        u32 head, tail;
        u32 taken;
        int ret = 0;
        spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags);
  
        head = stream->oa_buffer.head;
-       aged_tail_idx = stream->oa_buffer.aged_tail_idx;
-       tail = stream->oa_buffer.tails[aged_tail_idx].offset;
+       tail = stream->oa_buffer.tail;
  
        spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
  
-       /* An invalid tail pointer here means we're still waiting for the poll
-        * hrtimer callback to give us a pointer
-        */
-       if (tail == INVALID_TAIL_PTR)
-               return -EAGAIN;
        /* NB: oa_buffer.head/tail include the gtt_offset which we don't want
         * while indexing relative to oa_buf_base.
         */
                if (ret)
                        break;
  
-               /* The above report-id field sanity check is based on
-                * the assumption that the OA buffer is initially
-                * zeroed and we reset the field after copying so the
-                * check is still meaningful once old reports start
-                * being overwritten.
+               /* Clear out the first 2 dwords as a mean to detect unlanded
+                * reports.
                 */
                report32[0] = 0;
+               report32[1] = 0;
        }
  
        if (start_offset != *offset) {
@@@ -1447,8 -1400,8 +1400,8 @@@ static void gen7_init_oa_buffer(struct 
                           gtt_offset | OABUFFER_SIZE_16M);
  
        /* Mark that we need updated tail pointers to read from... */
-       stream->oa_buffer.tails[0].offset = INVALID_TAIL_PTR;
-       stream->oa_buffer.tails[1].offset = INVALID_TAIL_PTR;
+       stream->oa_buffer.aging_tail = INVALID_TAIL_PTR;
+       stream->oa_buffer.tail = gtt_offset;
  
        spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags);
  
         * memory...
         */
        memset(stream->oa_buffer.vaddr, 0, OA_BUFFER_SIZE);
-       stream->pollin = false;
  }
  
  static void gen8_init_oa_buffer(struct i915_perf_stream *stream)
        intel_uncore_write(uncore, GEN8_OATAILPTR, gtt_offset & GEN8_OATAILPTR_MASK);
  
        /* Mark that we need updated tail pointers to read from... */
-       stream->oa_buffer.tails[0].offset = INVALID_TAIL_PTR;
-       stream->oa_buffer.tails[1].offset = INVALID_TAIL_PTR;
+       stream->oa_buffer.aging_tail = INVALID_TAIL_PTR;
+       stream->oa_buffer.tail = gtt_offset;
  
        /*
         * Reset state used to recognise context switches, affecting which
         * memory...
         */
        memset(stream->oa_buffer.vaddr, 0, OA_BUFFER_SIZE);
-       stream->pollin = false;
  }
  
  static void gen12_init_oa_buffer(struct i915_perf_stream *stream)
                           gtt_offset & GEN12_OAG_OATAILPTR_MASK);
  
        /* Mark that we need updated tail pointers to read from... */
-       stream->oa_buffer.tails[0].offset = INVALID_TAIL_PTR;
-       stream->oa_buffer.tails[1].offset = INVALID_TAIL_PTR;
+       stream->oa_buffer.aging_tail = INVALID_TAIL_PTR;
+       stream->oa_buffer.tail = gtt_offset;
  
        /*
         * Reset state used to recognise context switches, affecting which
         */
        memset(stream->oa_buffer.vaddr, 0,
               stream->oa_buffer.vma->size);
-       stream->pollin = false;
  }
  
  static int alloc_oa_buffer(struct i915_perf_stream *stream)
@@@ -1665,10 -1612,7 +1612,7 @@@ static int alloc_noa_wait(struct i915_p
        struct drm_i915_gem_object *bo;
        struct i915_vma *vma;
        const u64 delay_ticks = 0xffffffffffffffff -
-               DIV64_U64_ROUND_UP(
-                       atomic64_read(&stream->perf->noa_programming_delay) *
-                       RUNTIME_INFO(i915)->cs_timestamp_frequency_khz,
-                       1000000ull);
+               i915_cs_timestamp_ns_to_ticks(i915, atomic64_read(&stream->perf->noa_programming_delay));
        const u32 base = stream->engine->mmio_base;
  #define CS_GPR(x) GEN8_RING_CS_GPR(base, x)
        u32 *batch, *ts0, *cs, *jump;
        return i915_vma_get(oa_bo->vma);
  }
  
- static struct i915_request *
+ static int
  emit_oa_config(struct i915_perf_stream *stream,
               struct i915_oa_config *oa_config,
-              struct intel_context *ce)
+              struct intel_context *ce,
+              struct i915_active *active)
  {
        struct i915_request *rq;
        struct i915_vma *vma;
  
        vma = get_oa_vma(stream, oa_config);
        if (IS_ERR(vma))
-               return ERR_CAST(vma);
+               return PTR_ERR(vma);
  
        err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH);
        if (err)
                goto err_vma_unpin;
        }
  
+       if (!IS_ERR_OR_NULL(active)) {
+               /* After all individual context modifications */
+               err = i915_request_await_active(rq, active,
+                                               I915_ACTIVE_AWAIT_ACTIVE);
+               if (err)
+                       goto err_add_request;
+               err = i915_active_add_request(active, rq);
+               if (err)
+                       goto err_add_request;
+       }
        i915_vma_lock(vma);
        err = i915_request_await_object(rq, vma->obj, 0);
        if (!err)
        if (err)
                goto err_add_request;
  
-       i915_request_get(rq);
  err_add_request:
        i915_request_add(rq);
  err_vma_unpin:
        i915_vma_unpin(vma);
  err_vma_put:
        i915_vma_put(vma);
-       return err ? ERR_PTR(err) : rq;
+       return err;
  }
  
  static struct intel_context *oa_context(struct i915_perf_stream *stream)
        return stream->pinned_ctx ?: stream->engine->kernel_context;
  }
  
- static struct i915_request *
- hsw_enable_metric_set(struct i915_perf_stream *stream)
+ static int
+ hsw_enable_metric_set(struct i915_perf_stream *stream,
+                     struct i915_active *active)
  {
        struct intel_uncore *uncore = stream->uncore;
  
        intel_uncore_rmw(uncore, GEN6_UCGCTL1,
                         0, GEN6_CSUNIT_CLOCK_GATE_DISABLE);
  
-       return emit_oa_config(stream, stream->oa_config, oa_context(stream));
+       return emit_oa_config(stream,
+                             stream->oa_config, oa_context(stream),
+                             active);
  }
  
  static void hsw_disable_metric_set(struct i915_perf_stream *stream)
@@@ -2114,9 -2073,6 +2073,6 @@@ gen8_update_reg_state_unlocked(const st
        for (i = 0; i < ARRAY_SIZE(flex_regs); i++)
                reg_state[ctx_flexeu0 + i * 2 + 1] =
                        oa_config_flex_reg(stream->oa_config, flex_regs[i]);
-       reg_state[CTX_R_PWR_CLK_STATE] =
-               intel_sseu_make_rpcs(ce->engine->i915, &ce->sseu);
  }
  
  struct flex {
@@@ -2137,7 -2093,7 +2093,7 @@@ gen8_store_flex(struct i915_request *rq
        if (IS_ERR(cs))
                return PTR_ERR(cs);
  
-       offset = i915_ggtt_offset(ce->state) + LRC_STATE_PN * PAGE_SIZE;
+       offset = i915_ggtt_offset(ce->state) + LRC_STATE_OFFSET;
        do {
                *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
                *cs++ = offset + flex->offset * sizeof(u32);
@@@ -2194,8 -2150,10 +2150,10 @@@ static int gen8_modify_context(struct i
        return err;
  }
  
- static int gen8_modify_self(struct intel_context *ce,
-                           const struct flex *flex, unsigned int count)
+ static int
+ gen8_modify_self(struct intel_context *ce,
+                const struct flex *flex, unsigned int count,
+                struct i915_active *active)
  {
        struct i915_request *rq;
        int err;
        if (IS_ERR(rq))
                return PTR_ERR(rq);
  
+       if (!IS_ERR_OR_NULL(active)) {
+               err = i915_active_add_request(active, rq);
+               if (err)
+                       goto err_add_request;
+       }
        err = gen8_load_flex(rq, ce, flex, count);
+       if (err)
+               goto err_add_request;
  
+ err_add_request:
        i915_request_add(rq);
        return err;
  }
@@@ -2241,7 -2208,8 +2208,8 @@@ static int gen8_configure_context(struc
        return err;
  }
  
- static int gen12_configure_oar_context(struct i915_perf_stream *stream, bool enable)
+ static int gen12_configure_oar_context(struct i915_perf_stream *stream,
+                                      struct i915_active *active)
  {
        int err;
        struct intel_context *ce = stream->pinned_ctx;
                {
                        GEN8_OACTXCONTROL,
                        stream->perf->ctx_oactxctrl_offset + 1,
-                       enable ? GEN8_OA_COUNTER_RESUME : 0,
+                       active ? GEN8_OA_COUNTER_RESUME : 0,
                },
        };
        /* Offsets in regs_lri are not used since this configuration is only
                        GEN12_OAR_OACONTROL,
                        GEN12_OAR_OACONTROL_OFFSET + 1,
                        (format << GEN12_OAR_OACONTROL_COUNTER_FORMAT_SHIFT) |
-                       (enable ? GEN12_OAR_OACONTROL_COUNTER_ENABLE : 0)
+                       (active ? GEN12_OAR_OACONTROL_COUNTER_ENABLE : 0)
                },
                {
                        RING_CONTEXT_CONTROL(ce->engine->mmio_base),
                        CTX_CONTEXT_CONTROL,
                        _MASKED_FIELD(GEN12_CTX_CTRL_OAR_CONTEXT_ENABLE,
-                                     enable ?
+                                     active ?
                                      GEN12_CTX_CTRL_OAR_CONTEXT_ENABLE :
                                      0)
                },
                return err;
  
        /* Apply regs_lri using LRI with pinned context */
-       return gen8_modify_self(ce, regs_lri, ARRAY_SIZE(regs_lri));
+       return gen8_modify_self(ce, regs_lri, ARRAY_SIZE(regs_lri), active);
  }
  
  /*
   * Note: it's only the RCS/Render context that has any OA state.
   * Note: the first flex register passed must always be R_PWR_CLK_STATE
   */
- static int oa_configure_all_contexts(struct i915_perf_stream *stream,
-                                    struct flex *regs,
-                                    size_t num_regs)
+ static int
+ oa_configure_all_contexts(struct i915_perf_stream *stream,
+                         struct flex *regs,
+                         size_t num_regs,
+                         struct i915_active *active)
  {
        struct drm_i915_private *i915 = stream->perf->i915;
        struct intel_engine_cs *engine;
  
                regs[0].value = intel_sseu_make_rpcs(i915, &ce->sseu);
  
-               err = gen8_modify_self(ce, regs, num_regs);
+               err = gen8_modify_self(ce, regs, num_regs, active);
                if (err)
                        return err;
        }
        return 0;
  }
  
- static int gen12_configure_all_contexts(struct i915_perf_stream *stream,
-                                       const struct i915_oa_config *oa_config)
+ static int
+ gen12_configure_all_contexts(struct i915_perf_stream *stream,
+                            const struct i915_oa_config *oa_config,
+                            struct i915_active *active)
  {
        struct flex regs[] = {
                {
                },
        };
  
-       return oa_configure_all_contexts(stream, regs, ARRAY_SIZE(regs));
+       return oa_configure_all_contexts(stream,
+                                        regs, ARRAY_SIZE(regs),
+                                        active);
  }
  
- static int lrc_configure_all_contexts(struct i915_perf_stream *stream,
-                                     const struct i915_oa_config *oa_config)
+ static int
+ lrc_configure_all_contexts(struct i915_perf_stream *stream,
+                          const struct i915_oa_config *oa_config,
+                          struct i915_active *active)
  {
        /* The MMIO offsets for Flex EU registers aren't contiguous */
        const u32 ctx_flexeu0 = stream->perf->ctx_flexeu0_offset;
        for (i = 2; i < ARRAY_SIZE(regs); i++)
                regs[i].value = oa_config_flex_reg(oa_config, regs[i].reg);
  
-       return oa_configure_all_contexts(stream, regs, ARRAY_SIZE(regs));
+       return oa_configure_all_contexts(stream,
+                                        regs, ARRAY_SIZE(regs),
+                                        active);
  }
  
- static struct i915_request *
- gen8_enable_metric_set(struct i915_perf_stream *stream)
+ static int
+ gen8_enable_metric_set(struct i915_perf_stream *stream,
+                      struct i915_active *active)
  {
        struct intel_uncore *uncore = stream->uncore;
        struct i915_oa_config *oa_config = stream->oa_config;
         * to make sure all slices/subslices are ON before writing to NOA
         * registers.
         */
-       ret = lrc_configure_all_contexts(stream, oa_config);
+       ret = lrc_configure_all_contexts(stream, oa_config, active);
        if (ret)
-               return ERR_PTR(ret);
+               return ret;
  
-       return emit_oa_config(stream, oa_config, oa_context(stream));
+       return emit_oa_config(stream,
+                             stream->oa_config, oa_context(stream),
+                             active);
  }
  
  static u32 oag_report_ctx_switches(const struct i915_perf_stream *stream)
                             0 : GEN12_OAG_OA_DEBUG_DISABLE_CTX_SWITCH_REPORTS);
  }
  
- static struct i915_request *
- gen12_enable_metric_set(struct i915_perf_stream *stream)
+ static int
+ gen12_enable_metric_set(struct i915_perf_stream *stream,
+                       struct i915_active *active)
  {
        struct intel_uncore *uncore = stream->uncore;
        struct i915_oa_config *oa_config = stream->oa_config;
         * to make sure all slices/subslices are ON before writing to NOA
         * registers.
         */
-       ret = gen12_configure_all_contexts(stream, oa_config);
+       ret = gen12_configure_all_contexts(stream, oa_config, active);
        if (ret)
-               return ERR_PTR(ret);
+               return ret;
  
        /*
         * For Gen12, performance counters are context
         * requested this.
         */
        if (stream->ctx) {
-               ret = gen12_configure_oar_context(stream, true);
+               ret = gen12_configure_oar_context(stream, active);
                if (ret)
-                       return ERR_PTR(ret);
+                       return ret;
        }
  
-       return emit_oa_config(stream, oa_config, oa_context(stream));
+       return emit_oa_config(stream,
+                             stream->oa_config, oa_context(stream),
+                             active);
  }
  
  static void gen8_disable_metric_set(struct i915_perf_stream *stream)
        struct intel_uncore *uncore = stream->uncore;
  
        /* Reset all contexts' slices/subslices configurations. */
-       lrc_configure_all_contexts(stream, NULL);
+       lrc_configure_all_contexts(stream, NULL, NULL);
  
        intel_uncore_rmw(uncore, GDT_CHICKEN_BITS, GT_NOA_ENABLE, 0);
  }
@@@ -2548,7 -2532,7 +2532,7 @@@ static void gen10_disable_metric_set(st
        struct intel_uncore *uncore = stream->uncore;
  
        /* Reset all contexts' slices/subslices configurations. */
-       lrc_configure_all_contexts(stream, NULL);
+       lrc_configure_all_contexts(stream, NULL, NULL);
  
        /* Make sure we disable noa to save power. */
        intel_uncore_rmw(uncore, RPM_CONFIG1, GEN10_GT_NOA_ENABLE, 0);
@@@ -2559,11 -2543,11 +2543,11 @@@ static void gen12_disable_metric_set(st
        struct intel_uncore *uncore = stream->uncore;
  
        /* Reset all contexts' slices/subslices configurations. */
-       gen12_configure_all_contexts(stream, NULL);
+       gen12_configure_all_contexts(stream, NULL, NULL);
  
        /* disable the context save/restore or OAR counters */
        if (stream->ctx)
-               gen12_configure_oar_context(stream, false);
+               gen12_configure_oar_context(stream, NULL);
  
        /* Make sure we disable noa to save power. */
        intel_uncore_rmw(uncore, RPM_CONFIG1, GEN10_GT_NOA_ENABLE, 0);
@@@ -2655,11 -2639,13 +2639,13 @@@ static void gen12_oa_enable(struct i915
   */
  static void i915_oa_stream_enable(struct i915_perf_stream *stream)
  {
+       stream->pollin = false;
        stream->perf->ops.oa_enable(stream);
  
        if (stream->periodic)
                hrtimer_start(&stream->poll_check_timer,
-                             ns_to_ktime(POLL_PERIOD),
+                             ns_to_ktime(stream->poll_oa_period),
                              HRTIMER_MODE_REL_PINNED);
  }
  
@@@ -2735,16 -2721,52 +2721,52 @@@ static const struct i915_perf_stream_op
  
  static int i915_perf_stream_enable_sync(struct i915_perf_stream *stream)
  {
-       struct i915_request *rq;
+       struct i915_active *active;
+       int err;
  
-       rq = stream->perf->ops.enable_metric_set(stream);
-       if (IS_ERR(rq))
-               return PTR_ERR(rq);
+       active = i915_active_create();
+       if (!active)
+               return -ENOMEM;
  
-       i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT);
-       i915_request_put(rq);
+       err = stream->perf->ops.enable_metric_set(stream, active);
+       if (err == 0)
+               __i915_active_wait(active, TASK_UNINTERRUPTIBLE);
  
-       return 0;
+       i915_active_put(active);
+       return err;
+ }
+ static void
+ get_default_sseu_config(struct intel_sseu *out_sseu,
+                       struct intel_engine_cs *engine)
+ {
+       const struct sseu_dev_info *devinfo_sseu =
+               &RUNTIME_INFO(engine->i915)->sseu;
+       *out_sseu = intel_sseu_from_device_info(devinfo_sseu);
+       if (IS_GEN(engine->i915, 11)) {
+               /*
+                * We only need subslice count so it doesn't matter which ones
+                * we select - just turn off low bits in the amount of half of
+                * all available subslices per slice.
+                */
+               out_sseu->subslice_mask =
+                       ~(~0 << (hweight8(out_sseu->subslice_mask) / 2));
+               out_sseu->slice_mask = 0x1;
+       }
+ }
+ static int
+ get_sseu_config(struct intel_sseu *out_sseu,
+               struct intel_engine_cs *engine,
+               const struct drm_i915_gem_context_param_sseu *drm_sseu)
+ {
+       if (drm_sseu->engine.engine_class != engine->uabi_class ||
+           drm_sseu->engine.engine_instance != engine->uabi_instance)
+               return -EINVAL;
+       return i915_gem_user_to_context_sseu(engine->i915, drm_sseu, out_sseu);
  }
  
  /**
@@@ -2879,6 -2901,8 +2901,8 @@@ static int i915_oa_stream_init(struct i
                goto err_oa_buf_alloc;
  
        stream->ops = &i915_oa_stream_ops;
+       perf->sseu = props->sseu;
        WRITE_ONCE(perf->exclusive_stream, stream);
  
        ret = i915_perf_stream_enable_sync(stream);
@@@ -2930,10 -2954,6 +2954,6 @@@ void i915_oa_init_reg_state(const struc
  
        /* perf.exclusive_stream serialised by lrc_configure_all_contexts() */
        stream = READ_ONCE(engine->i915->perf.exclusive_stream);
-       /*
-        * For gen12, only CTX_R_PWR_CLK_STATE needs update, but the caller
-        * is already doing that, so nothing to be done for gen12 here.
-        */
        if (stream && INTEL_GEN(stream->perf->i915) < 12)
                gen8_update_reg_state_unlocked(ce, stream);
  }
@@@ -3024,7 -3044,8 +3044,8 @@@ static enum hrtimer_restart oa_poll_che
                wake_up(&stream->poll_wq);
        }
  
-       hrtimer_forward_now(hrtimer, ns_to_ktime(POLL_PERIOD));
+       hrtimer_forward_now(hrtimer,
+                           ns_to_ktime(stream->poll_oa_period));
  
        return HRTIMER_RESTART;
  }
@@@ -3155,7 -3176,7 +3176,7 @@@ static long i915_perf_config_locked(str
                return -EINVAL;
  
        if (config != stream->oa_config) {
-               struct i915_request *rq;
+               int err;
  
                /*
                 * If OA is bound to a specific context, emit the
                 * When set globally, we use a low priority kernel context,
                 * so it will effectively take effect when idle.
                 */
-               rq = emit_oa_config(stream, config, oa_context(stream));
-               if (!IS_ERR(rq)) {
+               err = emit_oa_config(stream, config, oa_context(stream), NULL);
+               if (!err)
                        config = xchg(&stream->oa_config, config);
-                       i915_request_put(rq);
-               } else {
-                       ret = PTR_ERR(rq);
-               }
+               else
+                       ret = err;
        }
  
        i915_oa_config_put(config);
@@@ -3385,13 -3404,21 +3404,21 @@@ i915_perf_open_ioctl_locked(struct i915
                privileged_op = true;
        }
  
+       /*
+        * Asking for SSEU configuration is a priviliged operation.
+        */
+       if (props->has_sseu)
+               privileged_op = true;
+       else
+               get_default_sseu_config(&props->sseu, props->engine);
        /* Similar to perf's kernel.perf_paranoid_cpu sysctl option
         * we check a dev.i915.perf_stream_paranoid sysctl option
         * to determine if it's ok to access system wide OA counters
 -       * without CAP_SYS_ADMIN privileges.
 +       * without CAP_PERFMON or CAP_SYS_ADMIN privileges.
         */
        if (privileged_op &&
 -          i915_perf_stream_paranoid && !capable(CAP_SYS_ADMIN)) {
 +          i915_perf_stream_paranoid && !perfmon_capable()) {
                DRM_DEBUG("Insufficient privileges to open i915 perf stream\n");
                ret = -EACCES;
                goto err_ctx;
  
        stream->perf = perf;
        stream->ctx = specific_ctx;
+       stream->poll_oa_period = props->poll_oa_period;
  
        ret = i915_oa_stream_init(stream, param, props);
        if (ret)
@@@ -3454,8 -3482,7 +3482,7 @@@ err
  
  static u64 oa_exponent_to_ns(struct i915_perf *perf, int exponent)
  {
-       return div64_u64(1000000000ULL * (2ULL << exponent),
-                        1000ULL * RUNTIME_INFO(perf->i915)->cs_timestamp_frequency_khz);
+       return i915_cs_timestamp_ticks_to_ns(perf->i915, 2ULL << exponent);
  }
  
  /**
@@@ -3480,8 -3507,10 +3507,10 @@@ static int read_properties_unlocked(str
  {
        u64 __user *uprop = uprops;
        u32 i;
+       int ret;
  
        memset(props, 0, sizeof(struct perf_open_properties));
+       props->poll_oa_period = DEFAULT_POLL_PERIOD_NS;
  
        if (!n_props) {
                DRM_DEBUG("No i915 perf properties given\n");
        for (i = 0; i < n_props; i++) {
                u64 oa_period, oa_freq_hz;
                u64 id, value;
-               int ret;
  
                ret = get_user(id, uprop);
                if (ret)
                        } else
                                oa_freq_hz = 0;
  
 -                      if (oa_freq_hz > i915_oa_max_sample_rate &&
 -                          !capable(CAP_SYS_ADMIN)) {
 -                              DRM_DEBUG("OA exponent would exceed the max sampling frequency (sysctl dev.i915.oa_max_sample_rate) %uHz without root privileges\n",
 +                      if (oa_freq_hz > i915_oa_max_sample_rate && !perfmon_capable()) {
 +                              DRM_DEBUG("OA exponent would exceed the max sampling frequency (sysctl dev.i915.oa_max_sample_rate) %uHz without CAP_PERFMON or CAP_SYS_ADMIN privileges\n",
                                          i915_oa_max_sample_rate);
                                return -EACCES;
                        }
                case DRM_I915_PERF_PROP_HOLD_PREEMPTION:
                        props->hold_preemption = !!value;
                        break;
+               case DRM_I915_PERF_PROP_GLOBAL_SSEU: {
+                       struct drm_i915_gem_context_param_sseu user_sseu;
+                       if (copy_from_user(&user_sseu,
+                                          u64_to_user_ptr(value),
+                                          sizeof(user_sseu))) {
+                               DRM_DEBUG("Unable to copy global sseu parameter\n");
+                               return -EFAULT;
+                       }
+                       ret = get_sseu_config(&props->sseu, props->engine, &user_sseu);
+                       if (ret) {
+                               DRM_DEBUG("Invalid SSEU configuration\n");
+                               return ret;
+                       }
+                       props->has_sseu = true;
+                       break;
+               }
+               case DRM_I915_PERF_PROP_POLL_OA_PERIOD:
+                       if (value < 100000 /* 100us */) {
+                               DRM_DEBUG("OA availability timer too small (%lluns < 100us)\n",
+                                         value);
+                               return -EINVAL;
+                       }
+                       props->poll_oa_period = value;
+                       break;
                case DRM_I915_PERF_PROP_MAX:
                        MISSING_CASE(id);
                        return -EINVAL;
@@@ -3678,7 -3733,6 +3732,6 @@@ int i915_perf_open_ioctl(struct drm_dev
  void i915_perf_register(struct drm_i915_private *i915)
  {
        struct i915_perf *perf = &i915->perf;
-       int ret;
  
        if (!perf->i915)
                return;
        perf->metrics_kobj =
                kobject_create_and_add("metrics",
                                       &i915->drm.primary->kdev->kobj);
-       if (!perf->metrics_kobj)
-               goto exit;
-       sysfs_attr_init(&perf->test_config.sysfs_metric_id.attr);
-       if (IS_TIGERLAKE(i915)) {
-               i915_perf_load_test_config_tgl(i915);
-       } else if (INTEL_GEN(i915) >= 11) {
-               i915_perf_load_test_config_icl(i915);
-       } else if (IS_CANNONLAKE(i915)) {
-               i915_perf_load_test_config_cnl(i915);
-       } else if (IS_COFFEELAKE(i915)) {
-               if (IS_CFL_GT2(i915))
-                       i915_perf_load_test_config_cflgt2(i915);
-               if (IS_CFL_GT3(i915))
-                       i915_perf_load_test_config_cflgt3(i915);
-       } else if (IS_GEMINILAKE(i915)) {
-               i915_perf_load_test_config_glk(i915);
-       } else if (IS_KABYLAKE(i915)) {
-               if (IS_KBL_GT2(i915))
-                       i915_perf_load_test_config_kblgt2(i915);
-               else if (IS_KBL_GT3(i915))
-                       i915_perf_load_test_config_kblgt3(i915);
-       } else if (IS_BROXTON(i915)) {
-               i915_perf_load_test_config_bxt(i915);
-       } else if (IS_SKYLAKE(i915)) {
-               if (IS_SKL_GT2(i915))
-                       i915_perf_load_test_config_sklgt2(i915);
-               else if (IS_SKL_GT3(i915))
-                       i915_perf_load_test_config_sklgt3(i915);
-               else if (IS_SKL_GT4(i915))
-                       i915_perf_load_test_config_sklgt4(i915);
-       } else if (IS_CHERRYVIEW(i915)) {
-               i915_perf_load_test_config_chv(i915);
-       } else if (IS_BROADWELL(i915)) {
-               i915_perf_load_test_config_bdw(i915);
-       } else if (IS_HASWELL(i915)) {
-               i915_perf_load_test_config_hsw(i915);
-       }
-       if (perf->test_config.id == 0)
-               goto sysfs_error;
-       ret = sysfs_create_group(perf->metrics_kobj,
-                                &perf->test_config.sysfs_metric);
-       if (ret)
-               goto sysfs_error;
-       perf->test_config.perf = perf;
-       kref_init(&perf->test_config.ref);
-       goto exit;
  
- sysfs_error:
-       kobject_put(perf->metrics_kobj);
-       perf->metrics_kobj = NULL;
- exit:
        mutex_unlock(&perf->lock);
  }
  
@@@ -3769,9 -3766,6 +3765,6 @@@ void i915_perf_unregister(struct drm_i9
        if (!perf->metrics_kobj)
                return;
  
-       sysfs_remove_group(perf->metrics_kobj,
-                          &perf->test_config.sysfs_metric);
        kobject_put(perf->metrics_kobj);
        perf->metrics_kobj = NULL;
  }
@@@ -4006,7 -4000,7 +3999,7 @@@ int i915_perf_add_config_ioctl(struct d
                return -EINVAL;
        }
  
 -      if (i915_perf_stream_paranoid && !capable(CAP_SYS_ADMIN)) {
 +      if (i915_perf_stream_paranoid && !perfmon_capable()) {
                DRM_DEBUG("Insufficient privileges to add i915 OA config\n");
                return -EACCES;
        }
@@@ -4153,7 -4147,7 +4146,7 @@@ int i915_perf_remove_config_ioctl(struc
                return -ENOTSUPP;
        }
  
 -      if (i915_perf_stream_paranoid && !capable(CAP_SYS_ADMIN)) {
 +      if (i915_perf_stream_paranoid && !perfmon_capable()) {
                DRM_DEBUG("Insufficient privileges to remove i915 OA config\n");
                return -EACCES;
        }
@@@ -4346,8 -4340,8 +4339,8 @@@ void i915_perf_init(struct drm_i915_pri
        if (perf->ops.enable_metric_set) {
                mutex_init(&perf->lock);
  
-               oa_sample_rate_hard_limit = 1000 *
-                       (RUNTIME_INFO(i915)->cs_timestamp_frequency_khz / 2);
+               oa_sample_rate_hard_limit =
+                       RUNTIME_INFO(i915)->cs_timestamp_frequency_hz / 2;
  
                mutex_init(&perf->metrics_lock);
                idr_init(&perf->metrics_idr);
                ratelimit_set_flags(&perf->spurious_report_rs,
                                    RATELIMIT_MSG_ON_RELEASE);
  
+               ratelimit_state_init(&perf->tail_pointer_race,
+                                    5 * HZ, 10);
+               ratelimit_set_flags(&perf->tail_pointer_race,
+                                   RATELIMIT_MSG_ON_RELEASE);
                atomic64_set(&perf->noa_programming_delay,
                             500 * 1000 /* 500us */);
  
@@@ -4430,8 -4429,15 +4428,15 @@@ int i915_perf_ioctl_version(void
         *    preemption on a particular context so that performance data is
         *    accessible from a delta of MI_RPC reports without looking at the
         *    OA buffer.
+        *
+        * 4: Add DRM_I915_PERF_PROP_ALLOWED_SSEU to limit what contexts can
+        *    be run for the duration of the performance recording based on
+        *    their SSEU configuration.
+        *
+        * 5: Add DRM_I915_PERF_PROP_POLL_OA_PERIOD parameter that controls the
+        *    interval for the hrtimer used to check for OA data.
         */
-       return 3;
+       return 5;
  }
  
  #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
index 548cc25ea4abed9565f1eebed9af9aa92b908a58,632d72177123c524bbff14840991d96f6475b21a..55b49a31729bf180b924cd742a810f355d8e8039
  #include <drm/drm_fourcc.h>
  #include <drm/drm_gem_framebuffer_helper.h>
  #include <drm/drm_irq.h>
+ #include <drm/drm_managed.h>
  #include <drm/drm_of.h>
  #include <drm/drm_panel.h>
  #include <drm/drm_plane.h>
  #include <drm/drm_plane_helper.h>
  #include <drm/drm_probe_helper.h>
+ #include <drm/drm_simple_kms_helper.h>
  #include <drm/drm_vblank.h>
  
  #define JZ_REG_LCD_CFG                                0x00
@@@ -328,8 -330,8 +330,8 @@@ static int ingenic_drm_crtc_atomic_chec
        if (!drm_atomic_crtc_needs_modeset(state))
                return 0;
  
 -      if (state->mode.hdisplay > priv->soc_info->max_height ||
 -          state->mode.vdisplay > priv->soc_info->max_width)
 +      if (state->mode.hdisplay > priv->soc_info->max_width ||
 +          state->mode.vdisplay > priv->soc_info->max_height)
                return -EINVAL;
  
        rate = clk_round_rate(priv->pix_clk,
@@@ -474,7 -476,7 +476,7 @@@ static int ingenic_drm_encoder_atomic_c
  
  static irqreturn_t ingenic_drm_irq_handler(int irq, void *arg)
  {
 -      struct ingenic_drm *priv = arg;
 +      struct ingenic_drm *priv = drm_device_get_priv(arg);
        unsigned int state;
  
        regmap_read(priv->map, JZ_REG_LCD_STATE, &state);
        return IRQ_HANDLED;
  }
  
- static void ingenic_drm_release(struct drm_device *drm)
- {
-       struct ingenic_drm *priv = drm_device_get_priv(drm);
-       drm_mode_config_cleanup(drm);
-       drm_dev_fini(drm);
-       kfree(priv);
- }
  static int ingenic_drm_enable_vblank(struct drm_crtc *crtc)
  {
        struct ingenic_drm *priv = drm_crtc_get_priv(crtc);
@@@ -540,7 -533,6 +533,6 @@@ static struct drm_driver ingenic_drm_dr
        .gem_prime_mmap         = drm_gem_cma_prime_mmap,
  
        .irq_handler            = ingenic_drm_irq_handler,
-       .release                = ingenic_drm_release,
  };
  
  static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs = {
@@@ -592,10 -584,6 +584,6 @@@ static const struct drm_mode_config_fun
        .atomic_commit          = drm_atomic_helper_commit,
  };
  
- static const struct drm_encoder_funcs ingenic_drm_encoder_funcs = {
-       .destroy                = drm_encoder_cleanup,
- };
  static void ingenic_drm_free_dma_hwdesc(void *d)
  {
        struct ingenic_drm *priv = d;
@@@ -623,24 -611,21 +611,21 @@@ static int ingenic_drm_probe(struct pla
                return -EINVAL;
        }
  
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
+       priv = devm_drm_dev_alloc(dev, &ingenic_drm_driver_data,
+                                 struct ingenic_drm, drm);
+       if (IS_ERR(priv))
+               return PTR_ERR(priv);
  
        priv->soc_info = soc_info;
        priv->dev = dev;
        drm = &priv->drm;
-       drm->dev_private = priv;
  
        platform_set_drvdata(pdev, priv);
  
-       ret = devm_drm_dev_init(dev, drm, &ingenic_drm_driver_data);
-       if (ret) {
-               kfree(priv);
+       ret = drmm_mode_config_init(drm);
+       if (ret)
                return ret;
-       }
  
-       drm_mode_config_init(drm);
        drm->mode_config.min_width = 0;
        drm->mode_config.min_height = 0;
        drm->mode_config.max_width = soc_info->max_width;
        }
  
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "Failed to get platform irq");
+       if (irq < 0)
                return irq;
-       }
  
        if (soc_info->needs_dev_clk) {
                priv->lcd_clk = devm_clk_get(dev, "lcd");
        drm_encoder_helper_add(&priv->encoder,
                               &ingenic_drm_encoder_helper_funcs);
  
-       ret = drm_encoder_init(drm, &priv->encoder, &ingenic_drm_encoder_funcs,
-                              DRM_MODE_ENCODER_DPI, NULL);
+       ret = drm_simple_encoder_init(drm, &priv->encoder,
+                                     DRM_MODE_ENCODER_DPI);
        if (ret) {
                dev_err(dev, "Failed to init encoder: %i", ret);
                return ret;
                goto err_devclk_disable;
        }
  
-       ret = drm_fbdev_generic_setup(drm, 32);
-       if (ret)
-               dev_warn(dev, "Unable to start fbdev emulation: %i", ret);
+       drm_fbdev_generic_setup(drm, 32);
  
        return 0;
  
@@@ -843,7 -824,6 +824,7 @@@ static const struct of_device_id ingeni
        { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info },
        { /* sentinel */ },
  };
 +MODULE_DEVICE_TABLE(of, ingenic_drm_of_match);
  
  static struct platform_driver ingenic_drm_driver = {
        .driver = {
index 8c2e1b47e81a59c582b4556ed7cde3f7c4df2452,621f6de0f076a6176ffd5f9e929e971b59a1d9ff..4c5aafcec7991bec654f03145f05a60c13db51c7
@@@ -11,6 -11,7 +11,7 @@@
  #include <linux/component.h>
  #include <linux/module.h>
  #include <linux/of_graph.h>
+ #include <linux/sys_soc.h>
  #include <linux/platform_device.h>
  #include <linux/soc/amlogic/meson-canvas.h>
  
@@@ -183,6 -184,24 +184,24 @@@ static void meson_remove_framebuffers(v
        kfree(ap);
  }
  
+ struct meson_drm_soc_attr {
+       struct meson_drm_soc_limits limits;
+       const struct soc_device_attribute *attrs;
+ };
+ static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = {
+       /* S805X/S805Y HDMI PLL won't lock for HDMI PHY freq > 1,65GHz */
+       {
+               .limits = {
+                       .max_hdmi_phy_freq = 1650000,
+               },
+               .attrs = (const struct soc_device_attribute []) {
+                       { .soc_id = "GXL (S805*)", },
+                       { /* sentinel */ },
+               }
+       },
+ };
  static int meson_drv_bind_master(struct device *dev, bool has_components)
  {
        struct platform_device *pdev = to_platform_device(dev);
        struct drm_device *drm;
        struct resource *res;
        void __iomem *regs;
-       int ret;
+       int ret, i;
  
        /* Checks if an output connector is available */
        if (!meson_vpu_has_available_connectors(dev)) {
        if (ret)
                goto free_drm;
  
+       /* Assign limits per soc revision/package */
+       for (i = 0 ; i < ARRAY_SIZE(meson_drm_soc_attrs) ; ++i) {
+               if (soc_device_match(meson_drm_soc_attrs[i].attrs)) {
+                       priv->limits = &meson_drm_soc_attrs[i].limits;
+                       break;
+               }
+       }
        /* Remove early framebuffers (ie. simplefb) */
        meson_remove_framebuffers();
  
-       drm_mode_config_init(drm);
+       ret = drmm_mode_config_init(drm);
+       if (ret)
+               goto free_drm;
        drm->mode_config.max_width = 3840;
        drm->mode_config.max_height = 2160;
        drm->mode_config.funcs = &meson_mode_config_funcs;
@@@ -379,7 -408,6 +408,6 @@@ static void meson_drv_unbind(struct dev
        drm_dev_unregister(drm);
        drm_irq_uninstall(drm);
        drm_kms_helper_poll_fini(drm);
-       drm_mode_config_cleanup(drm);
        drm_dev_put(drm);
  }
  
@@@ -412,7 -440,9 +440,7 @@@ static int __maybe_unused meson_drv_pm_
        if (priv->afbcd.ops)
                priv->afbcd.ops->init(priv);
  
 -      drm_mode_config_helper_resume(priv->drm);
 -
 -      return 0;
 +      return drm_mode_config_helper_resume(priv->drm);
  }
  
  static int compare_of(struct device *dev, void *data)
index 64cb6ba4bc42d9ebb19f6dedb1272a36e094185d,5be963e9db05922582b3860fad5b02a11c42c721..24a12c453095fa762125a45aa9f5f50820c20ac7
@@@ -695,7 -695,7 +695,7 @@@ dw_hdmi_mode_valid(struct drm_connecto
        dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
                __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
  
-       return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
+       return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq);
  }
  
  /* Encoder */
@@@ -1034,8 -1034,10 +1034,8 @@@ static int meson_dw_hdmi_bind(struct de
                return PTR_ERR(dw_plat_data->regm);
  
        irq = platform_get_irq(pdev, 0);
 -      if (irq < 0) {
 -              dev_err(dev, "Failed to get hdmi top irq\n");
 +      if (irq < 0)
                return irq;
 -      }
  
        ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
                                        dw_hdmi_top_thread_irq, IRQF_SHARED,
index 3364904eccff5a4bda4c1fbaea8f5b8e4923e98b,339a0c387eae4eb744d66446a8b2af73ab37f7ab..e5c230d9ae24ed2ccca95c4d25c6765ef26beca0
  #include "nouveau_dma.h"
  #include "nouveau_mem.h"
  #include "nouveau_bo.h"
+ #include "nouveau_svm.h"
  
  #include <nvif/class.h>
  #include <nvif/object.h>
  #include <nvif/if000c.h>
  #include <nvif/if500b.h>
  #include <nvif/if900b.h>
+ #include <nvif/if000c.h>
  
  #include <linux/sched/mm.h>
  #include <linux/hmm.h>
@@@ -54,66 -56,69 +56,69 @@@ enum nouveau_aper 
  typedef int (*nouveau_migrate_copy_t)(struct nouveau_drm *drm, u64 npages,
                                      enum nouveau_aper, u64 dst_addr,
                                      enum nouveau_aper, u64 src_addr);
+ typedef int (*nouveau_clear_page_t)(struct nouveau_drm *drm, u32 length,
+                                     enum nouveau_aper, u64 dst_addr);
  
  struct nouveau_dmem_chunk {
        struct list_head list;
        struct nouveau_bo *bo;
        struct nouveau_drm *drm;
-       unsigned long pfn_first;
        unsigned long callocated;
-       unsigned long bitmap[BITS_TO_LONGS(DMEM_CHUNK_NPAGES)];
-       spinlock_t lock;
+       struct dev_pagemap pagemap;
  };
  
  struct nouveau_dmem_migrate {
        nouveau_migrate_copy_t copy_func;
+       nouveau_clear_page_t clear_func;
        struct nouveau_channel *chan;
  };
  
  struct nouveau_dmem {
        struct nouveau_drm *drm;
-       struct dev_pagemap pagemap;
        struct nouveau_dmem_migrate migrate;
-       struct list_head chunk_free;
-       struct list_head chunk_full;
-       struct list_head chunk_empty;
+       struct list_head chunks;
        struct mutex mutex;
+       struct page *free_pages;
+       spinlock_t lock;
  };
  
- static inline struct nouveau_dmem *page_to_dmem(struct page *page)
+ static struct nouveau_dmem_chunk *nouveau_page_to_chunk(struct page *page)
+ {
+       return container_of(page->pgmap, struct nouveau_dmem_chunk, pagemap);
+ }
+ static struct nouveau_drm *page_to_drm(struct page *page)
  {
-       return container_of(page->pgmap, struct nouveau_dmem, pagemap);
+       struct nouveau_dmem_chunk *chunk = nouveau_page_to_chunk(page);
+       return chunk->drm;
  }
  
 -static unsigned long nouveau_dmem_page_addr(struct page *page)
 +unsigned long nouveau_dmem_page_addr(struct page *page)
  {
-       struct nouveau_dmem_chunk *chunk = page->zone_device_data;
-       unsigned long idx = page_to_pfn(page) - chunk->pfn_first;
+       struct nouveau_dmem_chunk *chunk = nouveau_page_to_chunk(page);
+       unsigned long off = (page_to_pfn(page) << PAGE_SHIFT) -
+                               chunk->pagemap.res.start;
  
-       return (idx << PAGE_SHIFT) + chunk->bo->bo.offset;
+       return chunk->bo->bo.offset + off;
  }
  
  static void nouveau_dmem_page_free(struct page *page)
  {
-       struct nouveau_dmem_chunk *chunk = page->zone_device_data;
-       unsigned long idx = page_to_pfn(page) - chunk->pfn_first;
+       struct nouveau_dmem_chunk *chunk = nouveau_page_to_chunk(page);
+       struct nouveau_dmem *dmem = chunk->drm->dmem;
+       spin_lock(&dmem->lock);
+       page->zone_device_data = dmem->free_pages;
+       dmem->free_pages = page;
  
-       /*
-        * FIXME:
-        *
-        * This is really a bad example, we need to overhaul nouveau memory
-        * management to be more page focus and allow lighter locking scheme
-        * to be use in the process.
-        */
-       spin_lock(&chunk->lock);
-       clear_bit(idx, chunk->bitmap);
        WARN_ON(!chunk->callocated);
        chunk->callocated--;
        /*
         * FIXME when chunk->callocated reach 0 we should add the chunk to
         * a reclaim list so that it can be freed in case of memory pressure.
         */
-       spin_unlock(&chunk->lock);
+       spin_unlock(&dmem->lock);
  }
  
  static void nouveau_dmem_fence_done(struct nouveau_fence **fence)
@@@ -165,8 -170,8 +170,8 @@@ error_free_page
  
  static vm_fault_t nouveau_dmem_migrate_to_ram(struct vm_fault *vmf)
  {
-       struct nouveau_dmem *dmem = page_to_dmem(vmf->page);
-       struct nouveau_drm *drm = dmem->drm;
+       struct nouveau_drm *drm = page_to_drm(vmf->page);
+       struct nouveau_dmem *dmem = drm->dmem;
        struct nouveau_fence *fence;
        unsigned long src = 0, dst = 0;
        dma_addr_t dma_addr = 0;
@@@ -209,131 -214,105 +214,105 @@@ static const struct dev_pagemap_ops nou
  };
  
  static int
- nouveau_dmem_chunk_alloc(struct nouveau_drm *drm)
+ nouveau_dmem_chunk_alloc(struct nouveau_drm *drm, struct page **ppage)
  {
        struct nouveau_dmem_chunk *chunk;
+       struct resource *res;
+       struct page *page;
+       void *ptr;
+       unsigned long i, pfn_first;
        int ret;
  
-       if (drm->dmem == NULL)
-               return -EINVAL;
-       mutex_lock(&drm->dmem->mutex);
-       chunk = list_first_entry_or_null(&drm->dmem->chunk_empty,
-                                        struct nouveau_dmem_chunk,
-                                        list);
+       chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
        if (chunk == NULL) {
-               mutex_unlock(&drm->dmem->mutex);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
  
-       list_del(&chunk->list);
-       mutex_unlock(&drm->dmem->mutex);
+       /* Allocate unused physical address space for device private pages. */
+       res = request_free_mem_region(&iomem_resource, DMEM_CHUNK_SIZE,
+                                     "nouveau_dmem");
+       if (IS_ERR(res)) {
+               ret = PTR_ERR(res);
+               goto out_free;
+       }
+       chunk->drm = drm;
+       chunk->pagemap.type = MEMORY_DEVICE_PRIVATE;
+       chunk->pagemap.res = *res;
+       chunk->pagemap.ops = &nouveau_dmem_pagemap_ops;
+       chunk->pagemap.owner = drm->dev;
  
        ret = nouveau_bo_new(&drm->client, DMEM_CHUNK_SIZE, 0,
                             TTM_PL_FLAG_VRAM, 0, 0, NULL, NULL,
                             &chunk->bo);
        if (ret)
-               goto out;
+               goto out_release;
  
        ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
-       if (ret) {
-               nouveau_bo_ref(NULL, &chunk->bo);
-               goto out;
-       }
+       if (ret)
+               goto out_bo_free;
  
-       bitmap_zero(chunk->bitmap, DMEM_CHUNK_NPAGES);
-       spin_lock_init(&chunk->lock);
+       ptr = memremap_pages(&chunk->pagemap, numa_node_id());
+       if (IS_ERR(ptr)) {
+               ret = PTR_ERR(ptr);
+               goto out_bo_unpin;
+       }
  
- out:
        mutex_lock(&drm->dmem->mutex);
-       if (chunk->bo)
-               list_add(&chunk->list, &drm->dmem->chunk_empty);
-       else
-               list_add_tail(&chunk->list, &drm->dmem->chunk_empty);
+       list_add(&chunk->list, &drm->dmem->chunks);
        mutex_unlock(&drm->dmem->mutex);
  
-       return ret;
- }
- static struct nouveau_dmem_chunk *
- nouveau_dmem_chunk_first_free_locked(struct nouveau_drm *drm)
- {
-       struct nouveau_dmem_chunk *chunk;
-       chunk = list_first_entry_or_null(&drm->dmem->chunk_free,
-                                        struct nouveau_dmem_chunk,
-                                        list);
-       if (chunk)
-               return chunk;
-       chunk = list_first_entry_or_null(&drm->dmem->chunk_empty,
-                                        struct nouveau_dmem_chunk,
-                                        list);
-       if (chunk->bo)
-               return chunk;
-       return NULL;
- }
- static int
- nouveau_dmem_pages_alloc(struct nouveau_drm *drm,
-                        unsigned long npages,
-                        unsigned long *pages)
- {
-       struct nouveau_dmem_chunk *chunk;
-       unsigned long c;
-       int ret;
-       memset(pages, 0xff, npages * sizeof(*pages));
-       mutex_lock(&drm->dmem->mutex);
-       for (c = 0; c < npages;) {
-               unsigned long i;
-               chunk = nouveau_dmem_chunk_first_free_locked(drm);
-               if (chunk == NULL) {
-                       mutex_unlock(&drm->dmem->mutex);
-                       ret = nouveau_dmem_chunk_alloc(drm);
-                       if (ret) {
-                               if (c)
-                                       return 0;
-                               return ret;
-                       }
-                       mutex_lock(&drm->dmem->mutex);
-                       continue;
-               }
-               spin_lock(&chunk->lock);
-               i = find_first_zero_bit(chunk->bitmap, DMEM_CHUNK_NPAGES);
-               while (i < DMEM_CHUNK_NPAGES && c < npages) {
-                       pages[c] = chunk->pfn_first + i;
-                       set_bit(i, chunk->bitmap);
-                       chunk->callocated++;
-                       c++;
-                       i = find_next_zero_bit(chunk->bitmap,
-                                       DMEM_CHUNK_NPAGES, i);
-               }
-               spin_unlock(&chunk->lock);
+       pfn_first = chunk->pagemap.res.start >> PAGE_SHIFT;
+       page = pfn_to_page(pfn_first);
+       spin_lock(&drm->dmem->lock);
+       for (i = 0; i < DMEM_CHUNK_NPAGES - 1; ++i, ++page) {
+               page->zone_device_data = drm->dmem->free_pages;
+               drm->dmem->free_pages = page;
        }
-       mutex_unlock(&drm->dmem->mutex);
+       *ppage = page;
+       chunk->callocated++;
+       spin_unlock(&drm->dmem->lock);
+       NV_INFO(drm, "DMEM: registered %ldMB of device memory\n",
+               DMEM_CHUNK_SIZE >> 20);
  
        return 0;
+ out_bo_unpin:
+       nouveau_bo_unpin(chunk->bo);
+ out_bo_free:
+       nouveau_bo_ref(NULL, &chunk->bo);
+ out_release:
+       release_mem_region(chunk->pagemap.res.start,
+                          resource_size(&chunk->pagemap.res));
+ out_free:
+       kfree(chunk);
+ out:
+       return ret;
  }
  
  static struct page *
  nouveau_dmem_page_alloc_locked(struct nouveau_drm *drm)
  {
-       unsigned long pfns[1];
-       struct page *page;
+       struct nouveau_dmem_chunk *chunk;
+       struct page *page = NULL;
        int ret;
  
-       /* FIXME stop all the miss-match API ... */
-       ret = nouveau_dmem_pages_alloc(drm, 1, pfns);
-       if (ret)
-               return NULL;
+       spin_lock(&drm->dmem->lock);
+       if (drm->dmem->free_pages) {
+               page = drm->dmem->free_pages;
+               drm->dmem->free_pages = page->zone_device_data;
+               chunk = nouveau_page_to_chunk(page);
+               chunk->callocated++;
+               spin_unlock(&drm->dmem->lock);
+       } else {
+               spin_unlock(&drm->dmem->lock);
+               ret = nouveau_dmem_chunk_alloc(drm, &page);
+               if (ret)
+                       return NULL;
+       }
  
-       page = pfn_to_page(pfns[0]);
        get_page(page);
        lock_page(page);
        return page;
@@@ -356,12 -335,7 +335,7 @@@ nouveau_dmem_resume(struct nouveau_drm 
                return;
  
        mutex_lock(&drm->dmem->mutex);
-       list_for_each_entry (chunk, &drm->dmem->chunk_free, list) {
-               ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
-               /* FIXME handle pin failure */
-               WARN_ON(ret);
-       }
-       list_for_each_entry (chunk, &drm->dmem->chunk_full, list) {
+       list_for_each_entry(chunk, &drm->dmem->chunks, list) {
                ret = nouveau_bo_pin(chunk->bo, TTM_PL_FLAG_VRAM, false);
                /* FIXME handle pin failure */
                WARN_ON(ret);
@@@ -378,12 -352,8 +352,8 @@@ nouveau_dmem_suspend(struct nouveau_dr
                return;
  
        mutex_lock(&drm->dmem->mutex);
-       list_for_each_entry (chunk, &drm->dmem->chunk_free, list) {
-               nouveau_bo_unpin(chunk->bo);
-       }
-       list_for_each_entry (chunk, &drm->dmem->chunk_full, list) {
+       list_for_each_entry(chunk, &drm->dmem->chunks, list)
                nouveau_bo_unpin(chunk->bo);
-       }
        mutex_unlock(&drm->dmem->mutex);
  }
  
@@@ -397,15 -367,13 +367,13 @@@ nouveau_dmem_fini(struct nouveau_drm *d
  
        mutex_lock(&drm->dmem->mutex);
  
-       WARN_ON(!list_empty(&drm->dmem->chunk_free));
-       WARN_ON(!list_empty(&drm->dmem->chunk_full));
-       list_for_each_entry_safe (chunk, tmp, &drm->dmem->chunk_empty, list) {
-               if (chunk->bo) {
-                       nouveau_bo_unpin(chunk->bo);
-                       nouveau_bo_ref(NULL, &chunk->bo);
-               }
+       list_for_each_entry_safe(chunk, tmp, &drm->dmem->chunks, list) {
+               nouveau_bo_unpin(chunk->bo);
+               nouveau_bo_ref(NULL, &chunk->bo);
                list_del(&chunk->list);
+               memunmap_pages(&chunk->pagemap);
+               release_mem_region(chunk->pagemap.res.start,
+                                  resource_size(&chunk->pagemap.res));
                kfree(chunk);
        }
  
@@@ -471,6 -439,52 +439,52 @@@ nvc0b5_migrate_copy(struct nouveau_drm 
        return 0;
  }
  
+ static int
+ nvc0b5_migrate_clear(struct nouveau_drm *drm, u32 length,
+                    enum nouveau_aper dst_aper, u64 dst_addr)
+ {
+       struct nouveau_channel *chan = drm->dmem->migrate.chan;
+       u32 launch_dma = (1 << 10) /* REMAP_ENABLE_TRUE */ |
+                        (1 << 8) /* DST_MEMORY_LAYOUT_PITCH. */ |
+                        (1 << 7) /* SRC_MEMORY_LAYOUT_PITCH. */ |
+                        (1 << 2) /* FLUSH_ENABLE_TRUE. */ |
+                        (2 << 0) /* DATA_TRANSFER_TYPE_NON_PIPELINED. */;
+       u32 remap = (4 <<  0) /* DST_X_CONST_A */ |
+                   (5 <<  4) /* DST_Y_CONST_B */ |
+                   (3 << 16) /* COMPONENT_SIZE_FOUR */ |
+                   (1 << 24) /* NUM_DST_COMPONENTS_TWO */;
+       int ret;
+       ret = RING_SPACE(chan, 12);
+       if (ret)
+               return ret;
+       switch (dst_aper) {
+       case NOUVEAU_APER_VRAM:
+               BEGIN_IMC0(chan, NvSubCopy, 0x0264, 0);
+                       break;
+       case NOUVEAU_APER_HOST:
+               BEGIN_IMC0(chan, NvSubCopy, 0x0264, 1);
+               break;
+       default:
+               return -EINVAL;
+       }
+       launch_dma |= 0x00002000; /* DST_TYPE_PHYSICAL. */
+       BEGIN_NVC0(chan, NvSubCopy, 0x0700, 3);
+       OUT_RING(chan, 0);
+       OUT_RING(chan, 0);
+       OUT_RING(chan, remap);
+       BEGIN_NVC0(chan, NvSubCopy, 0x0408, 2);
+       OUT_RING(chan, upper_32_bits(dst_addr));
+       OUT_RING(chan, lower_32_bits(dst_addr));
+       BEGIN_NVC0(chan, NvSubCopy, 0x0418, 1);
+       OUT_RING(chan, length >> 3);
+       BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1);
+       OUT_RING(chan, launch_dma);
+       return 0;
+ }
  static int
  nouveau_dmem_migrate_init(struct nouveau_drm *drm)
  {
        case  VOLTA_DMA_COPY_A:
        case TURING_DMA_COPY_A:
                drm->dmem->migrate.copy_func = nvc0b5_migrate_copy;
+               drm->dmem->migrate.clear_func = nvc0b5_migrate_clear;
                drm->dmem->migrate.chan = drm->ttm.chan;
                return 0;
        default:
  void
  nouveau_dmem_init(struct nouveau_drm *drm)
  {
-       struct device *device = drm->dev->dev;
-       struct resource *res;
-       unsigned long i, size, pfn_first;
        int ret;
  
        /* This only make sense on PASCAL or newer */
  
        drm->dmem->drm = drm;
        mutex_init(&drm->dmem->mutex);
-       INIT_LIST_HEAD(&drm->dmem->chunk_free);
-       INIT_LIST_HEAD(&drm->dmem->chunk_full);
-       INIT_LIST_HEAD(&drm->dmem->chunk_empty);
-       size = ALIGN(drm->client.device.info.ram_user, DMEM_CHUNK_SIZE);
+       INIT_LIST_HEAD(&drm->dmem->chunks);
+       mutex_init(&drm->dmem->mutex);
+       spin_lock_init(&drm->dmem->lock);
  
        /* Initialize migration dma helpers before registering memory */
        ret = nouveau_dmem_migrate_init(drm);
-       if (ret)
-               goto out_free;
-       /*
-        * FIXME we need some kind of policy to decide how much VRAM we
-        * want to register with HMM. For now just register everything
-        * and latter if we want to do thing like over commit then we
-        * could revisit this.
-        */
-       res = devm_request_free_mem_region(device, &iomem_resource, size);
-       if (IS_ERR(res))
-               goto out_free;
-       drm->dmem->pagemap.type = MEMORY_DEVICE_PRIVATE;
-       drm->dmem->pagemap.res = *res;
-       drm->dmem->pagemap.ops = &nouveau_dmem_pagemap_ops;
-       drm->dmem->pagemap.owner = drm->dev;
-       if (IS_ERR(devm_memremap_pages(device, &drm->dmem->pagemap)))
-               goto out_free;
-       pfn_first = res->start >> PAGE_SHIFT;
-       for (i = 0; i < (size / DMEM_CHUNK_SIZE); ++i) {
-               struct nouveau_dmem_chunk *chunk;
-               struct page *page;
-               unsigned long j;
-               chunk = kzalloc(sizeof(*chunk), GFP_KERNEL);
-               if (chunk == NULL) {
-                       nouveau_dmem_fini(drm);
-                       return;
-               }
-               chunk->drm = drm;
-               chunk->pfn_first = pfn_first + (i * DMEM_CHUNK_NPAGES);
-               list_add_tail(&chunk->list, &drm->dmem->chunk_empty);
-               page = pfn_to_page(chunk->pfn_first);
-               for (j = 0; j < DMEM_CHUNK_NPAGES; ++j, ++page)
-                       page->zone_device_data = chunk;
+       if (ret) {
+               kfree(drm->dmem);
+               drm->dmem = NULL;
        }
-       NV_INFO(drm, "DMEM: registered %ldMB of device memory\n", size >> 20);
-       return;
- out_free:
-       kfree(drm->dmem);
-       drm->dmem = NULL;
  }
  
  static unsigned long nouveau_dmem_migrate_copy_one(struct nouveau_drm *drm,
-               unsigned long src, dma_addr_t *dma_addr)
+               unsigned long src, dma_addr_t *dma_addr, u64 *pfn)
  {
        struct device *dev = drm->dev->dev;
        struct page *dpage, *spage;
+       unsigned long paddr;
  
        spage = migrate_pfn_to_page(src);
-       if (!spage || !(src & MIGRATE_PFN_MIGRATE))
+       if (!(src & MIGRATE_PFN_MIGRATE))
                goto out;
  
        dpage = nouveau_dmem_page_alloc_locked(drm);
        if (!dpage)
-               return 0;
-       *dma_addr = dma_map_page(dev, spage, 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
-       if (dma_mapping_error(dev, *dma_addr))
-               goto out_free_page;
+               goto out;
  
-       if (drm->dmem->migrate.copy_func(drm, 1, NOUVEAU_APER_VRAM,
-                       nouveau_dmem_page_addr(dpage), NOUVEAU_APER_HOST,
-                       *dma_addr))
-               goto out_dma_unmap;
+       paddr = nouveau_dmem_page_addr(dpage);
+       if (spage) {
+               *dma_addr = dma_map_page(dev, spage, 0, page_size(spage),
+                                        DMA_BIDIRECTIONAL);
+               if (dma_mapping_error(dev, *dma_addr))
+                       goto out_free_page;
+               if (drm->dmem->migrate.copy_func(drm, page_size(spage),
+                       NOUVEAU_APER_VRAM, paddr, NOUVEAU_APER_HOST, *dma_addr))
+                       goto out_dma_unmap;
+       } else {
+               *dma_addr = DMA_MAPPING_ERROR;
+               if (drm->dmem->migrate.clear_func(drm, page_size(dpage),
+                       NOUVEAU_APER_VRAM, paddr))
+                       goto out_free_page;
+       }
  
+       *pfn = NVIF_VMM_PFNMAP_V0_V | NVIF_VMM_PFNMAP_V0_VRAM |
+               ((paddr >> PAGE_SHIFT) << NVIF_VMM_PFNMAP_V0_ADDR_SHIFT);
+       if (src & MIGRATE_PFN_WRITE)
+               *pfn |= NVIF_VMM_PFNMAP_V0_W;
        return migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED;
  
  out_dma_unmap:
  out_free_page:
        nouveau_dmem_page_free_locked(drm, dpage);
  out:
+       *pfn = NVIF_VMM_PFNMAP_V0_NONE;
        return 0;
  }
  
  static void nouveau_dmem_migrate_chunk(struct nouveau_drm *drm,
-               struct migrate_vma *args, dma_addr_t *dma_addrs)
+               struct nouveau_svmm *svmm, struct migrate_vma *args,
+               dma_addr_t *dma_addrs, u64 *pfns)
  {
        struct nouveau_fence *fence;
        unsigned long addr = args->start, nr_dma = 0, i;
  
        for (i = 0; addr < args->end; i++) {
                args->dst[i] = nouveau_dmem_migrate_copy_one(drm, args->src[i],
-                               dma_addrs + nr_dma);
-               if (args->dst[i])
+                               dma_addrs + nr_dma, pfns + i);
+               if (!dma_mapping_error(drm->dev->dev, dma_addrs[nr_dma]))
                        nr_dma++;
                addr += PAGE_SIZE;
        }
        nouveau_fence_new(drm->dmem->migrate.chan, false, &fence);
        migrate_vma_pages(args);
        nouveau_dmem_fence_done(&fence);
+       nouveau_pfns_map(svmm, args->vma->vm_mm, args->start, pfns, i);
  
        while (nr_dma--) {
                dma_unmap_page(drm->dev->dev, dma_addrs[nr_dma], PAGE_SIZE,
                                DMA_BIDIRECTIONAL);
        }
-       /*
-        * FIXME optimization: update GPU page table to point to newly migrated
-        * memory.
-        */
        migrate_vma_finalize(args);
  }
  
  int
  nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
+                        struct nouveau_svmm *svmm,
                         struct vm_area_struct *vma,
                         unsigned long start,
                         unsigned long end)
                .vma            = vma,
                .start          = start,
        };
-       unsigned long c, i;
+       unsigned long i;
+       u64 *pfns;
        int ret = -ENOMEM;
  
+       if (drm->dmem == NULL)
+               return -ENODEV;
        args.src = kcalloc(max, sizeof(*args.src), GFP_KERNEL);
        if (!args.src)
                goto out;
        if (!dma_addrs)
                goto out_free_dst;
  
-       for (i = 0; i < npages; i += c) {
-               c = min(SG_MAX_SINGLE_ALLOC, npages);
-               args.end = start + (c << PAGE_SHIFT);
+       pfns = nouveau_pfns_alloc(max);
+       if (!pfns)
+               goto out_free_dma;
+       for (i = 0; i < npages; i += max) {
+               args.end = start + (max << PAGE_SHIFT);
                ret = migrate_vma_setup(&args);
                if (ret)
-                       goto out_free_dma;
+                       goto out_free_pfns;
  
                if (args.cpages)
-                       nouveau_dmem_migrate_chunk(drm, &args, dma_addrs);
+                       nouveau_dmem_migrate_chunk(drm, svmm, &args, dma_addrs,
+                                                  pfns);
                args.start = args.end;
        }
  
        ret = 0;
+ out_free_pfns:
+       nouveau_pfns_free(pfns);
  out_free_dma:
        kfree(dma_addrs);
  out_free_dst:
@@@ -671,3 -662,28 +662,3 @@@ out_free_src
  out:
        return ret;
  }
 -
 -void
 -nouveau_dmem_convert_pfn(struct nouveau_drm *drm,
 -                       struct hmm_range *range)
 -{
 -      unsigned long i, npages;
 -
 -      npages = (range->end - range->start) >> PAGE_SHIFT;
 -      for (i = 0; i < npages; ++i) {
 -              struct page *page;
 -              uint64_t addr;
 -
 -              page = hmm_device_entry_to_page(range, range->pfns[i]);
 -              if (page == NULL)
 -                      continue;
 -
 -              if (!is_device_private_page(page))
 -                      continue;
 -
 -              addr = nouveau_dmem_page_addr(page);
 -              range->pfns[i] &= ((1UL << range->pfn_shift) - 1);
 -              range->pfns[i] |= (addr >> PAGE_SHIFT) << range->pfn_shift;
 -              range->pfns[i] |= NVIF_VMM_PFNMAP_V0_VRAM;
 -      }
 -}
index db3b59b210af13f799a94e001df725279fdce70b,3e03d9629a3861605da7b48d68a8dbc0ed50f7b1..64da5d3635c8e540a5d1bb0ad7935f9a8b413542
@@@ -25,6 -25,7 +25,7 @@@
  struct drm_device;
  struct drm_file;
  struct nouveau_drm;
+ struct nouveau_svmm;
  struct hmm_range;
  
  #if IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM)
@@@ -34,11 -35,13 +35,12 @@@ void nouveau_dmem_suspend(struct nouvea
  void nouveau_dmem_resume(struct nouveau_drm *);
  
  int nouveau_dmem_migrate_vma(struct nouveau_drm *drm,
+                            struct nouveau_svmm *svmm,
                             struct vm_area_struct *vma,
                             unsigned long start,
                             unsigned long end);
 +unsigned long nouveau_dmem_page_addr(struct page *page);
  
 -void nouveau_dmem_convert_pfn(struct nouveau_drm *drm,
 -                            struct hmm_range *range);
  #else /* IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM) */
  static inline void nouveau_dmem_init(struct nouveau_drm *drm) {}
  static inline void nouveau_dmem_fini(struct nouveau_drm *drm) {}
index 407e34a5c0abf834eefaf798bd61600aab0d83a6,fe89abf237a8d1903d2e51009c7fe874bed8d9c3..22f054f7ee3e405a3d00f87a924b98d0e9d390fe
@@@ -70,6 -70,12 +70,12 @@@ struct nouveau_svm 
  #define SVM_DBG(s,f,a...) NV_DEBUG((s)->drm, "svm: "f"\n", ##a)
  #define SVM_ERR(s,f,a...) NV_WARN((s)->drm, "svm: "f"\n", ##a)
  
+ struct nouveau_pfnmap_args {
+       struct nvif_ioctl_v0 i;
+       struct nvif_ioctl_mthd_v0 m;
+       struct nvif_vmm_pfnmap_v0 p;
+ };
  struct nouveau_ivmm {
        struct nouveau_svmm *svmm;
        u64 inst;
@@@ -187,7 -193,8 +193,8 @@@ nouveau_svmm_bind(struct drm_device *de
                addr = max(addr, vma->vm_start);
                next = min(vma->vm_end, end);
                /* This is a best effort so we ignore errors */
-               nouveau_dmem_migrate_vma(cli->drm, vma, addr, next);
+               nouveau_dmem_migrate_vma(cli->drm, cli->svm.svmm, vma, addr,
+                                        next);
                addr = next;
        }
  
@@@ -369,6 -376,19 +376,6 @@@ out_free
        return ret;
  }
  
 -static const u64
 -nouveau_svm_pfn_flags[HMM_PFN_FLAG_MAX] = {
 -      [HMM_PFN_VALID         ] = NVIF_VMM_PFNMAP_V0_V,
 -      [HMM_PFN_WRITE         ] = NVIF_VMM_PFNMAP_V0_W,
 -};
 -
 -static const u64
 -nouveau_svm_pfn_values[HMM_PFN_VALUE_MAX] = {
 -      [HMM_PFN_ERROR  ] = ~NVIF_VMM_PFNMAP_V0_V,
 -      [HMM_PFN_NONE   ] =  NVIF_VMM_PFNMAP_V0_NONE,
 -      [HMM_PFN_SPECIAL] = ~NVIF_VMM_PFNMAP_V0_V,
 -};
 -
  /* Issue fault replay for GPU to retry accesses that faulted previously. */
  static void
  nouveau_svm_fault_replay(struct nouveau_svm *svm)
@@@ -506,45 -526,9 +513,45 @@@ static const struct mmu_interval_notifi
        .invalidate = nouveau_svm_range_invalidate,
  };
  
 +static void nouveau_hmm_convert_pfn(struct nouveau_drm *drm,
 +                                  struct hmm_range *range, u64 *ioctl_addr)
 +{
 +      unsigned long i, npages;
 +
 +      /*
 +       * The ioctl_addr prepared here is passed through nvif_object_ioctl()
 +       * to an eventual DMA map in something like gp100_vmm_pgt_pfn()
 +       *
 +       * This is all just encoding the internal hmm representation into a
 +       * different nouveau internal representation.
 +       */
 +      npages = (range->end - range->start) >> PAGE_SHIFT;
 +      for (i = 0; i < npages; ++i) {
 +              struct page *page;
 +
 +              if (!(range->hmm_pfns[i] & HMM_PFN_VALID)) {
 +                      ioctl_addr[i] = 0;
 +                      continue;
 +              }
 +
 +              page = hmm_pfn_to_page(range->hmm_pfns[i]);
 +              if (is_device_private_page(page))
 +                      ioctl_addr[i] = nouveau_dmem_page_addr(page) |
 +                                      NVIF_VMM_PFNMAP_V0_V |
 +                                      NVIF_VMM_PFNMAP_V0_VRAM;
 +              else
 +                      ioctl_addr[i] = page_to_phys(page) |
 +                                      NVIF_VMM_PFNMAP_V0_V |
 +                                      NVIF_VMM_PFNMAP_V0_HOST;
 +              if (range->hmm_pfns[i] & HMM_PFN_WRITE)
 +                      ioctl_addr[i] |= NVIF_VMM_PFNMAP_V0_W;
 +      }
 +}
 +
  static int nouveau_range_fault(struct nouveau_svmm *svmm,
                               struct nouveau_drm *drm, void *data, u32 size,
 -                             u64 *pfns, struct svm_notifier *notifier)
 +                             unsigned long hmm_pfns[], u64 *ioctl_addr,
 +                             struct svm_notifier *notifier)
  {
        unsigned long timeout =
                jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
                .notifier = &notifier->notifier,
                .start = notifier->notifier.interval_tree.start,
                .end = notifier->notifier.interval_tree.last + 1,
 -              .pfns = pfns,
 -              .flags = nouveau_svm_pfn_flags,
 -              .values = nouveau_svm_pfn_values,
 -              .pfn_shift = NVIF_VMM_PFNMAP_V0_ADDR_SHIFT,
 +              .pfn_flags_mask = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_WRITE,
 +              .hmm_pfns = hmm_pfns,
        };
        struct mm_struct *mm = notifier->notifier.mm;
 -      long ret;
 +      int ret;
  
        while (true) {
                if (time_after(jiffies, timeout))
                        return -EBUSY;
  
                range.notifier_seq = mmu_interval_read_begin(range.notifier);
 -              range.default_flags = 0;
 -              range.pfn_flags_mask = -1UL;
                down_read(&mm->mmap_sem);
                ret = hmm_range_fault(&range);
                up_read(&mm->mmap_sem);
 -              if (ret <= 0) {
 -                      if (ret == 0 || ret == -EBUSY)
 +              if (ret) {
 +                      /*
 +                       * FIXME: the input PFN_REQ flags are destroyed on
 +                       * -EBUSY, we need to regenerate them, also for the
 +                       * other continue below
 +                       */
 +                      if (ret == -EBUSY)
                                continue;
                        return ret;
                }
                break;
        }
  
 -      nouveau_dmem_convert_pfn(drm, &range);
 +      nouveau_hmm_convert_pfn(drm, &range, ioctl_addr);
  
        svmm->vmm->vmm.object.client->super = true;
        ret = nvif_object_ioctl(&svmm->vmm->vmm.object, data, size, NULL);
@@@ -614,7 -597,6 +621,7 @@@ nouveau_svm_fault(struct nvif_notify *n
                } i;
                u64 phys[16];
        } args;
 +      unsigned long hmm_pfns[ARRAY_SIZE(args.phys)];
        struct vm_area_struct *vma;
        u64 inst, start, limit;
        int fi, fn, pi, fill;
                         * access flags.
                         *XXX: atomic?
                         */
 -                      if (buffer->fault[fn]->access != 0 /* READ. */ &&
 -                          buffer->fault[fn]->access != 3 /* PREFETCH. */) {
 -                              args.phys[pi++] = NVIF_VMM_PFNMAP_V0_V |
 -                                                NVIF_VMM_PFNMAP_V0_W;
 -                      } else {
 -                              args.phys[pi++] = NVIF_VMM_PFNMAP_V0_V;
 +                      switch (buffer->fault[fn]->access) {
 +                      case 0: /* READ. */
 +                              hmm_pfns[pi++] = HMM_PFN_REQ_FAULT;
 +                              break;
 +                      case 3: /* PREFETCH. */
 +                              hmm_pfns[pi++] = 0;
 +                              break;
 +                      default:
 +                              hmm_pfns[pi++] = HMM_PFN_REQ_FAULT |
 +                                               HMM_PFN_REQ_WRITE;
 +                              break;
                        }
                        args.i.p.size = pi << PAGE_SHIFT;
  
                        fill = (buffer->fault[fn    ]->addr -
                                buffer->fault[fn - 1]->addr) >> PAGE_SHIFT;
                        while (--fill)
 -                              args.phys[pi++] = NVIF_VMM_PFNMAP_V0_NONE;
 +                              hmm_pfns[pi++] = 0;
                }
  
                SVMM_DBG(svmm, "wndw %016llx-%016llx covering %d fault(s)",
                        ret = nouveau_range_fault(
                                svmm, svm->drm, &args,
                                sizeof(args.i) + pi * sizeof(args.phys[0]),
 -                              args.phys, &notifier);
 +                              hmm_pfns, args.phys, &notifier);
                        mmu_interval_notifier_remove(&notifier.notifier);
                }
                mmput(mm);
        return NVIF_NOTIFY_KEEP;
  }
  
+ static struct nouveau_pfnmap_args *
+ nouveau_pfns_to_args(void *pfns)
+ {
+       return container_of(pfns, struct nouveau_pfnmap_args, p.phys);
+ }
+ u64 *
+ nouveau_pfns_alloc(unsigned long npages)
+ {
+       struct nouveau_pfnmap_args *args;
+       args = kzalloc(struct_size(args, p.phys, npages), GFP_KERNEL);
+       if (!args)
+               return NULL;
+       args->i.type = NVIF_IOCTL_V0_MTHD;
+       args->m.method = NVIF_VMM_V0_PFNMAP;
+       args->p.page = PAGE_SHIFT;
+       return args->p.phys;
+ }
+ void
+ nouveau_pfns_free(u64 *pfns)
+ {
+       struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
+       kfree(args);
+ }
+ void
+ nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm,
+                unsigned long addr, u64 *pfns, unsigned long npages)
+ {
+       struct nouveau_pfnmap_args *args = nouveau_pfns_to_args(pfns);
+       int ret;
+       args->p.addr = addr;
+       args->p.size = npages << PAGE_SHIFT;
+       mutex_lock(&svmm->mutex);
+       svmm->vmm->vmm.object.client->super = true;
+       ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, sizeof(*args) +
+                               npages * sizeof(args->p.phys[0]), NULL);
+       svmm->vmm->vmm.object.client->super = false;
+       mutex_unlock(&svmm->mutex);
+ }
  static void
  nouveau_svm_fault_buffer_fini(struct nouveau_svm *svm, int id)
  {
index 91f398d51cfadf4e69fd60125147d2d35eb905d1,1082cd5d2fd47c20aeff3ecf10d079ff4c3c385b..9d45d5a4278f462db9b0b21a623c8c6bfa478a96
@@@ -221,7 -221,7 +221,7 @@@ static int qxl_add_mode(struct drm_conn
                        bool preferred)
  {
        struct drm_device *dev = connector->dev;
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_display_mode *mode = NULL;
        int rc;
  
  static int qxl_add_monitors_config_modes(struct drm_connector *connector)
  {
        struct drm_device *dev = connector->dev;
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct qxl_output *output = drm_connector_to_qxl_output(connector);
        int h = output->index;
        struct qxl_head *head;
@@@ -310,7 -310,7 +310,7 @@@ static void qxl_crtc_update_monitors_co
                                            const char *reason)
  {
        struct drm_device *dev = crtc->dev;
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
        struct qxl_head head;
        int oldcount, i = qcrtc->index;
@@@ -400,7 -400,7 +400,7 @@@ static int qxl_framebuffer_surface_dirt
                                         unsigned int num_clips)
  {
        /* TODO: vmwgfx where this was cribbed from had locking. Why? */
-       struct qxl_device *qdev = fb->dev->dev_private;
+       struct qxl_device *qdev = to_qxl(fb->dev);
        struct drm_clip_rect norect;
        struct qxl_bo *qobj;
        bool is_primary;
@@@ -462,7 -462,7 +462,7 @@@ static const struct drm_crtc_helper_fun
  static int qxl_primary_atomic_check(struct drm_plane *plane,
                                    struct drm_plane_state *state)
  {
-       struct qxl_device *qdev = plane->dev->dev_private;
+       struct qxl_device *qdev = to_qxl(plane->dev);
        struct qxl_bo *bo;
  
        if (!state->crtc || !state->fb)
  static int qxl_primary_apply_cursor(struct drm_plane *plane)
  {
        struct drm_device *dev = plane->dev;
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_framebuffer *fb = plane->state->fb;
        struct qxl_crtc *qcrtc = to_qxl_crtc(plane->state->crtc);
        struct qxl_cursor_cmd *cmd;
        cmd->u.set.visible = 1;
        qxl_release_unmap(qdev, release, &cmd->release_info);
  
 -      qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
        qxl_release_fence_buffer_objects(release);
 +      qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
  
        return ret;
  
@@@ -523,7 -523,7 +523,7 @@@ out_free_release
  static void qxl_primary_atomic_update(struct drm_plane *plane,
                                      struct drm_plane_state *old_state)
  {
-       struct qxl_device *qdev = plane->dev->dev_private;
+       struct qxl_device *qdev = to_qxl(plane->dev);
        struct qxl_bo *bo = gem_to_qxl_bo(plane->state->fb->obj[0]);
        struct qxl_bo *primary;
        struct drm_clip_rect norect = {
  static void qxl_primary_atomic_disable(struct drm_plane *plane,
                                       struct drm_plane_state *old_state)
  {
-       struct qxl_device *qdev = plane->dev->dev_private;
+       struct qxl_device *qdev = to_qxl(plane->dev);
  
        if (old_state->fb) {
                struct qxl_bo *bo = gem_to_qxl_bo(old_state->fb->obj[0]);
@@@ -570,7 -570,7 +570,7 @@@ static void qxl_cursor_atomic_update(st
                                     struct drm_plane_state *old_state)
  {
        struct drm_device *dev = plane->dev;
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_framebuffer *fb = plane->state->fb;
        struct qxl_crtc *qcrtc = to_qxl_crtc(plane->state->crtc);
        struct qxl_release *release;
        cmd->u.position.y = plane->state->crtc_y + fb->hot_y;
  
        qxl_release_unmap(qdev, release, &cmd->release_info);
 -      qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
        qxl_release_fence_buffer_objects(release);
 +      qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
  
        if (old_cursor_bo != NULL)
                qxl_bo_unpin(old_cursor_bo);
@@@ -679,7 -679,7 +679,7 @@@ out_free_release
  static void qxl_cursor_atomic_disable(struct drm_plane *plane,
                                      struct drm_plane_state *old_state)
  {
-       struct qxl_device *qdev = plane->dev->dev_private;
+       struct qxl_device *qdev = to_qxl(plane->dev);
        struct qxl_release *release;
        struct qxl_cursor_cmd *cmd;
        int ret;
        cmd->type = QXL_CURSOR_HIDE;
        qxl_release_unmap(qdev, release, &cmd->release_info);
  
 -      qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
        qxl_release_fence_buffer_objects(release);
 +      qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
  }
  
  static void qxl_update_dumb_head(struct qxl_device *qdev,
@@@ -762,7 -762,7 +762,7 @@@ static void qxl_calc_dumb_shadow(struc
  static int qxl_plane_prepare_fb(struct drm_plane *plane,
                                struct drm_plane_state *new_state)
  {
-       struct qxl_device *qdev = plane->dev->dev_private;
+       struct qxl_device *qdev = to_qxl(plane->dev);
        struct drm_gem_object *obj;
        struct qxl_bo *user_bo;
        struct qxl_surface surf;
@@@ -923,7 -923,7 +923,7 @@@ static int qdev_crtc_init(struct drm_de
  {
        struct qxl_crtc *qxl_crtc;
        struct drm_plane *primary, *cursor;
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        int r;
  
        qxl_crtc = kzalloc(sizeof(struct qxl_crtc), GFP_KERNEL);
@@@ -965,7 -965,7 +965,7 @@@ free_mem
  static int qxl_conn_get_modes(struct drm_connector *connector)
  {
        struct drm_device *dev = connector->dev;
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct qxl_output *output = drm_connector_to_qxl_output(connector);
        unsigned int pwidth = 1024;
        unsigned int pheight = 768;
@@@ -991,7 -991,7 +991,7 @@@ static enum drm_mode_status qxl_conn_mo
                               struct drm_display_mode *mode)
  {
        struct drm_device *ddev = connector->dev;
-       struct qxl_device *qdev = ddev->dev_private;
+       struct qxl_device *qdev = to_qxl(ddev);
  
        if (qxl_check_mode(qdev, mode->hdisplay, mode->vdisplay) != 0)
                return MODE_BAD;
@@@ -1021,7 -1021,7 +1021,7 @@@ static enum drm_connector_status qxl_co
        struct qxl_output *output =
                drm_connector_to_qxl_output(connector);
        struct drm_device *ddev = connector->dev;
-       struct qxl_device *qdev = ddev->dev_private;
+       struct qxl_device *qdev = to_qxl(ddev);
        bool connected = false;
  
        /* The first monitor is always connected */
@@@ -1071,7 -1071,7 +1071,7 @@@ static int qxl_mode_create_hotplug_mode
  
  static int qdev_output_init(struct drm_device *dev, int num_output)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct qxl_output *qxl_output;
        struct drm_connector *connector;
        struct drm_encoder *encoder;
index 72f3f1bbb40c1de0cf3f6a77047530fa2e47ef85,d9a583966949dfa5560438dd86f8f90cb61f27d5..13bd1d11c7036c85c56877475c1918cfe63c726a
@@@ -36,7 -36,7 +36,7 @@@
  static int qxl_alloc_ioctl(struct drm_device *dev, void *data,
                           struct drm_file *file_priv)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_alloc *qxl_alloc = data;
        int ret;
        struct qxl_bo *qobj;
@@@ -64,7 -64,7 +64,7 @@@
  static int qxl_map_ioctl(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_map *qxl_map = data;
  
        return qxl_mode_dumb_mmap(file_priv, &qdev->ddev, qxl_map->handle,
@@@ -261,8 -261,11 +261,8 @@@ static int qxl_process_single_command(s
                        apply_surf_reloc(qdev, &reloc_info[i]);
        }
  
 +      qxl_release_fence_buffer_objects(release);
        ret = qxl_push_command_ring_release(qdev, release, cmd->type, true);
 -      if (ret)
 -              qxl_release_backoff_reserve_list(release);
 -      else
 -              qxl_release_fence_buffer_objects(release);
  
  out_free_bos:
  out_free_release:
@@@ -276,7 -279,7 +276,7 @@@ out_free_reloc
  static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_execbuffer *execbuffer = data;
        struct drm_qxl_command user_cmd;
        int cmd_num;
  static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
                                 struct drm_file *file)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_update_area *update_area = data;
        struct qxl_rect area = {.left = update_area->left,
                                .top = update_area->top,
@@@ -351,7 -354,7 +351,7 @@@ out
  static int qxl_getparam_ioctl(struct drm_device *dev, void *data,
                       struct drm_file *file_priv)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_getparam *param = data;
  
        switch (param->param) {
  static int qxl_clientcap_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file_priv)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_clientcap *param = data;
        int byte, idx;
  
  static int qxl_alloc_surf_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file)
  {
-       struct qxl_device *qdev = dev->dev_private;
+       struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_alloc_surf *param = data;
        struct qxl_bo *qobj;
        int handle;
index 372962358a18190d321ca685dd59e4dd8efd5246,95006cbf42c313b8295c596038fa6fc96bd57075..c5d1dc9618a409f487bb3156c7818bd6e91aa061
@@@ -158,7 -158,7 +158,7 @@@ int radeon_driver_load_kms(struct drm_d
        }
  
        if (radeon_is_px(dev)) {
 -              dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NEVER_SKIP);
 +              dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
                pm_runtime_use_autosuspend(dev->dev);
                pm_runtime_set_autosuspend_delay(dev->dev, 5000);
                pm_runtime_set_active(dev->dev);
@@@ -828,7 -828,7 +828,7 @@@ int radeon_enable_vblank_kms(struct drm
        unsigned long irqflags;
        int r;
  
-       if (pipe < 0 || pipe >= rdev->num_crtc) {
+       if (pipe >= rdev->num_crtc) {
                DRM_ERROR("Invalid crtc %d\n", pipe);
                return -EINVAL;
        }
@@@ -854,7 -854,7 +854,7 @@@ void radeon_disable_vblank_kms(struct d
        struct radeon_device *rdev = dev->dev_private;
        unsigned long irqflags;
  
-       if (pipe < 0 || pipe >= rdev->num_crtc) {
+       if (pipe >= rdev->num_crtc) {
                DRM_ERROR("Invalid crtc %d\n", pipe);
                return;
        }
index 3eb89f1eb0e1ad44bfde8cb12359111ef5ad68be,f6c67dd87a054d0deafc1ea3a2a57692d2df748e..aa67cb037e9d10a417e932ea9abc7fca68fdb30f
@@@ -24,6 -24,7 +24,7 @@@
  #include <drm/drm_panel.h>
  #include <drm/drm_print.h>
  #include <drm/drm_probe_helper.h>
+ #include <drm/drm_simple_kms_helper.h>
  
  #include "sun4i_crtc.h"
  #include "sun4i_tcon.h"
@@@ -717,7 -718,7 +718,7 @@@ static void sun6i_dsi_encoder_enable(st
        struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
        struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
        struct mipi_dsi_device *device = dsi->device;
 -      union phy_configure_opts opts = { };
 +      union phy_configure_opts opts = { };
        struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
        u16 delay;
        int err;
@@@ -846,10 -847,6 +847,6 @@@ static const struct drm_encoder_helper_
        .enable         = sun6i_dsi_encoder_enable,
  };
  
- static const struct drm_encoder_funcs sun6i_dsi_enc_funcs = {
-       .destroy        = drm_encoder_cleanup,
- };
  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,
                                       const struct mipi_dsi_msg *msg)
  {
@@@ -1062,11 -1059,8 +1059,8 @@@ static int sun6i_dsi_bind(struct devic
  
        drm_encoder_helper_add(&dsi->encoder,
                               &sun6i_dsi_enc_helper_funcs);
-       ret = drm_encoder_init(drm,
-                              &dsi->encoder,
-                              &sun6i_dsi_enc_funcs,
-                              DRM_MODE_ENCODER_DSI,
-                              NULL);
+       ret = drm_simple_encoder_init(drm, &dsi->encoder,
+                                     DRM_MODE_ENCODER_DSI);
        if (ret) {
                dev_err(dsi->dev, "Couldn't initialise the DSI encoder\n");
                return ret;
index 583cd6e0ae27faa454f32243de79b7a5d703ac8f,d4f51b5c7ee55c2092dd96106e43cbf629ea7e1a..211906347f3f98f73e2b0a2e5a573a355de3150a
@@@ -839,11 -839,11 +839,11 @@@ static struct drm_info_list tegra_debug
        { "iova", tegra_debugfs_iova, 0 },
  };
  
- static int tegra_debugfs_init(struct drm_minor *minor)
+ static void tegra_debugfs_init(struct drm_minor *minor)
  {
-       return drm_debugfs_create_files(tegra_debugfs_list,
-                                       ARRAY_SIZE(tegra_debugfs_list),
-                                       minor->debugfs_root, minor);
+       drm_debugfs_create_files(tegra_debugfs_list,
+                                ARRAY_SIZE(tegra_debugfs_list),
+                                minor->debugfs_root, minor);
  }
  #endif
  
@@@ -1039,7 -1039,6 +1039,7 @@@ void tegra_drm_free(struct tegra_drm *t
  
  static bool host1x_drm_wants_iommu(struct host1x_device *dev)
  {
 +      struct host1x *host1x = dev_get_drvdata(dev->dev.parent);
        struct iommu_domain *domain;
  
        /*
         * sufficient and whether or not the host1x is attached to an IOMMU
         * doesn't matter.
         */
 -      if (!domain && dma_get_mask(dev->dev.parent) <= DMA_BIT_MASK(32))
 +      if (!domain && host1x_get_dma_mask(host1x) <= DMA_BIT_MASK(32))
                return true;
  
        return domain != NULL;
index 3221a707e07366c68c03e2945a72b7ddd5298c20,2396262c09e4c46e8ad79d52f463f1a9cb129b8e..89a226912de85f425404ec90d713e839fbd575e5
@@@ -24,7 -24,7 +24,7 @@@
  static void tidss_crtc_finish_page_flip(struct tidss_crtc *tcrtc)
  {
        struct drm_device *ddev = tcrtc->crtc.dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        struct drm_pending_vblank_event *event;
        unsigned long flags;
        bool busy;
@@@ -88,7 -88,7 +88,7 @@@ static int tidss_crtc_atomic_check(stru
                                   struct drm_crtc_state *state)
  {
        struct drm_device *ddev = crtc->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        struct dispc_device *dispc = tidss->dispc;
        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
        u32 hw_videoport = tcrtc->hw_videoport;
@@@ -165,7 -165,7 +165,7 @@@ static void tidss_crtc_atomic_flush(str
  {
        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
        struct drm_device *ddev = crtc->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        unsigned long flags;
  
        dev_dbg(ddev->dev,
@@@ -216,7 -216,7 +216,7 @@@ static void tidss_crtc_atomic_enable(st
  {
        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
        struct drm_device *ddev = crtc->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
        unsigned long flags;
        int r;
@@@ -259,7 -259,7 +259,7 @@@ static void tidss_crtc_atomic_disable(s
  {
        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
        struct drm_device *ddev = crtc->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        unsigned long flags;
  
        dev_dbg(ddev->dev, "%s, event %p\n", __func__, crtc->state->event);
@@@ -295,7 -295,7 +295,7 @@@ enum drm_mode_status tidss_crtc_mode_va
  {
        struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
        struct drm_device *ddev = crtc->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
  
        return dispc_vp_mode_valid(tidss->dispc, tcrtc->hw_videoport, mode);
  }
@@@ -314,7 -314,7 +314,7 @@@ static const struct drm_crtc_helper_fun
  static int tidss_crtc_enable_vblank(struct drm_crtc *crtc)
  {
        struct drm_device *ddev = crtc->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
  
        dev_dbg(ddev->dev, "%s\n", __func__);
  
  static void tidss_crtc_disable_vblank(struct drm_crtc *crtc)
  {
        struct drm_device *ddev = crtc->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
  
        dev_dbg(ddev->dev, "%s\n", __func__);
  
@@@ -379,17 -379,9 +379,17 @@@ static struct drm_crtc_state *tidss_crt
        return &state->base;
  }
  
 +static void tidss_crtc_destroy(struct drm_crtc *crtc)
 +{
 +      struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
 +
 +      drm_crtc_cleanup(crtc);
 +      kfree(tcrtc);
 +}
 +
  static const struct drm_crtc_funcs tidss_crtc_funcs = {
        .reset = tidss_crtc_reset,
 -      .destroy = drm_crtc_cleanup,
 +      .destroy = tidss_crtc_destroy,
        .set_config = drm_atomic_helper_set_config,
        .page_flip = drm_atomic_helper_page_flip,
        .atomic_duplicate_state = tidss_crtc_duplicate_state,
@@@ -408,7 -400,7 +408,7 @@@ struct tidss_crtc *tidss_crtc_create(st
        bool has_ctm = tidss->feat->vp_feat.color.has_ctm;
        int ret;
  
 -      tcrtc = devm_kzalloc(tidss->dev, sizeof(*tcrtc), GFP_KERNEL);
 +      tcrtc = kzalloc(sizeof(*tcrtc), GFP_KERNEL);
        if (!tcrtc)
                return ERR_PTR(-ENOMEM);
  
  
        ret = drm_crtc_init_with_planes(&tidss->ddev, crtc, primary,
                                        NULL, &tidss_crtc_funcs, NULL);
 -      if (ret < 0)
 +      if (ret < 0) {
 +              kfree(tcrtc);
                return ERR_PTR(ret);
 +      }
  
        drm_crtc_helper_add(crtc, &tidss_crtc_helper_funcs);
  
index 798488948fc539716bfe53a5316583b1360ee5ee,23bb3e59504b62773905cdcbb299f1427a4e085e..0a563eabcbb920cc15bbbb836816318ed80ed970
@@@ -22,7 -22,7 +22,7 @@@ static int tidss_plane_atomic_check(str
                                    struct drm_plane_state *state)
  {
        struct drm_device *ddev = plane->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        struct tidss_plane *tplane = to_tidss_plane(plane);
        const struct drm_format_info *finfo;
        struct drm_crtc_state *crtc_state;
@@@ -101,7 -101,7 +101,7 @@@ static void tidss_plane_atomic_update(s
                                      struct drm_plane_state *old_state)
  {
        struct drm_device *ddev = plane->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        struct tidss_plane *tplane = to_tidss_plane(plane);
        struct drm_plane_state *state = plane->state;
        u32 hw_videoport;
@@@ -133,7 -133,7 +133,7 @@@ static void tidss_plane_atomic_disable(
                                       struct drm_plane_state *old_state)
  {
        struct drm_device *ddev = plane->dev;
-       struct tidss_device *tidss = ddev->dev_private;
+       struct tidss_device *tidss = to_tidss(ddev);
        struct tidss_plane *tplane = to_tidss_plane(plane);
  
        dev_dbg(ddev->dev, "%s\n", __func__);
        dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
  }
  
 +static void drm_plane_destroy(struct drm_plane *plane)
 +{
 +      struct tidss_plane *tplane = to_tidss_plane(plane);
 +
 +      drm_plane_cleanup(plane);
 +      kfree(tplane);
 +}
 +
  static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = {
        .atomic_check = tidss_plane_atomic_check,
        .atomic_update = tidss_plane_atomic_update,
@@@ -159,7 -151,7 +159,7 @@@ static const struct drm_plane_funcs tid
        .update_plane = drm_atomic_helper_update_plane,
        .disable_plane = drm_atomic_helper_disable_plane,
        .reset = drm_atomic_helper_plane_reset,
 -      .destroy = drm_plane_cleanup,
 +      .destroy = drm_plane_destroy,
        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  };
@@@ -183,7 -175,7 +183,7 @@@ struct tidss_plane *tidss_plane_create(
                           BIT(DRM_MODE_BLEND_COVERAGE));
        int ret;
  
 -      tplane = devm_kzalloc(tidss->dev, sizeof(*tplane), GFP_KERNEL);
 +      tplane = kzalloc(sizeof(*tplane), GFP_KERNEL);
        if (!tplane)
                return ERR_PTR(-ENOMEM);
  
                                       formats, num_formats,
                                       NULL, type, NULL);
        if (ret < 0)
 -              return ERR_PTR(ret);
 +              goto err;
  
        drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs);
  
                                                default_encoding,
                                                default_range);
        if (ret)
 -              return ERR_PTR(ret);
 +              goto err;
  
        ret = drm_plane_create_alpha_property(&tplane->plane);
        if (ret)
 -              return ERR_PTR(ret);
 +              goto err;
  
        ret = drm_plane_create_blend_mode_property(&tplane->plane, blend_modes);
        if (ret)
 -              return ERR_PTR(ret);
 +              goto err;
  
        return tplane;
 +
 +err:
 +      kfree(tplane);
 +      return ERR_PTR(ret);
  }
index 7879ff58236f1472afb38d55de3ec1782e41fd7b,49bebdee6d91e3fcd37ff80b18062e10c28908c3..9ff9f4ac0522ac66b6526175fd40bb75521d44da
@@@ -218,27 -218,18 +218,19 @@@ struct virtio_gpu_fpriv 
        struct mutex context_lock;
  };
  
- /* virtio_ioctl.c */
+ /* virtgpu_ioctl.c */
  #define DRM_VIRTIO_NUM_IOCTLS 10
  extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS];
 +void virtio_gpu_create_context(struct drm_device *dev, struct drm_file *file);
  
- /* virtio_kms.c */
+ /* virtgpu_kms.c */
  int virtio_gpu_init(struct drm_device *dev);
  void virtio_gpu_deinit(struct drm_device *dev);
  void virtio_gpu_release(struct drm_device *dev);
  int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file);
  void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file);
  
- /* virtio_gem.c */
- void virtio_gpu_gem_free_object(struct drm_gem_object *gem_obj);
- int virtio_gpu_gem_init(struct virtio_gpu_device *vgdev);
- void virtio_gpu_gem_fini(struct virtio_gpu_device *vgdev);
- int virtio_gpu_gem_create(struct drm_file *file,
-                         struct drm_device *dev,
-                         struct virtio_gpu_object_params *params,
-                         struct drm_gem_object **obj_p,
-                         uint32_t *handle_p);
+ /* virtgpu_gem.c */
  int virtio_gpu_gem_object_open(struct drm_gem_object *obj,
                               struct drm_file *file);
  void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
@@@ -264,7 -255,7 +256,7 @@@ void virtio_gpu_array_put_free_delayed(
                                       struct virtio_gpu_object_array *objs);
  void virtio_gpu_array_put_free_work(struct work_struct *work);
  
- /* virtio vg */
+ /* virtgpu_vq.c */
  int virtio_gpu_alloc_vbufs(struct virtio_gpu_device *vgdev);
  void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev);
  void virtio_gpu_cmd_create_resource(struct virtio_gpu_device *vgdev,
@@@ -288,10 -279,10 +280,10 @@@ void virtio_gpu_cmd_set_scanout(struct 
                                uint32_t scanout_id, uint32_t resource_id,
                                uint32_t width, uint32_t height,
                                uint32_t x, uint32_t y);
int virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
-                            struct virtio_gpu_object *obj,
-                            struct virtio_gpu_mem_entry *ents,
-                            unsigned int nents);
void virtio_gpu_object_attach(struct virtio_gpu_device *vgdev,
+                             struct virtio_gpu_object *obj,
+                             struct virtio_gpu_mem_entry *ents,
+                             unsigned int nents);
  int virtio_gpu_attach_status_page(struct virtio_gpu_device *vgdev);
  int virtio_gpu_detach_status_page(struct virtio_gpu_device *vgdev);
  void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,
@@@ -344,17 -335,17 +336,17 @@@ void virtio_gpu_dequeue_fence_func(stru
  
  void virtio_gpu_notify(struct virtio_gpu_device *vgdev);
  
- /* virtio_gpu_display.c */
+ /* virtgpu_display.c */
  void virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev);
  void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev);
  
- /* virtio_gpu_plane.c */
+ /* virtgpu_plane.c */
  uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc);
  struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
                                        enum drm_plane_type type,
                                        int index);
  
- /* virtio_gpu_fence.c */
+ /* virtgpu_fence.c */
  struct virtio_gpu_fence *virtio_gpu_fence_alloc(
        struct virtio_gpu_device *vgdev);
  void virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
  void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev,
                                    u64 last_seq);
  
- /* virtio_gpu_object */
+ /* virtgpu_object.c */
  void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo);
  struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
                                                size_t size);
@@@ -379,7 -370,7 +371,7 @@@ struct drm_gem_object *virtgpu_gem_prim
        struct drm_device *dev, struct dma_buf_attachment *attach,
        struct sg_table *sgt);
  
- /* virgl debugfs */
int virtio_gpu_debugfs_init(struct drm_minor *minor);
+ /* virtgpu_debugfs.c */
void virtio_gpu_debugfs_init(struct drm_minor *minor);
  
  #endif
index f0d5a897467752aedbc1ba0ee8dbae6380da3bd2,1025658be4df23c8491cc7e2a6f11c3d4e6adc8d..d6cb350ae52a99289fb73a800fdfbb6ef5c44766
  
  #include "virtgpu_drv.h"
  
- int virtio_gpu_gem_create(struct drm_file *file,
-                         struct drm_device *dev,
-                         struct virtio_gpu_object_params *params,
-                         struct drm_gem_object **obj_p,
-                         uint32_t *handle_p)
static int virtio_gpu_gem_create(struct drm_file *file,
+                                struct drm_device *dev,
+                                struct virtio_gpu_object_params *params,
+                                struct drm_gem_object **obj_p,
+                                uint32_t *handle_p)
  {
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct virtio_gpu_object *obj;
        int ret;
        u32 handle;
  
 +      if (vgdev->has_virgl_3d)
 +              virtio_gpu_create_context(dev, file);
 +
        ret = virtio_gpu_object_create(vgdev, params, &obj, NULL);
        if (ret < 0)
                return ret;
@@@ -117,7 -114,7 +117,7 @@@ int virtio_gpu_gem_object_open(struct d
        struct virtio_gpu_object_array *objs;
  
        if (!vgdev->has_virgl_3d)
-               return 0;
+               goto out_notify;
  
        objs = virtio_gpu_array_alloc(1);
        if (!objs)
  
        virtio_gpu_cmd_context_attach_resource(vgdev, vfpriv->ctx_id,
                                               objs);
+ out_notify:
        virtio_gpu_notify(vgdev);
        return 0;
  }
index 512daff920387e5103e37743f2f441641a762dd9,867c5e239d5536f5dfc9db65ed3f4337a6eeb070..5df722072ba0b95998719f841a4d00ca7ae5debc
  
  #include <linux/file.h>
  #include <linux/sync_file.h>
 +#include <linux/uaccess.h>
  
  #include <drm/drm_file.h>
  #include <drm/virtgpu_drm.h>
  
  #include "virtgpu_drv.h"
  
 -static void virtio_gpu_create_context(struct drm_device *dev,
 -                                    struct drm_file *file)
 +void virtio_gpu_create_context(struct drm_device *dev, struct drm_file *file)
  {
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
@@@ -47,7 -47,6 +47,6 @@@
        get_task_comm(dbgname, current);
        virtio_gpu_cmd_context_create(vgdev, vfpriv->ctx_id,
                                      strlen(dbgname), dbgname);
-       virtio_gpu_notify(vgdev);
        vfpriv->context_created = true;
  
  out_unlock:
diff --combined include/drm/drm_modes.h
index 320f8112a0f84e3bf3aebf248e374ce2be8d628d,730fc31de4fbfedbdfd8f0de7c5b65ab0ce690cf..303ee5fbbdd8347f4b3428eb0f77414958d389aa
@@@ -48,7 -48,7 +48,7 @@@ struct videomode
   * @MODE_HSYNC: hsync out of range
   * @MODE_VSYNC: vsync out of range
   * @MODE_H_ILLEGAL: mode has illegal horizontal timings
 - * @MODE_V_ILLEGAL: mode has illegal horizontal timings
 + * @MODE_V_ILLEGAL: mode has illegal vertical timings
   * @MODE_BAD_WIDTH: requires an unsupported linepitch
   * @MODE_NOMODE: no mode with a matching name
   * @MODE_NO_INTERLACE: interlaced mode not supported
@@@ -390,16 -390,6 +390,6 @@@ struct drm_display_mode 
         */
        int vrefresh;
  
-       /**
-        * @hsync:
-        *
-        * Horizontal refresh rate, for debug output in human readable form. Not
-        * used in a functional way.
-        *
-        * This value is in kHz.
-        */
-       int hsync;
        /**
         * @picture_aspect_ratio:
         *
@@@ -493,7 -483,6 +483,6 @@@ int of_get_drm_display_mode(struct devi
                            int index);
  
  void drm_mode_set_name(struct drm_display_mode *mode);
- int drm_mode_hsync(const struct drm_display_mode *mode);
  int drm_mode_vrefresh(const struct drm_display_mode *mode);
  void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
                            int *hdisplay, int *vdisplay);
diff --combined include/linux/dma-buf.h
index 57bcef6f988a2d237f8e986bc9cefd01c639340d,82e0a4a64601f9864f9746dd4bef5ebdb10f4b2e..ab0c156abee6e95e1f37b526467e2efd012c5b5a
@@@ -329,12 -329,21 +329,20 @@@ struct dma_buf 
  
  /**
   * struct dma_buf_attach_ops - importer operations for an attachment
 - * @move_notify: [optional] notification that the DMA-buf is moving
   *
   * Attachment operations implemented by the importer.
   */
  struct dma_buf_attach_ops {
+       /**
+        * @allow_peer2peer:
+        *
+        * If this is set to true the importer must be able to handle peer
+        * resources without struct pages.
+        */
+       bool allow_peer2peer;
        /**
 -       * @move_notify
 +       * @move_notify: [optional] notification that the DMA-buf is moving
         *
         * If this callback is provided the framework can avoid pinning the
         * backing store while mappings exists.
   * @node: list of dma_buf_attachment, protected by dma_resv lock of the dmabuf.
   * @sgt: cached mapping.
   * @dir: direction of cached mapping.
+  * @peer2peer: true if the importer can handle peer resources without pages.
   * @priv: exporter specific attachment data.
   * @importer_ops: importer operations for this attachment, if provided
   * dma_buf_map/unmap_attachment() must be called with the dma_resv lock held.
@@@ -381,6 -391,7 +390,7 @@@ struct dma_buf_attachment 
        struct list_head node;
        struct sg_table *sgt;
        enum dma_data_direction dir;
+       bool peer2peer;
        const struct dma_buf_attach_ops *importer_ops;
        void *importer_priv;
        void *priv;
diff --combined mm/slub.c
index 2c56cc9e4ff2407bd94100c43c0b14c262dba54a,7002af0f013f92d27652325a082945152fe06f13..336be3224092e1226256f7a9e48bbd715911e131
+++ b/mm/slub.c
@@@ -551,32 -551,15 +551,32 @@@ static void print_section(char *level, 
        metadata_access_disable();
  }
  
 +/*
 + * See comment in calculate_sizes().
 + */
 +static inline bool freeptr_outside_object(struct kmem_cache *s)
 +{
 +      return s->offset >= s->inuse;
 +}
 +
 +/*
 + * Return offset of the end of info block which is inuse + free pointer if
 + * not overlapping with object.
 + */
 +static inline unsigned int get_info_end(struct kmem_cache *s)
 +{
 +      if (freeptr_outside_object(s))
 +              return s->inuse + sizeof(void *);
 +      else
 +              return s->inuse;
 +}
 +
  static struct track *get_track(struct kmem_cache *s, void *object,
        enum track_item alloc)
  {
        struct track *p;
  
 -      if (s->offset)
 -              p = object + s->offset + sizeof(void *);
 -      else
 -              p = object + s->inuse;
 +      p = object + get_info_end(s);
  
        return p + alloc;
  }
@@@ -679,20 -662,6 +679,20 @@@ static void slab_fix(struct kmem_cache 
        va_end(args);
  }
  
 +static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
 +                             void *freelist, void *nextfree)
 +{
 +      if ((s->flags & SLAB_CONSISTENCY_CHECKS) &&
 +          !check_valid_pointer(s, page, nextfree)) {
 +              object_err(s, page, freelist, "Freechain corrupt");
 +              freelist = NULL;
 +              slab_fix(s, "Isolate corrupted freechain");
 +              return true;
 +      }
 +
 +      return false;
 +}
 +
  static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
  {
        unsigned int off;       /* Offset of last byte */
                print_section(KERN_ERR, "Redzone ", p + s->object_size,
                        s->inuse - s->object_size);
  
 -      if (s->offset)
 -              off = s->offset + sizeof(void *);
 -      else
 -              off = s->inuse;
 +      off = get_info_end(s);
  
        if (s->flags & SLAB_STORE_USER)
                off += 2 * sizeof(struct track);
@@@ -810,7 -782,7 +810,7 @@@ static int check_bytes_and_report(struc
   * object address
   *    Bytes of the object to be managed.
   *    If the freepointer may overlay the object then the free
 - *    pointer is the first word of the object.
 + *    pointer is at the middle of the object.
   *
   *    Poisoning uses 0x6b (POISON_FREE) and the last byte is
   *    0xa5 (POISON_END)
  
  static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
  {
 -      unsigned long off = s->inuse;   /* The end of info */
 -
 -      if (s->offset)
 -              /* Freepointer is placed after the object. */
 -              off += sizeof(void *);
 +      unsigned long off = get_info_end(s);    /* The end of info */
  
        if (s->flags & SLAB_STORE_USER)
                /* We also have user information there */
@@@ -931,7 -907,7 +931,7 @@@ static int check_object(struct kmem_cac
                check_pad_bytes(s, page, p);
        }
  
 -      if (!s->offset && val == SLUB_RED_ACTIVE)
 +      if (!freeptr_outside_object(s) && val == SLUB_RED_ACTIVE)
                /*
                 * Object and freepointer overlap. Cannot check
                 * freepointer while object is allocated.
@@@ -1424,11 -1400,6 +1424,11 @@@ static inline void inc_slabs_node(struc
  static inline void dec_slabs_node(struct kmem_cache *s, int node,
                                                        int objects) {}
  
 +static bool freelist_corrupted(struct kmem_cache *s, struct page *page,
 +                             void *freelist, void *nextfree)
 +{
 +      return false;
 +}
  #endif /* CONFIG_SLUB_DEBUG */
  
  /*
@@@ -2112,14 -2083,6 +2112,14 @@@ static void deactivate_slab(struct kmem
                void *prior;
                unsigned long counters;
  
 +              /*
 +               * If 'nextfree' is invalid, it is possible that the object at
 +               * 'freelist' is already corrupted.  So isolate all objects
 +               * starting at 'freelist'.
 +               */
 +              if (freelist_corrupted(s, page, freelist, nextfree))
 +                      break;
 +
                do {
                        prior = page->freelist;
                        counters = page->counters;
@@@ -3570,7 -3533,6 +3570,7 @@@ static int calculate_sizes(struct kmem_
  {
        slab_flags_t flags = s->flags;
        unsigned int size = s->object_size;
 +      unsigned int freepointer_area;
        unsigned int order;
  
        /*
         * the possible location of the free pointer.
         */
        size = ALIGN(size, sizeof(void *));
 +      /*
 +       * This is the area of the object where a freepointer can be
 +       * safely written. If redzoning adds more to the inuse size, we
 +       * can't use that portion for writing the freepointer, so
 +       * s->offset must be limited within this for the general case.
 +       */
 +      freepointer_area = size;
  
  #ifdef CONFIG_SLUB_DEBUG
        /*
                 *
                 * This is the case if we do RCU, have a constructor or
                 * destructor or are poisoning the objects.
 +               *
 +               * The assumption that s->offset >= s->inuse means free
 +               * pointer is outside of the object is used in the
 +               * freeptr_outside_object() function. If that is no
 +               * longer true, the function needs to be modified.
                 */
                s->offset = size;
                size += sizeof(void *);
 -      } else if (size > sizeof(void *)) {
 +      } else if (freepointer_area > sizeof(void *)) {
                /*
                 * Store freelist pointer near middle of object to keep
                 * it away from the edges of the object to avoid small
                 * sized over/underflows from neighboring allocations.
                 */
 -              s->offset = ALIGN(size / 2, sizeof(void *));
 +              s->offset = ALIGN(freepointer_area / 2, sizeof(void *));
        }
  
  #ifdef CONFIG_SLUB_DEBUG
@@@ -3766,14 -3716,12 +3766,14 @@@ error
  }
  
  static void list_slab_objects(struct kmem_cache *s, struct page *page,
 -                                                      const char *text)
 +                            const char *text, unsigned long *map)
  {
  #ifdef CONFIG_SLUB_DEBUG
        void *addr = page_address(page);
        void *p;
 -      unsigned long *map;
 +
 +      if (!map)
 +              return;
  
        slab_err(s, page, text, s->name);
        slab_lock(page);
                        print_tracking(s, p);
                }
        }
 -      put_map(map);
 -
        slab_unlock(page);
  #endif
  }
@@@ -3799,11 -3749,6 +3799,11 @@@ static void free_partial(struct kmem_ca
  {
        LIST_HEAD(discard);
        struct page *page, *h;
 +      unsigned long *map = NULL;
 +
 +#ifdef CONFIG_SLUB_DEBUG
 +      map = bitmap_alloc(oo_objects(s->max), GFP_KERNEL);
 +#endif
  
        BUG_ON(irqs_disabled());
        spin_lock_irq(&n->list_lock);
                        list_add(&page->slab_list, &discard);
                } else {
                        list_slab_objects(s, page,
 -                      "Objects remaining in %s on __kmem_cache_shutdown()");
 +                        "Objects remaining in %s on __kmem_cache_shutdown()",
 +                        map);
                }
        }
        spin_unlock_irq(&n->list_lock);
  
 +#ifdef CONFIG_SLUB_DEBUG
 +      bitmap_free(map);
 +#endif
 +
        list_for_each_entry_safe(page, h, &discard, slab_list)
                discard_slab(s, page);
  }
@@@ -4445,6 -4385,7 +4445,7 @@@ void *__kmalloc_track_caller(size_t siz
  
        return ret;
  }
+ EXPORT_SYMBOL(__kmalloc_track_caller);
  
  #ifdef CONFIG_NUMA
  void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
  
        return ret;
  }
+ EXPORT_SYMBOL(__kmalloc_node_track_caller);
  #endif
  
  #ifdef CONFIG_SYSFS
@@@ -5691,8 -5633,7 +5693,8 @@@ static void memcg_propagate_slab_attrs(
                 */
                if (buffer)
                        buf = buffer;
 -              else if (root_cache->max_attr_size < ARRAY_SIZE(mbuf))
 +              else if (root_cache->max_attr_size < ARRAY_SIZE(mbuf) &&
 +                       !IS_ENABLED(CONFIG_SLUB_STATS))
                        buf = mbuf;
                else {
                        buffer = (char *) get_zeroed_page(GFP_KERNEL);
@@@ -5726,6 -5667,19 +5728,6 @@@ static struct kobj_type slab_ktype = 
        .release = kmem_cache_release,
  };
  
 -static int uevent_filter(struct kset *kset, struct kobject *kobj)
 -{
 -      struct kobj_type *ktype = get_ktype(kobj);
 -
 -      if (ktype == &slab_ktype)
 -              return 1;
 -      return 0;
 -}
 -
 -static const struct kset_uevent_ops slab_uevent_ops = {
 -      .filter = uevent_filter,
 -};
 -
  static struct kset *slab_kset;
  
  static inline struct kset *cache_kset(struct kmem_cache *s)
@@@ -5793,6 -5747,7 +5795,6 @@@ static void sysfs_slab_remove_workfn(st
  #ifdef CONFIG_MEMCG
        kset_unregister(s->memcg_kset);
  #endif
 -      kobject_uevent(&s->kobj, KOBJ_REMOVE);
  out:
        kobject_put(&s->kobj);
  }
@@@ -5850,6 -5805,7 +5852,6 @@@ static int sysfs_slab_add(struct kmem_c
        }
  #endif
  
 -      kobject_uevent(&s->kobj, KOBJ_ADD);
        if (!unmergeable) {
                /* Setup first alias */
                sysfs_slab_alias(s, s->name);
@@@ -5930,7 -5886,7 +5932,7 @@@ static int __init slab_sysfs_init(void
  
        mutex_lock(&slab_mutex);
  
 -      slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj);
 +      slab_kset = kset_create_and_add("slab", NULL, kernel_kobj);
        if (!slab_kset) {
                mutex_unlock(&slab_mutex);
                pr_err("Cannot register slab subsystem.\n");
This page took 0.478723 seconds and 4 git commands to generate.