mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	drm pull for 5.14-rc1
core:
 - mark AGP ioctls as legacy
 - disable force probing for non-master clients
 - HDR metadata property helpers
 - HDMI infoframe signal colorimetry support
 - remove drm_device.pdev pointer
 - remove DRM_KMS_FB_HELPER config option
 - remove drm_pci_alloc/free
 - drm_err_*/drm_dbg_* helpers
 - use drm driver names for fbdev
 - leaked DMA handle fix
 - 16bpc fixed point format fourcc
 - add prefetching memcpy for WC
 - Documentation fixes
 
 aperture:
 - add aperture ownership helpers
 
 dp:
 - aux fixes
 - downstream 0 port handling
 - use extended base receiver capability DPCD
 - Rename DP_PSR_SELECTIVE_UPDATE to better mach eDP spec
 - mst: use khz as link rate during init
 - VCPI fixes for StarTech hub
 
 ttm:
 - provide tt_shrink file via debugfs
 - warn about freeing pinned BOs
 - fix swapping error handling
 - move page alignment into BO
 - cleanup ttm_agp_backend
 - add ttm_sys_manager
 - don't override vm_ops
 - ttm_bo_mmap removed
 - make ttm_resource base of all managers
 - remove VM_MIXEDMAP usage
 
 panel:
 - sysfs_emit support
 - simple: runtime PM support
 - simple: power up panel when reading EDID + caching
 
 bridge:
 - MHDP8546: HDCP support + DT bindings
 - MHDP8546: Register DP AUX channel with userspace
 - TI SN65DSI83 + SN65DSI84: add driver
 - Sil8620: Fix module dependencies
 - dw-hdmi: make CEC driver loading optional
 - Ti-sn65dsi86: refclk fixes, subdrivers, runtime pm
 - It66121: Add driver + DT bindings
 - Adv7511: Support I2S IEC958 encoding
 - Anx7625: fix power-on delay
 - Nwi-dsi: Modesetting fixes; Cleanups
 - lt6911: add missing MODULE_DEVICE_TABLE
 - cdns: fix PM reference leak
 
 hyperv:
 - add new DRM driver for HyperV graphics
 
 efifb:
 - non-PCI device handling fixes
 
 i915:
 - refactor IP/device versioning
 - XeLPD Display IP preperation work
 - ADL-P enablement patches
 - DG1 uAPI behind BROKEN
 - disable mmap ioctl for discerte GPUs
 - start enabling HuC loading for Gen12+
 - major GuC backend rework for new platforms
 - initial TTM support for Discrete GPUs
 - locking rework for TTM prep
 - use correct max source link rate for eDP
 - %p4cc format printing
 - GLK display fixes
 - VLV DSI panel power fixes
 - PSR2 disabled for RKL and ADL-S
 - ACPI _DSM invalid access fixed
 - DMC FW path abstraction
 - ADL-S PCI ID update
 - uAPI headers converted to kerneldoc
 - initial LMEM support for DG1
 - x86/gpu: add Jasperlake to gen11 early quirks
 
 amdgpu:
 - Aldebaran updates + initial SR-IOV
 - new GPU: Beige Goby and Yellow Carp support
 - more LTTPR display work
 - Vangogh updates
 - SDMA 5.x GCR fixes
 - PCIe ASPM support
 - Renoir TMZ enablement
 - initial multiple eDP panel support
 - use fdinfo to track devices/process info
 - pin/unpin TTM fixes
 - free resource on fence usage query
 - fix fence calculation
 - fix hotunplug/suspend issues
 - GC/MM register access macro cleanup for SR-IOV
 - W=1 fixes
 - ACPI ATCS/ATIF handling rework
 - 16bpc fixed point format support
 - Initial smartshift support
 - RV/PCO power tuning fixes
 - new INFO query for additional vbios info
 
 amdkfd:
 - SR-IOV aldebaran support
 - HMM SVM support
 
 radeon:
 - SMU regression fixes
 - Oland flickering fix
 
 vmwgfx:
 - enable console with fbdev emulation
 - fix cpu updates of coherent multisample surfaces
 - remove reservation semaphore
 - add initial SVGA3 support
 - support arm64
 
 msm:
 - devcoredump support for display errors
 - dpu/dsi: yaml bindings conversion
 - mdp5: alpha/blend_mode/zpos support
 - a6xx: cached coherent buffer support
 - gpu iova fault improvement
 - a660 support
 
 rockchip:
 - RK3036 win1 scaling support
 - RK3066/3188 missing register support
 - RK3036/3066/3126/3188 alpha support
 
 mediatek:
 - MT8167 HDMI support
 - MT8183 DPI dual edge support
 
 tegra:
 - fixed YUV support/scaling on Tegra186+
 
 ast:
 - use pcim_iomap
 - fix DP501 EDID
 
 bochs:
 - screen blanking support
 
 etnaviv:
 - export more GPU ID values to userspace
 - add HWDB entry for GPU on i.MX8MP
 - rework linear window calcs
 
 exynos:
 - pm runtime changes
 
 imx:
 - Annotate dma_fence critical section
 - fix PRG modifiers after drmm conversion
 - Add 8 pixel alignment fix for 1366x768
 - fix YUV advertising
 - add color properties
 
 ingenic:
 - IPU planes fix
 
 panfrost:
 - Mediatek MT8183 support + DT bindings
 - export AFBC_FEATURES register to userspace
 
 simpledrm:
 - %pr for printing resources
 
 nouveau:
 - pin/unpin TTM fixes
 
 qxl:
 - unpin shadow BO
 
 virtio:
 - create dumb BOs as guest blob
 
 vkms:
 - drmm_universal_plane_alloc
 - add XRGB plane composition
 - overlay support
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmDdQzkACgkQDHTzWXnE
 hr7bhQ//aSYnp1To3tvPtwQ2H88RTnEbUd+nCi3C03QdLAbHC9dYHVdWuNPw2doh
 aiJO2JyQoqXVo95Jc39qkmpvm1lLDNQuufBweCHxbbpl8wYIUjfkIYq+fnZbWPaA
 aRVSOLE/4DIcgJTimsgOssAOK9klk/WYT9EV7CNIBA/b0R6f9iTUoBxCALDvMeVx
 Pt3Rnfsg3+u8msqBkkpkvFLZRS8lkXx6eZ0LEhUfRsfMcKo5L80cOHgvIhrh9+fN
 yBFv+u7jM3fOxyUYEoBeVY8UqTLfbgM+vdiP9pmiGn66yCZVJWIxCe1Mijk6K143
 f4OxJy1jJAGzo/knLCuCb21qbzyImQzkold9V+h8KAvTXGeMPISjbpLbwGeo8rne
 lfTAisGnu8q3xvYAU9znx9DkFQULgUuWahEYY3jX0ApVCR76hiT6H7AR9EOMhvKY
 PD1n39Bf62p7zK5QQ+XUOiX3PGv8J6Hw/wykFy+AIg4YgT/oK+QJul820MjZiYyt
 7Kt09Ibj4JO+vubxqlbJVsW3xtdg/Oz3BRMIdHs+2l/s0pSwBZa+qTcXhPGZxB5B
 HiyHiUgLsK8MQ0aIw9IK8+nJH8M60t6A179BbmVWxhYpGLH2Wvq0Vxgsedt9trHn
 2RN3mHlpXHSaZJbIbPcvuOewBLKA6K94o2ZZ8xqZbDcCjjC60ts=
 =fFet
 -----END PGP SIGNATURE-----
Merge tag 'drm-next-2021-07-01' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
 "Highlights:
   - AMD enables two more GPUs, with resulting header files
   - i915 has started to move to TTM for discrete GPU and enable DG1
     discrete GPU support (not by default yet)
   - new HyperV drm driver
   - vmwgfx adds arm64 support
   - TTM refactoring ongoing
   - 16bpc display support for AMD hw
  Otherwise it's just the usual insane amounts of work all over the
  place in lots of drivers and the core, as mostly summarised below:
  Core:
   - mark AGP ioctls as legacy
   - disable force probing for non-master clients
   - HDR metadata property helpers
   - HDMI infoframe signal colorimetry support
   - remove drm_device.pdev pointer
   - remove DRM_KMS_FB_HELPER config option
   - remove drm_pci_alloc/free
   - drm_err_*/drm_dbg_* helpers
   - use drm driver names for fbdev
   - leaked DMA handle fix
   - 16bpc fixed point format fourcc
   - add prefetching memcpy for WC
   - Documentation fixes
  aperture:
   - add aperture ownership helpers
  dp:
   - aux fixes
   - downstream 0 port handling
   - use extended base receiver capability DPCD
   - Rename DP_PSR_SELECTIVE_UPDATE to better mach eDP spec
   - mst: use khz as link rate during init
   - VCPI fixes for StarTech hub
  ttm:
   - provide tt_shrink file via debugfs
   - warn about freeing pinned BOs
   - fix swapping error handling
   - move page alignment into BO
   - cleanup ttm_agp_backend
   - add ttm_sys_manager
   - don't override vm_ops
   - ttm_bo_mmap removed
   - make ttm_resource base of all managers
   - remove VM_MIXEDMAP usage
  panel:
   - sysfs_emit support
   - simple: runtime PM support
   - simple: power up panel when reading EDID + caching
  bridge:
   - MHDP8546: HDCP support + DT bindings
   - MHDP8546: Register DP AUX channel with userspace
   - TI SN65DSI83 + SN65DSI84: add driver
   - Sil8620: Fix module dependencies
   - dw-hdmi: make CEC driver loading optional
   - Ti-sn65dsi86: refclk fixes, subdrivers, runtime pm
   - It66121: Add driver + DT bindings
   - Adv7511: Support I2S IEC958 encoding
   - Anx7625: fix power-on delay
   - Nwi-dsi: Modesetting fixes; Cleanups
   - lt6911: add missing MODULE_DEVICE_TABLE
   - cdns: fix PM reference leak
  hyperv:
   - add new DRM driver for HyperV graphics
  efifb:
   - non-PCI device handling fixes
  i915:
   - refactor IP/device versioning
   - XeLPD Display IP preperation work
   - ADL-P enablement patches
   - DG1 uAPI behind BROKEN
   - disable mmap ioctl for discerte GPUs
   - start enabling HuC loading for Gen12+
   - major GuC backend rework for new platforms
   - initial TTM support for Discrete GPUs
   - locking rework for TTM prep
   - use correct max source link rate for eDP
   - %p4cc format printing
   - GLK display fixes
   - VLV DSI panel power fixes
   - PSR2 disabled for RKL and ADL-S
   - ACPI _DSM invalid access fixed
   - DMC FW path abstraction
   - ADL-S PCI ID update
   - uAPI headers converted to kerneldoc
   - initial LMEM support for DG1
   - x86/gpu: add Jasperlake to gen11 early quirks
  amdgpu:
   - Aldebaran updates + initial SR-IOV
   - new GPU: Beige Goby and Yellow Carp support
   - more LTTPR display work
   - Vangogh updates
   - SDMA 5.x GCR fixes
   - PCIe ASPM support
   - Renoir TMZ enablement
   - initial multiple eDP panel support
   - use fdinfo to track devices/process info
   - pin/unpin TTM fixes
   - free resource on fence usage query
   - fix fence calculation
   - fix hotunplug/suspend issues
   - GC/MM register access macro cleanup for SR-IOV
   - W=1 fixes
   - ACPI ATCS/ATIF handling rework
   - 16bpc fixed point format support
   - Initial smartshift support
   - RV/PCO power tuning fixes
   - new INFO query for additional vbios info
  amdkfd:
   - SR-IOV aldebaran support
   - HMM SVM support
  radeon:
   - SMU regression fixes
   - Oland flickering fix
  vmwgfx:
   - enable console with fbdev emulation
   - fix cpu updates of coherent multisample surfaces
   - remove reservation semaphore
   - add initial SVGA3 support
   - support arm64
  msm:
   - devcoredump support for display errors
   - dpu/dsi: yaml bindings conversion
   - mdp5: alpha/blend_mode/zpos support
   - a6xx: cached coherent buffer support
   - gpu iova fault improvement
   - a660 support
  rockchip:
   - RK3036 win1 scaling support
   - RK3066/3188 missing register support
   - RK3036/3066/3126/3188 alpha support
  mediatek:
   - MT8167 HDMI support
   - MT8183 DPI dual edge support
  tegra:
   - fixed YUV support/scaling on Tegra186+
  ast:
   - use pcim_iomap
   - fix DP501 EDID
  bochs:
   - screen blanking support
  etnaviv:
   - export more GPU ID values to userspace
   - add HWDB entry for GPU on i.MX8MP
   - rework linear window calcs
  exynos:
   - pm runtime changes
  imx:
   - Annotate dma_fence critical section
   - fix PRG modifiers after drmm conversion
   - Add 8 pixel alignment fix for 1366x768
   - fix YUV advertising
   - add color properties
  ingenic:
   - IPU planes fix
  panfrost:
   - Mediatek MT8183 support + DT bindings
   - export AFBC_FEATURES register to userspace
  simpledrm:
   - %pr for printing resources
  nouveau:
   - pin/unpin TTM fixes
  qxl:
   - unpin shadow BO
  virtio:
   - create dumb BOs as guest blob
  vkms:
   - drmm_universal_plane_alloc
   - add XRGB plane composition
   - overlay support"
* tag 'drm-next-2021-07-01' of git://anongit.freedesktop.org/drm/drm: (1570 commits)
  drm/i915: Reinstate the mmap ioctl for some platforms
  drm/i915/dsc: abstract helpers to get bigjoiner primary/secondary crtc
  Revert "drm/msm/mdp5: provide dynamic bandwidth management"
  drm/msm/mdp5: provide dynamic bandwidth management
  drm/msm/mdp5: add perf blocks for holding fudge factors
  drm/msm/mdp5: switch to standard zpos property
  drm/msm/mdp5: add support for alpha/blend_mode properties
  drm/msm/mdp5: use drm_plane_state for pixel blend mode
  drm/msm/mdp5: use drm_plane_state for storing alpha value
  drm/msm/mdp5: use drm atomic helpers to handle base drm plane state
  drm/msm/dsi: do not enable PHYs when called for the slave DSI interface
  drm/msm: Add debugfs to trigger shrinker
  drm/msm/dpu: Avoid ABBA deadlock between IRQ modules
  drm/msm: devcoredump iommu fault support
  iommu/arm-smmu-qcom: Add stall support
  drm/msm: Improve the a6xx page fault handler
  iommu/arm-smmu-qcom: Add an adreno-smmu-priv callback to get pagefault info
  iommu/arm-smmu: Add support for driver IOMMU fault handlers
  drm/msm: export hangcheck_period in debugfs
  drm/msm/a6xx: add support for Adreno 660 GPU
  ...
			
			
This commit is contained in:
		
						commit
						e058a84bfd
					
				| @ -11,7 +11,9 @@ maintainers: | |||||||
| 
 | 
 | ||||||
| properties: | properties: | ||||||
|   compatible: |   compatible: | ||||||
|     const: brcm,bcm2835-vec |     enum: | ||||||
|  |       - brcm,bcm2711-vec | ||||||
|  |       - brcm,bcm2835-vec | ||||||
| 
 | 
 | ||||||
|   reg: |   reg: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ properties: | |||||||
| 
 | 
 | ||||||
|   reg: |   reg: | ||||||
|     minItems: 1 |     minItems: 1 | ||||||
|     maxItems: 2 |     maxItems: 3 | ||||||
|     items: |     items: | ||||||
|       - description: |       - description: | ||||||
|           Register block of mhdptx apb registers up to PHY mapped area (AUX_CONFIG_P). |           Register block of mhdptx apb registers up to PHY mapped area (AUX_CONFIG_P). | ||||||
| @ -26,13 +26,16 @@ properties: | |||||||
|           included in the associated PHY. |           included in the associated PHY. | ||||||
|       - description: |       - description: | ||||||
|           Register block for DSS_EDP0_INTG_CFG_VP registers in case of TI J7 SoCs. |           Register block for DSS_EDP0_INTG_CFG_VP registers in case of TI J7 SoCs. | ||||||
|  |       - description: | ||||||
|  |           Register block of mhdptx sapb registers. | ||||||
| 
 | 
 | ||||||
|   reg-names: |   reg-names: | ||||||
|     minItems: 1 |     minItems: 1 | ||||||
|     maxItems: 2 |     maxItems: 3 | ||||||
|     items: |     items: | ||||||
|       - const: mhdptx |       - const: mhdptx | ||||||
|       - const: j721e-intg |       - const: j721e-intg | ||||||
|  |       - const: mhdptx-sapb | ||||||
| 
 | 
 | ||||||
|   clocks: |   clocks: | ||||||
|     maxItems: 1 |     maxItems: 1 | ||||||
| @ -99,14 +102,18 @@ allOf: | |||||||
|       properties: |       properties: | ||||||
|         reg: |         reg: | ||||||
|           minItems: 2 |           minItems: 2 | ||||||
|  |           maxItems: 3 | ||||||
|         reg-names: |         reg-names: | ||||||
|           minItems: 2 |           minItems: 2 | ||||||
|  |           maxItems: 3 | ||||||
|     else: |     else: | ||||||
|       properties: |       properties: | ||||||
|         reg: |         reg: | ||||||
|           maxItems: 1 |           minItems: 1 | ||||||
|  |           maxItems: 2 | ||||||
|         reg-names: |         reg-names: | ||||||
|           maxItems: 1 |           minItems: 1 | ||||||
|  |           maxItems: 2 | ||||||
| 
 | 
 | ||||||
| required: | required: | ||||||
|   - compatible |   - compatible | ||||||
|  | |||||||
| @ -0,0 +1,82 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/bridge/google,cros-ec-anx7688.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: ChromeOS EC ANX7688 HDMI to DP Converter through Type-C Port | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Nicolas Boichat <drinkcat@chromium.org> | ||||||
|  |   - Enric Balletbo i Serra <enric.balletbo@collabora.com> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   ChromeOS EC ANX7688 is a display bridge that converts HDMI 2.0 to | ||||||
|  |   DisplayPort 1.3 Ultra-HDi (4096x2160p60). It is an Analogix ANX7688 chip | ||||||
|  |   which is connected to and operated by the ChromeOS Embedded Controller | ||||||
|  |   (See google,cros-ec.yaml). It is accessed using I2C tunneling through | ||||||
|  |   the EC and therefore its node should be a child of an EC I2C tunnel node | ||||||
|  |   (See google,cros-ec-i2c-tunnel.yaml). | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     const: google,cros-ec-anx7688 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  |     description: I2C address of the device. | ||||||
|  | 
 | ||||||
|  |   ports: | ||||||
|  |     $ref: /schemas/graph.yaml#/properties/ports | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       port@0: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: Video port for HDMI input. | ||||||
|  | 
 | ||||||
|  |       port@1: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: USB Type-c connector. | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - port@0 | ||||||
|  |       - port@1 | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - ports | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     i2c_tunnel_b: i2c-tunnel1 { | ||||||
|  |         compatible = "google,cros-ec-i2c-tunnel"; | ||||||
|  |         google,remote-bus = <1>; | ||||||
|  |         #address-cells = <1>; | ||||||
|  |         #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         anx7688: anx7688@2c { | ||||||
|  |             compatible = "google,cros-ec-anx7688"; | ||||||
|  |             reg = <0x2c>; | ||||||
|  | 
 | ||||||
|  |             ports { | ||||||
|  |                 #address-cells = <1>; | ||||||
|  |                 #size-cells = <0>; | ||||||
|  |                 port@0 { | ||||||
|  |                     reg = <0>; | ||||||
|  |                     anx7688_in: endpoint { | ||||||
|  |                         remote-endpoint = <&hdmi0_out>; | ||||||
|  |                     }; | ||||||
|  |                 }; | ||||||
|  |                 port@1 { | ||||||
|  |                     reg = <1>; | ||||||
|  |                     anx7688_out: endpoint { | ||||||
|  |                         remote-endpoint = <&typec_connector>; | ||||||
|  |                     }; | ||||||
|  |                 }; | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
| @ -0,0 +1,124 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/bridge/ite,it66121.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: ITE it66121 HDMI bridge Device Tree Bindings | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Phong LE <ple@baylibre.com> | ||||||
|  |   - Neil Armstrong <narmstrong@baylibre.com> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   The IT66121 is a high-performance and low-power single channel HDMI | ||||||
|  |   transmitter, fully compliant with HDMI 1.3a, HDCP 1.2 and backward compatible | ||||||
|  |   to DVI 1.0 specifications. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     const: ite,it66121 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   reset-gpios: | ||||||
|  |     maxItems: 1 | ||||||
|  |     description: GPIO connected to active low reset | ||||||
|  | 
 | ||||||
|  |   vrf12-supply: | ||||||
|  |     description: Regulator for 1.2V analog core power. | ||||||
|  | 
 | ||||||
|  |   vcn33-supply: | ||||||
|  |     description: Regulator for 3.3V digital core power. | ||||||
|  | 
 | ||||||
|  |   vcn18-supply: | ||||||
|  |     description: Regulator for 1.8V IO core power. | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   ports: | ||||||
|  |     $ref: /schemas/graph.yaml#/properties/ports | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       port@0: | ||||||
|  |         $ref: /schemas/graph.yaml#/$defs/port-base | ||||||
|  |         unevaluatedProperties: false | ||||||
|  |         description: DPI input port. | ||||||
|  | 
 | ||||||
|  |         properties: | ||||||
|  |           endpoint: | ||||||
|  |             $ref: /schemas/graph.yaml#/$defs/endpoint-base | ||||||
|  |             unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  |             properties: | ||||||
|  |               bus-width: | ||||||
|  |                 description: | ||||||
|  |                   Endpoint bus width. | ||||||
|  |                 enum: | ||||||
|  |                   - 12  # 12 data lines connected and dual-edge mode | ||||||
|  |                   - 24  # 24 data lines connected and single-edge mode | ||||||
|  |                 default: 24 | ||||||
|  | 
 | ||||||
|  |       port@1: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: HDMI Connector port. | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - port@0 | ||||||
|  |       - port@1 | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reset-gpios | ||||||
|  |   - vrf12-supply | ||||||
|  |   - vcn33-supply | ||||||
|  |   - vcn18-supply | ||||||
|  |   - interrupts | ||||||
|  |   - ports | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|  |     #include <dt-bindings/gpio/gpio.h> | ||||||
|  |     i2c { | ||||||
|  |         #address-cells = <1>; | ||||||
|  |         #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         it66121hdmitx: hdmitx@4c { | ||||||
|  |             compatible = "ite,it66121"; | ||||||
|  |             pinctrl-names = "default"; | ||||||
|  |             pinctrl-0 = <&ite_pins_default>; | ||||||
|  |             vcn33-supply = <&mt6358_vcn33_wifi_reg>; | ||||||
|  |             vcn18-supply = <&mt6358_vcn18_reg>; | ||||||
|  |             vrf12-supply = <&mt6358_vrf12_reg>; | ||||||
|  |             reset-gpios = <&pio 160 GPIO_ACTIVE_LOW>; | ||||||
|  |             interrupt-parent = <&pio>; | ||||||
|  |             interrupts = <4 IRQ_TYPE_LEVEL_LOW>; | ||||||
|  |             reg = <0x4c>; | ||||||
|  | 
 | ||||||
|  |             ports { | ||||||
|  |                 #address-cells = <1>; | ||||||
|  |                 #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |                 port@0 { | ||||||
|  |                     reg = <0>; | ||||||
|  |                     it66121_in: endpoint { | ||||||
|  |                         bus-width = <12>; | ||||||
|  |                         remote-endpoint = <&display_out>; | ||||||
|  |                     }; | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 port@1 { | ||||||
|  |                     reg = <1>; | ||||||
|  |                     hdmi_conn_out: endpoint { | ||||||
|  |                         remote-endpoint = <&hdmi_conn_in>; | ||||||
|  |                     }; | ||||||
|  |                 }; | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
| @ -0,0 +1,159 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/bridge/ti,sn65dsi83.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: SN65DSI83 and SN65DSI84 DSI to LVDS bridge chip | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Marek Vasut <marex@denx.de> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   Texas Instruments SN65DSI83 1x Single-link MIPI DSI | ||||||
|  |   to 1x Single-link LVDS | ||||||
|  |   https://www.ti.com/lit/gpn/sn65dsi83 | ||||||
|  |   Texas Instruments SN65DSI84 1x Single-link MIPI DSI | ||||||
|  |   to 1x Dual-link or 2x Single-link LVDS | ||||||
|  |   https://www.ti.com/lit/gpn/sn65dsi84 | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - ti,sn65dsi83 | ||||||
|  |       - ti,sn65dsi84 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     enum: | ||||||
|  |       - 0x2c | ||||||
|  |       - 0x2d | ||||||
|  | 
 | ||||||
|  |   enable-gpios: | ||||||
|  |     maxItems: 1 | ||||||
|  |     description: GPIO specifier for bridge_en pin (active high). | ||||||
|  | 
 | ||||||
|  |   ports: | ||||||
|  |     $ref: /schemas/graph.yaml#/properties/ports | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       port@0: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: Video port for MIPI DSI Channel-A input | ||||||
|  | 
 | ||||||
|  |         properties: | ||||||
|  |           endpoint: | ||||||
|  |             $ref: /schemas/media/video-interfaces.yaml# | ||||||
|  |             unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  |             properties: | ||||||
|  |               data-lanes: | ||||||
|  |                 description: array of physical DSI data lane indexes. | ||||||
|  |                 minItems: 1 | ||||||
|  |                 maxItems: 4 | ||||||
|  |                 items: | ||||||
|  |                   - const: 1 | ||||||
|  |                   - const: 2 | ||||||
|  |                   - const: 3 | ||||||
|  |                   - const: 4 | ||||||
|  | 
 | ||||||
|  |       port@1: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: Video port for MIPI DSI Channel-B input | ||||||
|  | 
 | ||||||
|  |         properties: | ||||||
|  |           endpoint: | ||||||
|  |             $ref: /schemas/media/video-interfaces.yaml# | ||||||
|  |             unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  |             properties: | ||||||
|  |               data-lanes: | ||||||
|  |                 description: array of physical DSI data lane indexes. | ||||||
|  |                 minItems: 1 | ||||||
|  |                 maxItems: 4 | ||||||
|  |                 items: | ||||||
|  |                   - const: 1 | ||||||
|  |                   - const: 2 | ||||||
|  |                   - const: 3 | ||||||
|  |                   - const: 4 | ||||||
|  | 
 | ||||||
|  |       port@2: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: Video port for LVDS Channel-A output (panel or bridge). | ||||||
|  | 
 | ||||||
|  |       port@3: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: Video port for LVDS Channel-B output (panel or bridge). | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - port@0 | ||||||
|  |       - port@2 | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - enable-gpios | ||||||
|  |   - ports | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - if: | ||||||
|  |       properties: | ||||||
|  |         compatible: | ||||||
|  |           contains: | ||||||
|  |             const: ti,sn65dsi83 | ||||||
|  |     then: | ||||||
|  |       properties: | ||||||
|  |         ports: | ||||||
|  |           properties: | ||||||
|  |             port@1: false | ||||||
|  |             port@3: false | ||||||
|  | 
 | ||||||
|  |   - if: | ||||||
|  |       properties: | ||||||
|  |         compatible: | ||||||
|  |           contains: | ||||||
|  |             const: ti,sn65dsi84 | ||||||
|  |     then: | ||||||
|  |       properties: | ||||||
|  |         ports: | ||||||
|  |           properties: | ||||||
|  |             port@1: false | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/gpio/gpio.h> | ||||||
|  | 
 | ||||||
|  |     i2c { | ||||||
|  |         #address-cells = <1>; | ||||||
|  |         #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         bridge@2d { | ||||||
|  |             compatible = "ti,sn65dsi83"; | ||||||
|  |             reg = <0x2d>; | ||||||
|  | 
 | ||||||
|  |             enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; | ||||||
|  | 
 | ||||||
|  |             ports { | ||||||
|  |                 #address-cells = <1>; | ||||||
|  |                 #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |                 port@0 { | ||||||
|  |                     reg = <0>; | ||||||
|  | 
 | ||||||
|  |                     endpoint { | ||||||
|  |                         remote-endpoint = <&dsi0_out>; | ||||||
|  |                         data-lanes = <1 2 3 4>; | ||||||
|  |                     }; | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 port@2 { | ||||||
|  |                     reg = <2>; | ||||||
|  | 
 | ||||||
|  |                     endpoint { | ||||||
|  |                         remote-endpoint = <&panel_in_lvds>; | ||||||
|  |                     }; | ||||||
|  |                 }; | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
| @ -1,54 +0,0 @@ | |||||||
| * Faraday TV Encoder TVE200 |  | ||||||
| 
 |  | ||||||
| Required properties: |  | ||||||
| 
 |  | ||||||
| - compatible: must be one of: |  | ||||||
| 	"faraday,tve200" |  | ||||||
| 	"cortina,gemini-tvc", "faraday,tve200" |  | ||||||
| 
 |  | ||||||
| - reg: base address and size of the control registers block |  | ||||||
| 
 |  | ||||||
| - interrupts: contains an interrupt specifier for the interrupt |  | ||||||
| 	line from the TVE200 |  | ||||||
| 
 |  | ||||||
| - clock-names: should contain "PCLK" for the clock line clocking the |  | ||||||
| 	silicon and "TVE" for the 27MHz clock to the video driver |  | ||||||
| 
 |  | ||||||
| - clocks: contains phandle and clock specifier pairs for the entries |  | ||||||
| 	in the clock-names property. See |  | ||||||
| 	Documentation/devicetree/bindings/clock/clock-bindings.txt |  | ||||||
| 
 |  | ||||||
| Optional properties: |  | ||||||
| 
 |  | ||||||
| - resets: contains the reset line phandle for the block |  | ||||||
| 
 |  | ||||||
| Required sub-nodes: |  | ||||||
| 
 |  | ||||||
| - port: describes LCD panel signals, following the common binding |  | ||||||
| 	for video transmitter interfaces; see |  | ||||||
| 	Documentation/devicetree/bindings/media/video-interfaces.txt |  | ||||||
| 	This port should have the properties: |  | ||||||
| 	reg = <0>; |  | ||||||
| 	It should have one endpoint connected to a remote endpoint where |  | ||||||
| 	the display is connected. |  | ||||||
| 
 |  | ||||||
| Example: |  | ||||||
| 
 |  | ||||||
| display-controller@6a000000 { |  | ||||||
| 	#address-cells = <1>; |  | ||||||
| 	#size-cells = <0>; |  | ||||||
| 	compatible = "faraday,tve200"; |  | ||||||
| 	reg = <0x6a000000 0x1000>; |  | ||||||
| 	interrupts = <13 IRQ_TYPE_EDGE_RISING>; |  | ||||||
| 	resets = <&syscon GEMINI_RESET_TVC>; |  | ||||||
| 	clocks = <&syscon GEMINI_CLK_GATE_TVC>, |  | ||||||
| 		 <&syscon GEMINI_CLK_TVC>; |  | ||||||
| 	clock-names = "PCLK", "TVE"; |  | ||||||
| 
 |  | ||||||
| 	port@0 { |  | ||||||
| 		reg = <0>; |  | ||||||
| 		display_out: endpoint { |  | ||||||
| 			remote-endpoint = <&panel_in>; |  | ||||||
| 		}; |  | ||||||
| 	}; |  | ||||||
| }; |  | ||||||
| @ -0,0 +1,68 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/faraday,tve200.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Faraday TV Encoder TVE200 | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Linus Walleij <linus.walleij@linaro.org> | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     oneOf: | ||||||
|  |       - const: faraday,tve200 | ||||||
|  |       - items: | ||||||
|  |           - const: cortina,gemini-tvc | ||||||
|  |           - const: faraday,tve200 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     minItems: 1 | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: PCLK | ||||||
|  |       - const: TVE | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     minItems: 2 | ||||||
|  | 
 | ||||||
|  |   resets: | ||||||
|  |     minItems: 1 | ||||||
|  | 
 | ||||||
|  |   port: | ||||||
|  |     $ref: /schemas/graph.yaml#/properties/port | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - interrupts | ||||||
|  |   - clock-names | ||||||
|  |   - clocks | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/clock/cortina,gemini-clock.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|  |     #include <dt-bindings/reset/cortina,gemini-reset.h> | ||||||
|  |     display-controller@6a000000 { | ||||||
|  |       compatible = "faraday,tve200"; | ||||||
|  |       reg = <0x6a000000 0x1000>; | ||||||
|  |       interrupts = <13 IRQ_TYPE_EDGE_RISING>; | ||||||
|  |       resets = <&syscon GEMINI_RESET_TVC>; | ||||||
|  |       clocks = <&syscon GEMINI_CLK_GATE_TVC>, | ||||||
|  |                <&syscon GEMINI_CLK_TVC>; | ||||||
|  |       clock-names = "PCLK", "TVE"; | ||||||
|  | 
 | ||||||
|  |       port { | ||||||
|  |         display_out: endpoint { | ||||||
|  |           remote-endpoint = <&panel_in>; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/mediatek/mediatek,cec.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Mediatek HDMI CEC Controller Device Tree Bindings | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - CK Hu <ck.hu@mediatek.com> | ||||||
|  |   - Jitao shi <jitao.shi@mediatek.com> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   The HDMI CEC controller handles hotplug detection and CEC communication. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - mediatek,mt7623-cec | ||||||
|  |       - mediatek,mt8167-cec | ||||||
|  |       - mediatek,mt8173-cec | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - interrupts | ||||||
|  |   - clocks | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/clock/mt8173-clk.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|  |     cec: cec@10013000 { | ||||||
|  |         compatible = "mediatek,mt8173-cec"; | ||||||
|  |         reg = <0x10013000 0xbc>; | ||||||
|  |         interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_LOW>; | ||||||
|  |         clocks = <&infracfg CLK_INFRA_CEC>; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | ... | ||||||
| @ -0,0 +1,58 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/mediatek/mediatek,hdmi-ddc.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Mediatek HDMI DDC Device Tree Bindings | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - CK Hu <ck.hu@mediatek.com> | ||||||
|  |   - Jitao shi <jitao.shi@mediatek.com> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   The HDMI DDC i2c controller is used to interface with the HDMI DDC pins. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - mediatek,mt7623-hdmi-ddc | ||||||
|  |       - mediatek,mt8167-hdmi-ddc | ||||||
|  |       - mediatek,mt8173-hdmi-ddc | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: ddc-i2c | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - interrupts | ||||||
|  |   - clocks | ||||||
|  |   - clock-names | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/clock/mt8173-clk.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|  |     hdmi_ddc0: i2c@11012000 { | ||||||
|  |         compatible = "mediatek,mt8173-hdmi-ddc"; | ||||||
|  |         reg = <0x11012000 0x1c>; | ||||||
|  |         interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_LOW>; | ||||||
|  |         clocks = <&pericfg CLK_PERI_I2C5>; | ||||||
|  |         clock-names = "ddc-i2c"; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | ... | ||||||
| @ -1,136 +0,0 @@ | |||||||
| Mediatek HDMI Encoder |  | ||||||
| ===================== |  | ||||||
| 
 |  | ||||||
| The Mediatek HDMI encoder can generate HDMI 1.4a or MHL 2.0 signals from |  | ||||||
| its parallel input. |  | ||||||
| 
 |  | ||||||
| Required properties: |  | ||||||
| - compatible: Should be "mediatek,<chip>-hdmi". |  | ||||||
| - the supported chips are mt2701, mt7623 and mt8173 |  | ||||||
| - reg: Physical base address and length of the controller's registers |  | ||||||
| - interrupts: The interrupt signal from the function block. |  | ||||||
| - clocks: device clocks |  | ||||||
|   See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. |  | ||||||
| - clock-names: must contain "pixel", "pll", "bclk", and "spdif". |  | ||||||
| - phys: phandle link to the HDMI PHY node. |  | ||||||
|   See Documentation/devicetree/bindings/phy/phy-bindings.txt for details. |  | ||||||
| - phy-names: must contain "hdmi" |  | ||||||
| - mediatek,syscon-hdmi: phandle link and register offset to the system |  | ||||||
|   configuration registers. For mt8173 this must be offset 0x900 into the |  | ||||||
|   MMSYS_CONFIG region: <&mmsys 0x900>. |  | ||||||
| - ports: A node containing input and output port nodes with endpoint |  | ||||||
|   definitions as documented in Documentation/devicetree/bindings/graph.txt. |  | ||||||
| - port@0: The input port in the ports node should be connected to a DPI output |  | ||||||
|   port. |  | ||||||
| - port@1: The output port in the ports node should be connected to the input |  | ||||||
|   port of a connector node that contains a ddc-i2c-bus property, or to the |  | ||||||
|   input port of an attached bridge chip, such as a SlimPort transmitter. |  | ||||||
| 
 |  | ||||||
| HDMI CEC |  | ||||||
| ======== |  | ||||||
| 
 |  | ||||||
| The HDMI CEC controller handles hotplug detection and CEC communication. |  | ||||||
| 
 |  | ||||||
| Required properties: |  | ||||||
| - compatible: Should be "mediatek,<chip>-cec" |  | ||||||
| - the supported chips are mt7623 and mt8173 |  | ||||||
| - reg: Physical base address and length of the controller's registers |  | ||||||
| - interrupts: The interrupt signal from the function block. |  | ||||||
| - clocks: device clock |  | ||||||
| 
 |  | ||||||
| HDMI DDC |  | ||||||
| ======== |  | ||||||
| 
 |  | ||||||
| The HDMI DDC i2c controller is used to interface with the HDMI DDC pins. |  | ||||||
| The Mediatek's I2C controller is used to interface with I2C devices. |  | ||||||
| 
 |  | ||||||
| Required properties: |  | ||||||
| - compatible: Should be "mediatek,<chip>-hdmi-ddc" |  | ||||||
| - the supported chips are mt7623 and mt8173 |  | ||||||
| - reg: Physical base address and length of the controller's registers |  | ||||||
| - clocks: device clock |  | ||||||
| - clock-names: Should be "ddc-i2c". |  | ||||||
| 
 |  | ||||||
| HDMI PHY |  | ||||||
| ======== |  | ||||||
| See phy/mediatek,hdmi-phy.yaml |  | ||||||
| 
 |  | ||||||
| Example: |  | ||||||
| 
 |  | ||||||
| cec: cec@10013000 { |  | ||||||
| 	compatible = "mediatek,mt8173-cec"; |  | ||||||
| 	reg = <0 0x10013000 0 0xbc>; |  | ||||||
| 	interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_LOW>; |  | ||||||
| 	clocks = <&infracfg CLK_INFRA_CEC>; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| hdmi_phy: hdmi-phy@10209100 { |  | ||||||
| 	compatible = "mediatek,mt8173-hdmi-phy"; |  | ||||||
| 	reg = <0 0x10209100 0 0x24>; |  | ||||||
| 	clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>; |  | ||||||
| 	clock-names = "pll_ref"; |  | ||||||
| 	clock-output-names = "hdmitx_dig_cts"; |  | ||||||
| 	mediatek,ibias = <0xa>; |  | ||||||
| 	mediatek,ibias_up = <0x1c>; |  | ||||||
| 	#clock-cells = <0>; |  | ||||||
| 	#phy-cells = <0>; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| hdmi_ddc0: i2c@11012000 { |  | ||||||
| 	compatible = "mediatek,mt8173-hdmi-ddc"; |  | ||||||
| 	reg = <0 0x11012000 0 0x1c>; |  | ||||||
| 	interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_LOW>; |  | ||||||
| 	clocks = <&pericfg CLK_PERI_I2C5>; |  | ||||||
| 	clock-names = "ddc-i2c"; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| hdmi0: hdmi@14025000 { |  | ||||||
| 	compatible = "mediatek,mt8173-hdmi"; |  | ||||||
| 	reg = <0 0x14025000 0 0x400>; |  | ||||||
| 	interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_LOW>; |  | ||||||
| 	clocks = <&mmsys CLK_MM_HDMI_PIXEL>, |  | ||||||
| 		 <&mmsys CLK_MM_HDMI_PLLCK>, |  | ||||||
| 		 <&mmsys CLK_MM_HDMI_AUDIO>, |  | ||||||
| 		 <&mmsys CLK_MM_HDMI_SPDIF>; |  | ||||||
| 	clock-names = "pixel", "pll", "bclk", "spdif"; |  | ||||||
| 	pinctrl-names = "default"; |  | ||||||
| 	pinctrl-0 = <&hdmi_pin>; |  | ||||||
| 	phys = <&hdmi_phy>; |  | ||||||
| 	phy-names = "hdmi"; |  | ||||||
| 	mediatek,syscon-hdmi = <&mmsys 0x900>; |  | ||||||
| 	assigned-clocks = <&topckgen CLK_TOP_HDMI_SEL>; |  | ||||||
| 	assigned-clock-parents = <&hdmi_phy>; |  | ||||||
| 
 |  | ||||||
| 	ports { |  | ||||||
| 		#address-cells = <1>; |  | ||||||
| 		#size-cells = <0>; |  | ||||||
| 
 |  | ||||||
| 		port@0 { |  | ||||||
| 			reg = <0>; |  | ||||||
| 
 |  | ||||||
| 			hdmi0_in: endpoint { |  | ||||||
| 				remote-endpoint = <&dpi0_out>; |  | ||||||
| 			}; |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		port@1 { |  | ||||||
| 			reg = <1>; |  | ||||||
| 
 |  | ||||||
| 			hdmi0_out: endpoint { |  | ||||||
| 				remote-endpoint = <&hdmi_con_in>; |  | ||||||
| 			}; |  | ||||||
| 		}; |  | ||||||
| 	}; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| connector { |  | ||||||
| 	compatible = "hdmi-connector"; |  | ||||||
| 	type = "a"; |  | ||||||
| 	ddc-i2c-bus = <&hdmiddc0>; |  | ||||||
| 
 |  | ||||||
| 	port { |  | ||||||
| 		hdmi_con_in: endpoint { |  | ||||||
| 			remote-endpoint = <&hdmi0_out>; |  | ||||||
| 		}; |  | ||||||
| 	}; |  | ||||||
| }; |  | ||||||
| @ -0,0 +1,133 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/mediatek/mediatek,hdmi.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Mediatek HDMI Encoder Device Tree Bindings | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - CK Hu <ck.hu@mediatek.com> | ||||||
|  |   - Jitao shi <jitao.shi@mediatek.com> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   The Mediatek HDMI encoder can generate HDMI 1.4a or MHL 2.0 signals from | ||||||
|  |   its parallel input. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - mediatek,mt2701-hdmi | ||||||
|  |       - mediatek,mt7623-hdmi | ||||||
|  |       - mediatek,mt8167-hdmi | ||||||
|  |       - mediatek,mt8173-hdmi | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     items: | ||||||
|  |       - description: Pixel Clock | ||||||
|  |       - description: HDMI PLL | ||||||
|  |       - description: Bit Clock | ||||||
|  |       - description: S/PDIF Clock | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: pixel | ||||||
|  |       - const: pll | ||||||
|  |       - const: bclk | ||||||
|  |       - const: spdif | ||||||
|  | 
 | ||||||
|  |   phys: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   phy-names: | ||||||
|  |     items: | ||||||
|  |       - const: hdmi | ||||||
|  | 
 | ||||||
|  |   mediatek,syscon-hdmi: | ||||||
|  |     $ref: '/schemas/types.yaml#/definitions/phandle-array' | ||||||
|  |     maxItems: 1 | ||||||
|  |     description: | | ||||||
|  |       phandle link and register offset to the system configuration registers. | ||||||
|  | 
 | ||||||
|  |   ports: | ||||||
|  |     $ref: /schemas/graph.yaml#/properties/ports | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       port@0: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: | | ||||||
|  |           Input port node. This port should be connected to a DPI output port. | ||||||
|  | 
 | ||||||
|  |       port@1: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: | | ||||||
|  |           Output port node. This port should be connected to the input port of a connector | ||||||
|  |           node that contains a ddc-i2c-bus property, or to the  input port of an attached | ||||||
|  |           bridge chip, such as a SlimPort transmitter. | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - port@0 | ||||||
|  |       - port@1 | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - interrupts | ||||||
|  |   - clocks | ||||||
|  |   - clock-names | ||||||
|  |   - phys | ||||||
|  |   - phy-names | ||||||
|  |   - mediatek,syscon-hdmi | ||||||
|  |   - ports | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/clock/mt8173-clk.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/irq.h> | ||||||
|  |     hdmi0: hdmi@14025000 { | ||||||
|  |         compatible = "mediatek,mt8173-hdmi"; | ||||||
|  |         reg = <0x14025000 0x400>; | ||||||
|  |         interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_LOW>; | ||||||
|  |         clocks = <&mmsys CLK_MM_HDMI_PIXEL>, | ||||||
|  |              <&mmsys CLK_MM_HDMI_PLLCK>, | ||||||
|  |              <&mmsys CLK_MM_HDMI_AUDIO>, | ||||||
|  |              <&mmsys CLK_MM_HDMI_SPDIF>; | ||||||
|  |         clock-names = "pixel", "pll", "bclk", "spdif"; | ||||||
|  |         pinctrl-names = "default"; | ||||||
|  |         pinctrl-0 = <&hdmi_pin>; | ||||||
|  |         phys = <&hdmi_phy>; | ||||||
|  |         phy-names = "hdmi"; | ||||||
|  |         mediatek,syscon-hdmi = <&mmsys 0x900>; | ||||||
|  | 
 | ||||||
|  |         ports { | ||||||
|  |           #address-cells = <1>; | ||||||
|  |           #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |           port@0 { | ||||||
|  |             reg = <0>; | ||||||
|  | 
 | ||||||
|  |             hdmi0_in: endpoint { | ||||||
|  |               remote-endpoint = <&dpi0_out>; | ||||||
|  |             }; | ||||||
|  |           }; | ||||||
|  | 
 | ||||||
|  |           port@1 { | ||||||
|  |             reg = <1>; | ||||||
|  | 
 | ||||||
|  |             hdmi0_out: endpoint { | ||||||
|  |               remote-endpoint = <&hdmi_con_in>; | ||||||
|  |             }; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | ... | ||||||
							
								
								
									
										146
									
								
								Documentation/devicetree/bindings/display/msm/dp-controller.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								Documentation/devicetree/bindings/display/msm/dp-controller.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,146 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dp-controller.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: MSM Display Port Controller | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Kuogee Hsieh <khsieh@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   Device tree bindings for DisplayPort host controller for MSM targets | ||||||
|  |   that are compatible with VESA DisplayPort interface specification. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     enum: | ||||||
|  |       - qcom,sc7180-dp | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     items: | ||||||
|  |       - description: AHB clock to enable register access | ||||||
|  |       - description: Display Port AUX clock | ||||||
|  |       - description: Display Port Link clock | ||||||
|  |       - description: Link interface clock between DP and PHY | ||||||
|  |       - description: Display Port Pixel clock | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: core_iface | ||||||
|  |       - const: core_aux | ||||||
|  |       - const: ctrl_link | ||||||
|  |       - const: ctrl_link_iface | ||||||
|  |       - const: stream_pixel | ||||||
|  | 
 | ||||||
|  |   assigned-clocks: | ||||||
|  |     items: | ||||||
|  |       - description: link clock source | ||||||
|  |       - description: pixel clock source | ||||||
|  | 
 | ||||||
|  |   assigned-clock-parents: | ||||||
|  |     items: | ||||||
|  |       - description: phy 0 parent | ||||||
|  |       - description: phy 1 parent | ||||||
|  | 
 | ||||||
|  |   phys: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   phy-names: | ||||||
|  |     items: | ||||||
|  |       - const: dp | ||||||
|  | 
 | ||||||
|  |   operating-points-v2: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   power-domains: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   "#sound-dai-cells": | ||||||
|  |     const: 0 | ||||||
|  | 
 | ||||||
|  |   ports: | ||||||
|  |     $ref: /schemas/graph.yaml#/properties/ports | ||||||
|  |     properties: | ||||||
|  |       port@0: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: Input endpoint of the controller | ||||||
|  | 
 | ||||||
|  |       port@1: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |         description: Output endpoint of the controller | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - interrupts | ||||||
|  |   - clocks | ||||||
|  |   - clock-names | ||||||
|  |   - phys | ||||||
|  |   - phy-names | ||||||
|  |   - "#sound-dai-cells" | ||||||
|  |   - power-domains | ||||||
|  |   - ports | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||||
|  |     #include <dt-bindings/clock/qcom,dispcc-sc7180.h> | ||||||
|  |     #include <dt-bindings/power/qcom-aoss-qmp.h> | ||||||
|  |     #include <dt-bindings/power/qcom-rpmpd.h> | ||||||
|  | 
 | ||||||
|  |     displayport-controller@ae90000 { | ||||||
|  |         compatible = "qcom,sc7180-dp"; | ||||||
|  |         reg = <0xae90000 0x1400>; | ||||||
|  |         interrupt-parent = <&mdss>; | ||||||
|  |         interrupts = <12>; | ||||||
|  |         clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                  <&dispcc DISP_CC_MDSS_DP_AUX_CLK>, | ||||||
|  |                  <&dispcc DISP_CC_MDSS_DP_LINK_CLK>, | ||||||
|  |                  <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, | ||||||
|  |                  <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>; | ||||||
|  |         clock-names = "core_iface", "core_aux", | ||||||
|  |                       "ctrl_link", | ||||||
|  |                       "ctrl_link_iface", "stream_pixel"; | ||||||
|  | 
 | ||||||
|  |         assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, | ||||||
|  |                           <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; | ||||||
|  | 
 | ||||||
|  |         assigned-clock-parents = <&dp_phy 0>, <&dp_phy 1>; | ||||||
|  | 
 | ||||||
|  |         phys = <&dp_phy>; | ||||||
|  |         phy-names = "dp"; | ||||||
|  | 
 | ||||||
|  |         #sound-dai-cells = <0>; | ||||||
|  | 
 | ||||||
|  |         power-domains = <&rpmhpd SC7180_CX>; | ||||||
|  | 
 | ||||||
|  |         ports { | ||||||
|  |             #address-cells = <1>; | ||||||
|  |             #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |             port@0 { | ||||||
|  |                 reg = <0>; | ||||||
|  |                 endpoint { | ||||||
|  |                     remote-endpoint = <&dpu_intf0_out>; | ||||||
|  |                 }; | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             port@1 { | ||||||
|  |                 reg = <1>; | ||||||
|  |                 endpoint { | ||||||
|  |                     remote-endpoint = <&typec>; | ||||||
|  |                 }; | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | ... | ||||||
							
								
								
									
										228
									
								
								Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								Documentation/devicetree/bindings/display/msm/dpu-sc7180.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,228 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dpu-sc7180.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm Display DPU dt properties for SC7180 target | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates | ||||||
|  |   sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree | ||||||
|  |   bindings of MDSS and DPU are mentioned for SC7180 target. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     items: | ||||||
|  |       - const: qcom,sc7180-mdss | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   reg-names: | ||||||
|  |     const: mdss | ||||||
|  | 
 | ||||||
|  |   power-domains: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     items: | ||||||
|  |       - description: Display AHB clock from gcc | ||||||
|  |       - description: Display AHB clock from dispcc | ||||||
|  |       - description: Display core clock | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: iface | ||||||
|  |       - const: ahb | ||||||
|  |       - const: core | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupt-controller: true | ||||||
|  | 
 | ||||||
|  |   "#address-cells": true | ||||||
|  | 
 | ||||||
|  |   "#size-cells": true | ||||||
|  | 
 | ||||||
|  |   "#interrupt-cells": | ||||||
|  |     const: 1 | ||||||
|  | 
 | ||||||
|  |   iommus: | ||||||
|  |     items: | ||||||
|  |       - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 | ||||||
|  | 
 | ||||||
|  |   ranges: true | ||||||
|  | 
 | ||||||
|  |   interconnects: | ||||||
|  |     items: | ||||||
|  |       - description: Interconnect path specifying the port ids for data bus | ||||||
|  | 
 | ||||||
|  |   interconnect-names: | ||||||
|  |     const: mdp0-mem | ||||||
|  | 
 | ||||||
|  | patternProperties: | ||||||
|  |   "^display-controller@[0-9a-f]+$": | ||||||
|  |     type: object | ||||||
|  |     description: Node containing the properties of DPU. | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       compatible: | ||||||
|  |         items: | ||||||
|  |           - const: qcom,sc7180-dpu | ||||||
|  | 
 | ||||||
|  |       reg: | ||||||
|  |         items: | ||||||
|  |           - description: Address offset and size for mdp register set | ||||||
|  |           - description: Address offset and size for vbif register set | ||||||
|  | 
 | ||||||
|  |       reg-names: | ||||||
|  |         items: | ||||||
|  |           - const: mdp | ||||||
|  |           - const: vbif | ||||||
|  | 
 | ||||||
|  |       clocks: | ||||||
|  |         items: | ||||||
|  |           - description: Display hf axi clock | ||||||
|  |           - description: Display ahb clock | ||||||
|  |           - description: Display rotator clock | ||||||
|  |           - description: Display lut clock | ||||||
|  |           - description: Display core clock | ||||||
|  |           - description: Display vsync clock | ||||||
|  | 
 | ||||||
|  |       clock-names: | ||||||
|  |         items: | ||||||
|  |           - const: bus | ||||||
|  |           - const: iface | ||||||
|  |           - const: rot | ||||||
|  |           - const: lut | ||||||
|  |           - const: core | ||||||
|  |           - const: vsync | ||||||
|  | 
 | ||||||
|  |       interrupts: | ||||||
|  |         maxItems: 1 | ||||||
|  | 
 | ||||||
|  |       power-domains: | ||||||
|  |         maxItems: 1 | ||||||
|  | 
 | ||||||
|  |       operating-points-v2: true | ||||||
|  | 
 | ||||||
|  |       ports: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/ports | ||||||
|  |         description: | | ||||||
|  |           Contains the list of output ports from DPU device. These ports | ||||||
|  |           connect to interfaces that are external to the DPU hardware, | ||||||
|  |           such as DSI, DP etc. Each output port contains an endpoint that | ||||||
|  |           describes how it is connected to an external interface. | ||||||
|  | 
 | ||||||
|  |         properties: | ||||||
|  |           port@0: | ||||||
|  |             $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |             description: DPU_INTF1 (DSI1) | ||||||
|  | 
 | ||||||
|  |           port@2: | ||||||
|  |             $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |             description: DPU_INTF0 (DP) | ||||||
|  | 
 | ||||||
|  |         required: | ||||||
|  |           - port@0 | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - compatible | ||||||
|  |       - reg | ||||||
|  |       - reg-names | ||||||
|  |       - clocks | ||||||
|  |       - interrupts | ||||||
|  |       - power-domains | ||||||
|  |       - operating-points-v2 | ||||||
|  |       - ports | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reg-names | ||||||
|  |   - power-domains | ||||||
|  |   - clocks | ||||||
|  |   - interrupts | ||||||
|  |   - interrupt-controller | ||||||
|  |   - iommus | ||||||
|  |   - ranges | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/clock/qcom,dispcc-sc7180.h> | ||||||
|  |     #include <dt-bindings/clock/qcom,gcc-sc7180.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||||
|  |     #include <dt-bindings/interconnect/qcom,sdm845.h> | ||||||
|  |     #include <dt-bindings/power/qcom-rpmpd.h> | ||||||
|  | 
 | ||||||
|  |     display-subsystem@ae00000 { | ||||||
|  |          #address-cells = <1>; | ||||||
|  |          #size-cells = <1>; | ||||||
|  |          compatible = "qcom,sc7180-mdss"; | ||||||
|  |          reg = <0xae00000 0x1000>; | ||||||
|  |          reg-names = "mdss"; | ||||||
|  |          power-domains = <&dispcc MDSS_GDSC>; | ||||||
|  |          clocks = <&gcc GCC_DISP_AHB_CLK>, | ||||||
|  |                   <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                   <&dispcc DISP_CC_MDSS_MDP_CLK>; | ||||||
|  |          clock-names = "iface", "ahb", "core"; | ||||||
|  | 
 | ||||||
|  |          interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; | ||||||
|  |          interrupt-controller; | ||||||
|  |          #interrupt-cells = <1>; | ||||||
|  | 
 | ||||||
|  |          interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; | ||||||
|  |          interconnect-names = "mdp0-mem"; | ||||||
|  | 
 | ||||||
|  |          iommus = <&apps_smmu 0x800 0x2>; | ||||||
|  |          ranges; | ||||||
|  | 
 | ||||||
|  |          display-controller@ae01000 { | ||||||
|  |                    compatible = "qcom,sc7180-dpu"; | ||||||
|  |                    reg = <0x0ae01000 0x8f000>, | ||||||
|  |                          <0x0aeb0000 0x2008>; | ||||||
|  | 
 | ||||||
|  |                    reg-names = "mdp", "vbif"; | ||||||
|  | 
 | ||||||
|  |                    clocks = <&gcc GCC_DISP_HF_AXI_CLK>, | ||||||
|  |                             <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                             <&dispcc DISP_CC_MDSS_ROT_CLK>, | ||||||
|  |                             <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, | ||||||
|  |                             <&dispcc DISP_CC_MDSS_MDP_CLK>, | ||||||
|  |                             <&dispcc DISP_CC_MDSS_VSYNC_CLK>; | ||||||
|  |                    clock-names = "bus", "iface", "rot", "lut", "core", | ||||||
|  |                                  "vsync"; | ||||||
|  | 
 | ||||||
|  |                    interrupt-parent = <&mdss>; | ||||||
|  |                    interrupts = <0>; | ||||||
|  |                    power-domains = <&rpmhpd SC7180_CX>; | ||||||
|  |                    operating-points-v2 = <&mdp_opp_table>; | ||||||
|  | 
 | ||||||
|  |                    ports { | ||||||
|  |                            #address-cells = <1>; | ||||||
|  |                            #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |                            port@0 { | ||||||
|  |                                    reg = <0>; | ||||||
|  |                                    dpu_intf1_out: endpoint { | ||||||
|  |                                                   remote-endpoint = <&dsi0_in>; | ||||||
|  |                                    }; | ||||||
|  |                            }; | ||||||
|  | 
 | ||||||
|  |                             port@2 { | ||||||
|  |                                     reg = <2>; | ||||||
|  |                                     dpu_intf0_out: endpoint { | ||||||
|  |                                                    remote-endpoint = <&dp_in>; | ||||||
|  |                                     }; | ||||||
|  |                             }; | ||||||
|  |                    }; | ||||||
|  |          }; | ||||||
|  |     }; | ||||||
|  | ... | ||||||
							
								
								
									
										212
									
								
								Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								Documentation/devicetree/bindings/display/msm/dpu-sdm845.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,212 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dpu-sdm845.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm Display DPU dt properties for SDM845 target | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates | ||||||
|  |   sub-blocks like DPU display controller, DSI and DP interfaces etc. Device tree | ||||||
|  |   bindings of MDSS and DPU are mentioned for SDM845 target. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     items: | ||||||
|  |       - const: qcom,sdm845-mdss | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   reg-names: | ||||||
|  |     const: mdss | ||||||
|  | 
 | ||||||
|  |   power-domains: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     items: | ||||||
|  |       - description: Display AHB clock from gcc | ||||||
|  |       - description: Display AXI clock | ||||||
|  |       - description: Display core clock | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: iface | ||||||
|  |       - const: bus | ||||||
|  |       - const: core | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   interrupt-controller: true | ||||||
|  | 
 | ||||||
|  |   "#address-cells": true | ||||||
|  | 
 | ||||||
|  |   "#size-cells": true | ||||||
|  | 
 | ||||||
|  |   "#interrupt-cells": | ||||||
|  |     const: 1 | ||||||
|  | 
 | ||||||
|  |   iommus: | ||||||
|  |     items: | ||||||
|  |       - description: Phandle to apps_smmu node with SID mask for Hard-Fail port0 | ||||||
|  |       - description: Phandle to apps_smmu node with SID mask for Hard-Fail port1 | ||||||
|  | 
 | ||||||
|  |   ranges: true | ||||||
|  | 
 | ||||||
|  | patternProperties: | ||||||
|  |   "^display-controller@[0-9a-f]+$": | ||||||
|  |     type: object | ||||||
|  |     description: Node containing the properties of DPU. | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       compatible: | ||||||
|  |         items: | ||||||
|  |           - const: qcom,sdm845-dpu | ||||||
|  | 
 | ||||||
|  |       reg: | ||||||
|  |         items: | ||||||
|  |           - description: Address offset and size for mdp register set | ||||||
|  |           - description: Address offset and size for vbif register set | ||||||
|  | 
 | ||||||
|  |       reg-names: | ||||||
|  |         items: | ||||||
|  |           - const: mdp | ||||||
|  |           - const: vbif | ||||||
|  | 
 | ||||||
|  |       clocks: | ||||||
|  |         items: | ||||||
|  |           - description: Display ahb clock | ||||||
|  |           - description: Display axi clock | ||||||
|  |           - description: Display core clock | ||||||
|  |           - description: Display vsync clock | ||||||
|  | 
 | ||||||
|  |       clock-names: | ||||||
|  |         items: | ||||||
|  |           - const: iface | ||||||
|  |           - const: bus | ||||||
|  |           - const: core | ||||||
|  |           - const: vsync | ||||||
|  | 
 | ||||||
|  |       interrupts: | ||||||
|  |         maxItems: 1 | ||||||
|  | 
 | ||||||
|  |       power-domains: | ||||||
|  |         maxItems: 1 | ||||||
|  | 
 | ||||||
|  |       operating-points-v2: true | ||||||
|  |       ports: | ||||||
|  |         $ref: /schemas/graph.yaml#/properties/ports | ||||||
|  |         description: | | ||||||
|  |           Contains the list of output ports from DPU device. These ports | ||||||
|  |           connect to interfaces that are external to the DPU hardware, | ||||||
|  |           such as DSI, DP etc. Each output port contains an endpoint that | ||||||
|  |           describes how it is connected to an external interface. | ||||||
|  | 
 | ||||||
|  |         properties: | ||||||
|  |           port@0: | ||||||
|  |             $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |             description: DPU_INTF1 (DSI1) | ||||||
|  | 
 | ||||||
|  |           port@1: | ||||||
|  |             $ref: /schemas/graph.yaml#/properties/port | ||||||
|  |             description: DPU_INTF2 (DSI2) | ||||||
|  | 
 | ||||||
|  |         required: | ||||||
|  |           - port@0 | ||||||
|  |           - port@1 | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - compatible | ||||||
|  |       - reg | ||||||
|  |       - reg-names | ||||||
|  |       - clocks | ||||||
|  |       - interrupts | ||||||
|  |       - power-domains | ||||||
|  |       - operating-points-v2 | ||||||
|  |       - ports | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reg-names | ||||||
|  |   - power-domains | ||||||
|  |   - clocks | ||||||
|  |   - interrupts | ||||||
|  |   - interrupt-controller | ||||||
|  |   - iommus | ||||||
|  |   - ranges | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/clock/qcom,dispcc-sdm845.h> | ||||||
|  |     #include <dt-bindings/clock/qcom,gcc-sdm845.h> | ||||||
|  |     #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||||
|  |     #include <dt-bindings/power/qcom-rpmpd.h> | ||||||
|  | 
 | ||||||
|  |     display-subsystem@ae00000 { | ||||||
|  |           #address-cells = <1>; | ||||||
|  |           #size-cells = <1>; | ||||||
|  |           compatible = "qcom,sdm845-mdss"; | ||||||
|  |           reg = <0x0ae00000 0x1000>; | ||||||
|  |           reg-names = "mdss"; | ||||||
|  |           power-domains = <&dispcc MDSS_GDSC>; | ||||||
|  | 
 | ||||||
|  |           clocks = <&gcc GCC_DISP_AHB_CLK>, | ||||||
|  |                    <&gcc GCC_DISP_AXI_CLK>, | ||||||
|  |                    <&dispcc DISP_CC_MDSS_MDP_CLK>; | ||||||
|  |           clock-names = "iface", "bus", "core"; | ||||||
|  | 
 | ||||||
|  |           interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; | ||||||
|  |           interrupt-controller; | ||||||
|  |           #interrupt-cells = <1>; | ||||||
|  | 
 | ||||||
|  |           iommus = <&apps_smmu 0x880 0x8>, | ||||||
|  |                    <&apps_smmu 0xc80 0x8>; | ||||||
|  |           ranges; | ||||||
|  | 
 | ||||||
|  |           display-controller@ae01000 { | ||||||
|  |                     compatible = "qcom,sdm845-dpu"; | ||||||
|  |                     reg = <0x0ae01000 0x8f000>, | ||||||
|  |                           <0x0aeb0000 0x2008>; | ||||||
|  |                     reg-names = "mdp", "vbif"; | ||||||
|  | 
 | ||||||
|  |                     clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                              <&dispcc DISP_CC_MDSS_AXI_CLK>, | ||||||
|  |                              <&dispcc DISP_CC_MDSS_MDP_CLK>, | ||||||
|  |                              <&dispcc DISP_CC_MDSS_VSYNC_CLK>; | ||||||
|  |                     clock-names = "iface", "bus", "core", "vsync"; | ||||||
|  | 
 | ||||||
|  |                     interrupt-parent = <&mdss>; | ||||||
|  |                     interrupts = <0>; | ||||||
|  |                     power-domains = <&rpmhpd SDM845_CX>; | ||||||
|  |                     operating-points-v2 = <&mdp_opp_table>; | ||||||
|  | 
 | ||||||
|  |                     ports { | ||||||
|  |                            #address-cells = <1>; | ||||||
|  |                            #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |                            port@0 { | ||||||
|  |                                    reg = <0>; | ||||||
|  |                                    dpu_intf1_out: endpoint { | ||||||
|  |                                                   remote-endpoint = <&dsi0_in>; | ||||||
|  |                                    }; | ||||||
|  |                            }; | ||||||
|  | 
 | ||||||
|  |                            port@1 { | ||||||
|  |                                    reg = <1>; | ||||||
|  |                                    dpu_intf2_out: endpoint { | ||||||
|  |                                                   remote-endpoint = <&dsi1_in>; | ||||||
|  |                                    }; | ||||||
|  |                            }; | ||||||
|  |                     }; | ||||||
|  |           }; | ||||||
|  |     }; | ||||||
|  | ... | ||||||
| @ -1,141 +0,0 @@ | |||||||
| Qualcomm Technologies, Inc. DPU KMS |  | ||||||
| 
 |  | ||||||
| Description: |  | ||||||
| 
 |  | ||||||
| Device tree bindings for MSM Mobile Display Subsystem(MDSS) that encapsulates |  | ||||||
| sub-blocks like DPU display controller, DSI and DP interfaces etc. |  | ||||||
| The DPU display controller is found in SDM845 SoC. |  | ||||||
| 
 |  | ||||||
| MDSS: |  | ||||||
| Required properties: |  | ||||||
| - compatible:  "qcom,sdm845-mdss", "qcom,sc7180-mdss" |  | ||||||
| - reg: physical base address and length of controller's registers. |  | ||||||
| - reg-names: register region names. The following region is required: |  | ||||||
|   * "mdss" |  | ||||||
| - power-domains: a power domain consumer specifier according to |  | ||||||
|   Documentation/devicetree/bindings/power/power_domain.txt |  | ||||||
| - clocks: list of clock specifiers for clocks needed by the device. |  | ||||||
| - clock-names: device clock names, must be in same order as clocks property. |  | ||||||
|   The following clocks are required: |  | ||||||
|   * "iface" |  | ||||||
|   * "bus" |  | ||||||
|   * "core" |  | ||||||
| - interrupts: interrupt signal from MDSS. |  | ||||||
| - interrupt-controller: identifies the node as an interrupt controller. |  | ||||||
| - #interrupt-cells: specifies the number of cells needed to encode an interrupt |  | ||||||
|   source, should be 1. |  | ||||||
| - iommus: phandle of iommu device node. |  | ||||||
| - #address-cells: number of address cells for the MDSS children. Should be 1. |  | ||||||
| - #size-cells: Should be 1. |  | ||||||
| - ranges: parent bus address space is the same as the child bus address space. |  | ||||||
| - interconnects : interconnect path specifier for MDSS according to |  | ||||||
|   Documentation/devicetree/bindings/interconnect/interconnect.txt. Should be |  | ||||||
|   2 paths corresponding to 2 AXI ports. |  | ||||||
| - interconnect-names : MDSS will have 2 port names to differentiate between the |  | ||||||
|   2 interconnect paths defined with interconnect specifier. |  | ||||||
| 
 |  | ||||||
| Optional properties: |  | ||||||
| - assigned-clocks: list of clock specifiers for clocks needing rate assignment |  | ||||||
| - assigned-clock-rates: list of clock frequencies sorted in the same order as |  | ||||||
|   the assigned-clocks property. |  | ||||||
| 
 |  | ||||||
| MDP: |  | ||||||
| Required properties: |  | ||||||
| - compatible: "qcom,sdm845-dpu", "qcom,sc7180-dpu" |  | ||||||
| - reg: physical base address and length of controller's registers. |  | ||||||
| - reg-names : register region names. The following region is required: |  | ||||||
|   * "mdp" |  | ||||||
|   * "vbif" |  | ||||||
| - clocks: list of clock specifiers for clocks needed by the device. |  | ||||||
| - clock-names: device clock names, must be in same order as clocks property. |  | ||||||
|   The following clocks are required. |  | ||||||
|   * "bus" |  | ||||||
|   * "iface" |  | ||||||
|   * "core" |  | ||||||
|   * "vsync" |  | ||||||
| - interrupts: interrupt line from DPU to MDSS. |  | ||||||
| - ports: contains the list of output ports from DPU device. These ports connect |  | ||||||
|   to interfaces that are external to the DPU hardware, such as DSI, DP etc. |  | ||||||
| 
 |  | ||||||
|   Each output port contains an endpoint that describes how it is connected to an |  | ||||||
|   external interface. These are described by the standard properties documented |  | ||||||
|   here: |  | ||||||
| 	Documentation/devicetree/bindings/graph.txt |  | ||||||
| 	Documentation/devicetree/bindings/media/video-interfaces.txt |  | ||||||
| 
 |  | ||||||
| 	Port 0 -> DPU_INTF1 (DSI1) |  | ||||||
| 	Port 1 -> DPU_INTF2 (DSI2) |  | ||||||
| 
 |  | ||||||
| Optional properties: |  | ||||||
| - assigned-clocks: list of clock specifiers for clocks needing rate assignment |  | ||||||
| - assigned-clock-rates: list of clock frequencies sorted in the same order as |  | ||||||
|   the assigned-clocks property. |  | ||||||
| 
 |  | ||||||
| Example: |  | ||||||
| 
 |  | ||||||
| 	mdss: mdss@ae00000 { |  | ||||||
| 		compatible = "qcom,sdm845-mdss"; |  | ||||||
| 		reg = <0xae00000 0x1000>; |  | ||||||
| 		reg-names = "mdss"; |  | ||||||
| 
 |  | ||||||
| 		power-domains = <&clock_dispcc 0>; |  | ||||||
| 
 |  | ||||||
| 		clocks = <&gcc GCC_DISP_AHB_CLK>, <&gcc GCC_DISP_AXI_CLK>, |  | ||||||
| 			 <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; |  | ||||||
| 		clock-names = "iface", "bus", "core"; |  | ||||||
| 
 |  | ||||||
| 		assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; |  | ||||||
| 		assigned-clock-rates = <300000000>; |  | ||||||
| 
 |  | ||||||
| 		interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; |  | ||||||
| 		interrupt-controller; |  | ||||||
| 		#interrupt-cells = <1>; |  | ||||||
| 
 |  | ||||||
| 		interconnects = <&rsc_hlos MASTER_MDP0 &rsc_hlos SLAVE_EBI1>, |  | ||||||
| 				<&rsc_hlos MASTER_MDP1 &rsc_hlos SLAVE_EBI1>; |  | ||||||
| 
 |  | ||||||
| 		interconnect-names = "mdp0-mem", "mdp1-mem"; |  | ||||||
| 
 |  | ||||||
| 		iommus = <&apps_iommu 0>; |  | ||||||
| 
 |  | ||||||
| 		#address-cells = <2>; |  | ||||||
| 		#size-cells = <1>; |  | ||||||
| 		ranges = <0 0 0xae00000 0xb2008>; |  | ||||||
| 
 |  | ||||||
| 		mdss_mdp: mdp@ae01000 { |  | ||||||
| 			compatible = "qcom,sdm845-dpu"; |  | ||||||
| 			reg = <0 0x1000 0x8f000>, <0 0xb0000 0x2008>; |  | ||||||
| 			reg-names = "mdp", "vbif"; |  | ||||||
| 
 |  | ||||||
| 			clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, |  | ||||||
| 				 <&clock_dispcc DISP_CC_MDSS_AXI_CLK>, |  | ||||||
| 				 <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, |  | ||||||
| 				 <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; |  | ||||||
| 			clock-names = "iface", "bus", "core", "vsync"; |  | ||||||
| 
 |  | ||||||
| 			assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, |  | ||||||
| 					  <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; |  | ||||||
| 			assigned-clock-rates = <0 0 300000000 19200000>; |  | ||||||
| 
 |  | ||||||
| 			interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; |  | ||||||
| 
 |  | ||||||
| 			ports { |  | ||||||
| 				#address-cells = <1>; |  | ||||||
| 				#size-cells = <0>; |  | ||||||
| 
 |  | ||||||
| 				port@0 { |  | ||||||
| 					reg = <0>; |  | ||||||
| 					dpu_intf1_out: endpoint { |  | ||||||
| 						remote-endpoint = <&dsi0_in>; |  | ||||||
| 					}; |  | ||||||
| 				}; |  | ||||||
| 
 |  | ||||||
| 				port@1 { |  | ||||||
| 					reg = <1>; |  | ||||||
| 					dpu_intf2_out: endpoint { |  | ||||||
| 						remote-endpoint = <&dsi1_in>; |  | ||||||
| 					}; |  | ||||||
| 				}; |  | ||||||
| 			}; |  | ||||||
| 		}; |  | ||||||
| 	}; |  | ||||||
| @ -0,0 +1,185 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dsi-controller-main.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm Display DSI controller | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: "../dsi-controller.yaml#" | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     items: | ||||||
|  |       - const: qcom,mdss-dsi-ctrl | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   reg-names: | ||||||
|  |     const: dsi_ctrl | ||||||
|  | 
 | ||||||
|  |   interrupts: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     items: | ||||||
|  |       - description: Display byte clock | ||||||
|  |       - description: Display byte interface clock | ||||||
|  |       - description: Display pixel clock | ||||||
|  |       - description: Display escape clock | ||||||
|  |       - description: Display AHB clock | ||||||
|  |       - description: Display AXI clock | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: byte | ||||||
|  |       - const: byte_intf | ||||||
|  |       - const: pixel | ||||||
|  |       - const: core | ||||||
|  |       - const: iface | ||||||
|  |       - const: bus | ||||||
|  | 
 | ||||||
|  |   phys: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   phy-names: | ||||||
|  |     const: dsi | ||||||
|  | 
 | ||||||
|  |   "#address-cells": true | ||||||
|  | 
 | ||||||
|  |   "#size-cells": true | ||||||
|  | 
 | ||||||
|  |   syscon-sfpb: | ||||||
|  |     description: A phandle to mmss_sfpb syscon node (only for DSIv2). | ||||||
|  |     $ref: "/schemas/types.yaml#/definitions/phandle" | ||||||
|  | 
 | ||||||
|  |   qcom,dual-dsi-mode: | ||||||
|  |     type: boolean | ||||||
|  |     description: | | ||||||
|  |       Indicates if the DSI controller is driving a panel which needs | ||||||
|  |       2 DSI links. | ||||||
|  | 
 | ||||||
|  |   power-domains: | ||||||
|  |     maxItems: 1 | ||||||
|  | 
 | ||||||
|  |   operating-points-v2: true | ||||||
|  | 
 | ||||||
|  |   ports: | ||||||
|  |     $ref: "/schemas/graph.yaml#/properties/ports" | ||||||
|  |     description: | | ||||||
|  |       Contains DSI controller input and output ports as children, each | ||||||
|  |       containing one endpoint subnode. | ||||||
|  | 
 | ||||||
|  |     properties: | ||||||
|  |       port@0: | ||||||
|  |         $ref: "/schemas/graph.yaml#/properties/port" | ||||||
|  |         description: | | ||||||
|  |           Input endpoints of the controller. | ||||||
|  |         properties: | ||||||
|  |           endpoint: | ||||||
|  |             $ref: /schemas/media/video-interfaces.yaml# | ||||||
|  |             unevaluatedProperties: false | ||||||
|  |             properties: | ||||||
|  |               data-lanes: | ||||||
|  |                 maxItems: 4 | ||||||
|  |                 minItems: 4 | ||||||
|  |                 items: | ||||||
|  |                   enum: [ 0, 1, 2, 3 ] | ||||||
|  | 
 | ||||||
|  |       port@1: | ||||||
|  |         $ref: "/schemas/graph.yaml#/properties/port" | ||||||
|  |         description: | | ||||||
|  |           Output endpoints of the controller. | ||||||
|  |         properties: | ||||||
|  |           endpoint: | ||||||
|  |             $ref: /schemas/media/video-interfaces.yaml# | ||||||
|  |             unevaluatedProperties: false | ||||||
|  |             properties: | ||||||
|  |               data-lanes: | ||||||
|  |                 maxItems: 4 | ||||||
|  |                 minItems: 4 | ||||||
|  |                 items: | ||||||
|  |                   enum: [ 0, 1, 2, 3 ] | ||||||
|  | 
 | ||||||
|  |     required: | ||||||
|  |       - port@0 | ||||||
|  |       - port@1 | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reg-names | ||||||
|  |   - interrupts | ||||||
|  |   - clocks | ||||||
|  |   - clock-names | ||||||
|  |   - phys | ||||||
|  |   - phy-names | ||||||
|  |   - power-domains | ||||||
|  |   - operating-points-v2 | ||||||
|  |   - ports | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |      #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||||
|  |      #include <dt-bindings/clock/qcom,dispcc-sdm845.h> | ||||||
|  |      #include <dt-bindings/clock/qcom,gcc-sdm845.h> | ||||||
|  |      #include <dt-bindings/power/qcom-rpmpd.h> | ||||||
|  | 
 | ||||||
|  |      dsi@ae94000 { | ||||||
|  |            compatible = "qcom,mdss-dsi-ctrl"; | ||||||
|  |            reg = <0x0ae94000 0x400>; | ||||||
|  |            reg-names = "dsi_ctrl"; | ||||||
|  | 
 | ||||||
|  |            #address-cells = <1>; | ||||||
|  |            #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |            interrupt-parent = <&mdss>; | ||||||
|  |            interrupts = <4>; | ||||||
|  | 
 | ||||||
|  |            clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, | ||||||
|  |                     <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, | ||||||
|  |                     <&dispcc DISP_CC_MDSS_PCLK0_CLK>, | ||||||
|  |                     <&dispcc DISP_CC_MDSS_ESC0_CLK>, | ||||||
|  |                     <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                     <&dispcc DISP_CC_MDSS_AXI_CLK>; | ||||||
|  |            clock-names = "byte", | ||||||
|  |                          "byte_intf", | ||||||
|  |                          "pixel", | ||||||
|  |                          "core", | ||||||
|  |                          "iface", | ||||||
|  |                          "bus"; | ||||||
|  | 
 | ||||||
|  |            phys = <&dsi0_phy>; | ||||||
|  |            phy-names = "dsi"; | ||||||
|  | 
 | ||||||
|  |            power-domains = <&rpmhpd SC7180_CX>; | ||||||
|  |            operating-points-v2 = <&dsi_opp_table>; | ||||||
|  | 
 | ||||||
|  |            ports { | ||||||
|  |                   #address-cells = <1>; | ||||||
|  |                   #size-cells = <0>; | ||||||
|  | 
 | ||||||
|  |                   port@0 { | ||||||
|  |                           reg = <0>; | ||||||
|  |                           dsi0_in: endpoint { | ||||||
|  |                                    remote-endpoint = <&dpu_intf1_out>; | ||||||
|  |                           }; | ||||||
|  |                   }; | ||||||
|  | 
 | ||||||
|  |                   port@1 { | ||||||
|  |                           reg = <1>; | ||||||
|  |                           dsi0_out: endpoint { | ||||||
|  |                                    remote-endpoint = <&sn65dsi86_in>; | ||||||
|  |                                    data-lanes = <0 1 2 3>; | ||||||
|  |                           }; | ||||||
|  |                   }; | ||||||
|  |            }; | ||||||
|  |      }; | ||||||
|  | ... | ||||||
| @ -0,0 +1,68 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dsi-phy-10nm.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm Display DSI 10nm PHY | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: dsi-phy-common.yaml# | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     oneOf: | ||||||
|  |       - const: qcom,dsi-phy-10nm | ||||||
|  |       - const: qcom,dsi-phy-10nm-8998 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     items: | ||||||
|  |       - description: dsi phy register set | ||||||
|  |       - description: dsi phy lane register set | ||||||
|  |       - description: dsi pll register set | ||||||
|  | 
 | ||||||
|  |   reg-names: | ||||||
|  |     items: | ||||||
|  |       - const: dsi_phy | ||||||
|  |       - const: dsi_phy_lane | ||||||
|  |       - const: dsi_pll | ||||||
|  | 
 | ||||||
|  |   vdds-supply: | ||||||
|  |     description: | | ||||||
|  |       Connected to DSI0_MIPI_DSI_PLL_VDDA0P9 pin for sc7180 target and | ||||||
|  |       connected to VDDA_MIPI_DSI_0_PLL_0P9 pin for sdm845 target | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reg-names | ||||||
|  |   - vdds-supply | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |      #include <dt-bindings/clock/qcom,dispcc-sdm845.h> | ||||||
|  |      #include <dt-bindings/clock/qcom,rpmh.h> | ||||||
|  | 
 | ||||||
|  |      dsi-phy@ae94400 { | ||||||
|  |          compatible = "qcom,dsi-phy-10nm"; | ||||||
|  |          reg = <0x0ae94400 0x200>, | ||||||
|  |                <0x0ae94600 0x280>, | ||||||
|  |                <0x0ae94a00 0x1e0>; | ||||||
|  |          reg-names = "dsi_phy", | ||||||
|  |                      "dsi_phy_lane", | ||||||
|  |                      "dsi_pll"; | ||||||
|  | 
 | ||||||
|  |          #clock-cells = <1>; | ||||||
|  |          #phy-cells = <0>; | ||||||
|  | 
 | ||||||
|  |          vdds-supply = <&vdda_mipi_dsi0_pll>; | ||||||
|  |          clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                   <&rpmhcc RPMH_CXO_CLK>; | ||||||
|  |          clock-names = "iface", "ref"; | ||||||
|  |      }; | ||||||
|  | ... | ||||||
| @ -0,0 +1,66 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dsi-phy-14nm.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm Display DSI 14nm PHY | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: dsi-phy-common.yaml# | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     oneOf: | ||||||
|  |       - const: qcom,dsi-phy-14nm | ||||||
|  |       - const: qcom,dsi-phy-14nm-660 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     items: | ||||||
|  |       - description: dsi phy register set | ||||||
|  |       - description: dsi phy lane register set | ||||||
|  |       - description: dsi pll register set | ||||||
|  | 
 | ||||||
|  |   reg-names: | ||||||
|  |     items: | ||||||
|  |       - const: dsi_phy | ||||||
|  |       - const: dsi_phy_lane | ||||||
|  |       - const: dsi_pll | ||||||
|  | 
 | ||||||
|  |   vcca-supply: | ||||||
|  |     description: Phandle to vcca regulator device node. | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reg-names | ||||||
|  |   - vcca-supply | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |      #include <dt-bindings/clock/qcom,dispcc-sdm845.h> | ||||||
|  |      #include <dt-bindings/clock/qcom,rpmh.h> | ||||||
|  | 
 | ||||||
|  |      dsi-phy@ae94400 { | ||||||
|  |          compatible = "qcom,dsi-phy-14nm"; | ||||||
|  |          reg = <0x0ae94400 0x200>, | ||||||
|  |                <0x0ae94600 0x280>, | ||||||
|  |                <0x0ae94a00 0x1e0>; | ||||||
|  |          reg-names = "dsi_phy", | ||||||
|  |                      "dsi_phy_lane", | ||||||
|  |                      "dsi_pll"; | ||||||
|  | 
 | ||||||
|  |          #clock-cells = <1>; | ||||||
|  |          #phy-cells = <0>; | ||||||
|  | 
 | ||||||
|  |          vcca-supply = <&vcca_reg>; | ||||||
|  |          clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                   <&rpmhcc RPMH_CXO_CLK>; | ||||||
|  |          clock-names = "iface", "ref"; | ||||||
|  |      }; | ||||||
|  | ... | ||||||
| @ -0,0 +1,71 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dsi-phy-20nm.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm Display DSI 20nm PHY | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: dsi-phy-common.yaml# | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     oneOf: | ||||||
|  |       - const: qcom,dsi-phy-20nm | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     items: | ||||||
|  |       - description: dsi pll register set | ||||||
|  |       - description: dsi phy register set | ||||||
|  |       - description: dsi phy regulator register set | ||||||
|  | 
 | ||||||
|  |   reg-names: | ||||||
|  |     items: | ||||||
|  |       - const: dsi_pll | ||||||
|  |       - const: dsi_phy | ||||||
|  |       - const: dsi_phy_regulator | ||||||
|  | 
 | ||||||
|  |   vcca-supply: | ||||||
|  |     description: Phandle to vcca regulator device node. | ||||||
|  | 
 | ||||||
|  |   vddio-supply: | ||||||
|  |     description: Phandle to vdd-io regulator device node. | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reg-names | ||||||
|  |   - vddio-supply | ||||||
|  |   - vcca-supply | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |      #include <dt-bindings/clock/qcom,dispcc-sdm845.h> | ||||||
|  |      #include <dt-bindings/clock/qcom,rpmh.h> | ||||||
|  | 
 | ||||||
|  |      dsi-phy@fd922a00 { | ||||||
|  |          compatible = "qcom,dsi-phy-20nm"; | ||||||
|  |          reg = <0xfd922a00 0xd4>, | ||||||
|  |                <0xfd922b00 0x2b0>, | ||||||
|  |                <0xfd922d80 0x7b>; | ||||||
|  |          reg-names = "dsi_pll", | ||||||
|  |                      "dsi_phy", | ||||||
|  |                      "dsi_phy_regulator"; | ||||||
|  | 
 | ||||||
|  |          #clock-cells = <1>; | ||||||
|  |          #phy-cells = <0>; | ||||||
|  | 
 | ||||||
|  |          vcca-supply = <&vcca_reg>; | ||||||
|  |          vddio-supply = <&vddio_reg>; | ||||||
|  | 
 | ||||||
|  |          clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                   <&rpmhcc RPMH_CXO_CLK>; | ||||||
|  |          clock-names = "iface", "ref"; | ||||||
|  |      }; | ||||||
|  | ... | ||||||
| @ -0,0 +1,68 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dsi-phy-28nm.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Qualcomm Display DSI 28nm PHY | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: dsi-phy-common.yaml# | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     oneOf: | ||||||
|  |       - const: qcom,dsi-phy-28nm-hpm | ||||||
|  |       - const: qcom,dsi-phy-28nm-lp | ||||||
|  |       - const: qcom,dsi-phy-28nm-8960 | ||||||
|  | 
 | ||||||
|  |   reg: | ||||||
|  |     items: | ||||||
|  |       - description: dsi pll register set | ||||||
|  |       - description: dsi phy register set | ||||||
|  |       - description: dsi phy regulator register set | ||||||
|  | 
 | ||||||
|  |   reg-names: | ||||||
|  |     items: | ||||||
|  |       - const: dsi_pll | ||||||
|  |       - const: dsi_phy | ||||||
|  |       - const: dsi_phy_regulator | ||||||
|  | 
 | ||||||
|  |   vddio-supply: | ||||||
|  |     description: Phandle to vdd-io regulator device node. | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  |   - reg-names | ||||||
|  |   - vddio-supply | ||||||
|  | 
 | ||||||
|  | unevaluatedProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |      #include <dt-bindings/clock/qcom,dispcc-sdm845.h> | ||||||
|  |      #include <dt-bindings/clock/qcom,rpmh.h> | ||||||
|  | 
 | ||||||
|  |      dsi-phy@fd922a00 { | ||||||
|  |          compatible = "qcom,dsi-phy-28nm-lp"; | ||||||
|  |          reg = <0xfd922a00 0xd4>, | ||||||
|  |                <0xfd922b00 0x2b0>, | ||||||
|  |                <0xfd922d80 0x7b>; | ||||||
|  |          reg-names = "dsi_pll", | ||||||
|  |                      "dsi_phy", | ||||||
|  |                      "dsi_phy_regulator"; | ||||||
|  | 
 | ||||||
|  |          #clock-cells = <1>; | ||||||
|  |          #phy-cells = <0>; | ||||||
|  | 
 | ||||||
|  |          vddio-supply = <&vddio_reg>; | ||||||
|  | 
 | ||||||
|  |          clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, | ||||||
|  |                   <&rpmhcc RPMH_CXO_CLK>; | ||||||
|  |          clock-names = "iface", "ref"; | ||||||
|  |      }; | ||||||
|  | ... | ||||||
| @ -0,0 +1,40 @@ | |||||||
|  | # SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/msm/dsi-phy-common.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Description of Qualcomm Display DSI PHY common dt properties | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Krishna Manikandan <mkrishn@codeaurora.org> | ||||||
|  | 
 | ||||||
|  | description: | | ||||||
|  |   This defines the DSI PHY dt properties which are common for all | ||||||
|  |   dsi phy versions. | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   "#clock-cells": | ||||||
|  |     const: 1 | ||||||
|  | 
 | ||||||
|  |   "#phy-cells": | ||||||
|  |     const: 0 | ||||||
|  | 
 | ||||||
|  |   clocks: | ||||||
|  |     items: | ||||||
|  |       - description: Display AHB clock | ||||||
|  |       - description: Board XO source | ||||||
|  | 
 | ||||||
|  |   clock-names: | ||||||
|  |     items: | ||||||
|  |       - const: iface | ||||||
|  |       - const: ref | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - clocks | ||||||
|  |   - clock-names | ||||||
|  |   - "#clock-cells" | ||||||
|  |   - "#phy-cells" | ||||||
|  | 
 | ||||||
|  | additionalProperties: true | ||||||
|  | ... | ||||||
| @ -1,249 +0,0 @@ | |||||||
| Qualcomm Technologies Inc. adreno/snapdragon DSI output |  | ||||||
| 
 |  | ||||||
| DSI Controller: |  | ||||||
| Required properties: |  | ||||||
| - compatible: |  | ||||||
|   * "qcom,mdss-dsi-ctrl" |  | ||||||
| - reg: Physical base address and length of the registers of controller |  | ||||||
| - reg-names: The names of register regions. The following regions are required: |  | ||||||
|   * "dsi_ctrl" |  | ||||||
| - interrupts: The interrupt signal from the DSI block. |  | ||||||
| - power-domains: Should be <&mmcc MDSS_GDSC>. |  | ||||||
| - clocks: Phandles to device clocks. |  | ||||||
| - clock-names: the following clocks are required: |  | ||||||
|   * "mdp_core" |  | ||||||
|   * "iface" |  | ||||||
|   * "bus" |  | ||||||
|   * "core_mmss" |  | ||||||
|   * "byte" |  | ||||||
|   * "pixel" |  | ||||||
|   * "core" |  | ||||||
|   For DSIv2, we need an additional clock: |  | ||||||
|    * "src" |  | ||||||
|   For DSI6G v2.0 onwards, we need also need the clock: |  | ||||||
|    * "byte_intf" |  | ||||||
| - assigned-clocks: Parents of "byte" and "pixel" for the given platform. |  | ||||||
| - assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided |  | ||||||
|   by a DSI PHY block. See [1] for details on clock bindings. |  | ||||||
| - vdd-supply: phandle to vdd regulator device node |  | ||||||
| - vddio-supply: phandle to vdd-io regulator device node |  | ||||||
| - vdda-supply: phandle to vdda regulator device node |  | ||||||
| - phys: phandle to DSI PHY device node |  | ||||||
| - phy-names: the name of the corresponding PHY device |  | ||||||
| - syscon-sfpb: A phandle to mmss_sfpb syscon node (only for DSIv2) |  | ||||||
| - ports: Contains 2 DSI controller ports as child nodes. Each port contains |  | ||||||
|   an endpoint subnode as defined in [2] and [3]. |  | ||||||
| 
 |  | ||||||
| Optional properties: |  | ||||||
| - panel@0: Node of panel connected to this DSI controller. |  | ||||||
|   See files in [4] for each supported panel. |  | ||||||
| - qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is |  | ||||||
|   driving a panel which needs 2 DSI links. |  | ||||||
| - qcom,master-dsi: Boolean value indicating if the DSI controller is driving |  | ||||||
|   the master link of the 2-DSI panel. |  | ||||||
| - qcom,sync-dual-dsi: Boolean value indicating if the DSI controller is |  | ||||||
|   driving a 2-DSI panel whose 2 links need receive command simultaneously. |  | ||||||
| - pinctrl-names: the pin control state names; should contain "default" |  | ||||||
| - pinctrl-0: the default pinctrl state (active) |  | ||||||
| - pinctrl-n: the "sleep" pinctrl state |  | ||||||
| - ports: contains DSI controller input and output ports as children, each |  | ||||||
|   containing one endpoint subnode. |  | ||||||
| 
 |  | ||||||
|   DSI Endpoint properties: |  | ||||||
|   - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's |  | ||||||
|     input endpoint. For port@1, set to the MDP interface output. See [2] for |  | ||||||
|     device graph info. |  | ||||||
| 
 |  | ||||||
|   - data-lanes: this describes how the physical DSI data lanes are mapped |  | ||||||
|     to the logical lanes on the given platform. The value contained in |  | ||||||
|     index n describes what physical lane is mapped to the logical lane n |  | ||||||
|     (DATAn, where n lies between 0 and 3). The clock lane position is fixed |  | ||||||
|     and can't be changed. Hence, they aren't a part of the DT bindings. See |  | ||||||
|     [3] for more info on the data-lanes property. |  | ||||||
| 
 |  | ||||||
|     For example: |  | ||||||
| 
 |  | ||||||
|     data-lanes = <3 0 1 2>; |  | ||||||
| 
 |  | ||||||
|     The above mapping describes that the logical data lane DATA0 is mapped to |  | ||||||
|     the physical data lane DATA3, logical DATA1 to physical DATA0, logic DATA2 |  | ||||||
|     to phys DATA1 and logic DATA3 to phys DATA2. |  | ||||||
| 
 |  | ||||||
|     There are only a limited number of physical to logical mappings possible: |  | ||||||
|     <0 1 2 3> |  | ||||||
|     <1 2 3 0> |  | ||||||
|     <2 3 0 1> |  | ||||||
|     <3 0 1 2> |  | ||||||
|     <0 3 2 1> |  | ||||||
|     <1 0 3 2> |  | ||||||
|     <2 1 0 3> |  | ||||||
|     <3 2 1 0> |  | ||||||
| 
 |  | ||||||
| DSI PHY: |  | ||||||
| Required properties: |  | ||||||
| - compatible: Could be the following |  | ||||||
|   * "qcom,dsi-phy-28nm-hpm" |  | ||||||
|   * "qcom,dsi-phy-28nm-lp" |  | ||||||
|   * "qcom,dsi-phy-20nm" |  | ||||||
|   * "qcom,dsi-phy-28nm-8960" |  | ||||||
|   * "qcom,dsi-phy-14nm" |  | ||||||
|   * "qcom,dsi-phy-14nm-660" |  | ||||||
|   * "qcom,dsi-phy-10nm" |  | ||||||
|   * "qcom,dsi-phy-10nm-8998" |  | ||||||
|   * "qcom,dsi-phy-7nm" |  | ||||||
|   * "qcom,dsi-phy-7nm-8150" |  | ||||||
| - reg: Physical base address and length of the registers of PLL, PHY. Some |  | ||||||
|   revisions require the PHY regulator base address, whereas others require the |  | ||||||
|   PHY lane base address. See below for each PHY revision. |  | ||||||
| - reg-names: The names of register regions. The following regions are required: |  | ||||||
|   For DSI 28nm HPM/LP/8960 PHYs and 20nm PHY: |  | ||||||
|   * "dsi_pll" |  | ||||||
|   * "dsi_phy" |  | ||||||
|   * "dsi_phy_regulator" |  | ||||||
|   For DSI 14nm, 10nm and 7nm PHYs: |  | ||||||
|   * "dsi_pll" |  | ||||||
|   * "dsi_phy" |  | ||||||
|   * "dsi_phy_lane" |  | ||||||
| - clock-cells: Must be 1. The DSI PHY block acts as a clock provider, creating |  | ||||||
|   2 clocks: A byte clock (index 0), and a pixel clock (index 1). |  | ||||||
| - power-domains: Should be <&mmcc MDSS_GDSC>. |  | ||||||
| - clocks: Phandles to device clocks. See [1] for details on clock bindings. |  | ||||||
| - clock-names: the following clocks are required: |  | ||||||
|   * "iface" |  | ||||||
|   * "ref" (only required for new DTS files/entries) |  | ||||||
|   For 28nm HPM/LP, 28nm 8960 PHYs: |  | ||||||
| - vddio-supply: phandle to vdd-io regulator device node |  | ||||||
|   For 20nm PHY: |  | ||||||
| - vddio-supply: phandle to vdd-io regulator device node |  | ||||||
| - vcca-supply: phandle to vcca regulator device node |  | ||||||
|   For 14nm PHY: |  | ||||||
| - vcca-supply: phandle to vcca regulator device node |  | ||||||
|   For 10nm and 7nm PHY: |  | ||||||
| - vdds-supply: phandle to vdds regulator device node |  | ||||||
| 
 |  | ||||||
| Optional properties: |  | ||||||
| - qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY |  | ||||||
|   regulator is wanted. |  | ||||||
| - qcom,mdss-mdp-transfer-time-us:	Specifies the dsi transfer time for command mode |  | ||||||
| 					panels in microseconds. Driver uses this number to adjust |  | ||||||
| 					the clock rate according to the expected transfer time. |  | ||||||
| 					Increasing this value would slow down the mdp processing |  | ||||||
| 					and can result in slower performance. |  | ||||||
| 					Decreasing this value can speed up the mdp processing, |  | ||||||
| 					but this can also impact power consumption. |  | ||||||
| 					As a rule this time should not be higher than the time |  | ||||||
| 					that would be expected with the processing at the |  | ||||||
| 					dsi link rate since anyways this would be the maximum |  | ||||||
| 					transfer time that could be achieved. |  | ||||||
| 					If ping pong split is enabled, this time should not be higher |  | ||||||
| 					than two times the dsi link rate time. |  | ||||||
| 					If the property is not specified, then the default value is 14000 us. |  | ||||||
| 
 |  | ||||||
| [1] Documentation/devicetree/bindings/clock/clock-bindings.txt |  | ||||||
| [2] Documentation/devicetree/bindings/graph.txt |  | ||||||
| [3] Documentation/devicetree/bindings/media/video-interfaces.txt |  | ||||||
| [4] Documentation/devicetree/bindings/display/panel/ |  | ||||||
| 
 |  | ||||||
| Example: |  | ||||||
| 	dsi0: dsi@fd922800 { |  | ||||||
| 		compatible = "qcom,mdss-dsi-ctrl"; |  | ||||||
| 		qcom,dsi-host-index = <0>; |  | ||||||
| 		interrupt-parent = <&mdp>; |  | ||||||
| 		interrupts = <4 0>; |  | ||||||
| 		reg-names = "dsi_ctrl"; |  | ||||||
| 		reg = <0xfd922800 0x200>; |  | ||||||
| 		power-domains = <&mmcc MDSS_GDSC>; |  | ||||||
| 		clock-names = |  | ||||||
| 			"bus", |  | ||||||
| 			"byte", |  | ||||||
| 			"core", |  | ||||||
| 			"core_mmss", |  | ||||||
| 			"iface", |  | ||||||
| 			"mdp_core", |  | ||||||
| 			"pixel"; |  | ||||||
| 		clocks = |  | ||||||
| 			<&mmcc MDSS_AXI_CLK>, |  | ||||||
| 			<&mmcc MDSS_BYTE0_CLK>, |  | ||||||
| 			<&mmcc MDSS_ESC0_CLK>, |  | ||||||
| 			<&mmcc MMSS_MISC_AHB_CLK>, |  | ||||||
| 			<&mmcc MDSS_AHB_CLK>, |  | ||||||
| 			<&mmcc MDSS_MDP_CLK>, |  | ||||||
| 			<&mmcc MDSS_PCLK0_CLK>; |  | ||||||
| 
 |  | ||||||
| 		assigned-clocks = |  | ||||||
| 				 <&mmcc BYTE0_CLK_SRC>, |  | ||||||
| 				 <&mmcc PCLK0_CLK_SRC>; |  | ||||||
| 		assigned-clock-parents = |  | ||||||
| 				 <&dsi_phy0 0>, |  | ||||||
| 				 <&dsi_phy0 1>; |  | ||||||
| 
 |  | ||||||
| 		vdda-supply = <&pma8084_l2>; |  | ||||||
| 		vdd-supply = <&pma8084_l22>; |  | ||||||
| 		vddio-supply = <&pma8084_l12>; |  | ||||||
| 
 |  | ||||||
| 		phys = <&dsi_phy0>; |  | ||||||
| 		phy-names ="dsi-phy"; |  | ||||||
| 
 |  | ||||||
| 		qcom,dual-dsi-mode; |  | ||||||
| 		qcom,master-dsi; |  | ||||||
| 		qcom,sync-dual-dsi; |  | ||||||
| 
 |  | ||||||
| 		qcom,mdss-mdp-transfer-time-us = <12000>; |  | ||||||
| 
 |  | ||||||
| 		pinctrl-names = "default", "sleep"; |  | ||||||
| 		pinctrl-0 = <&dsi_active>; |  | ||||||
| 		pinctrl-1 = <&dsi_suspend>; |  | ||||||
| 
 |  | ||||||
| 		ports { |  | ||||||
| 			#address-cells = <1>; |  | ||||||
| 			#size-cells = <0>; |  | ||||||
| 
 |  | ||||||
| 			port@0 { |  | ||||||
| 				reg = <0>; |  | ||||||
| 				dsi0_in: endpoint { |  | ||||||
| 					remote-endpoint = <&mdp_intf1_out>; |  | ||||||
| 				}; |  | ||||||
| 			}; |  | ||||||
| 
 |  | ||||||
| 			port@1 { |  | ||||||
| 				reg = <1>; |  | ||||||
| 				dsi0_out: endpoint { |  | ||||||
| 					remote-endpoint = <&panel_in>; |  | ||||||
| 					data-lanes = <0 1 2 3>; |  | ||||||
| 				}; |  | ||||||
| 			}; |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		panel: panel@0 { |  | ||||||
| 			compatible = "sharp,lq101r1sx01"; |  | ||||||
| 			reg = <0>; |  | ||||||
| 			link2 = <&secondary>; |  | ||||||
| 
 |  | ||||||
| 			power-supply = <...>; |  | ||||||
| 			backlight = <...>; |  | ||||||
| 
 |  | ||||||
| 			port { |  | ||||||
| 				panel_in: endpoint { |  | ||||||
| 					remote-endpoint = <&dsi0_out>; |  | ||||||
| 				}; |  | ||||||
| 			}; |  | ||||||
| 		}; |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	dsi_phy0: dsi-phy@fd922a00 { |  | ||||||
| 		compatible = "qcom,dsi-phy-28nm-hpm"; |  | ||||||
| 		qcom,dsi-phy-index = <0>; |  | ||||||
| 		reg-names = |  | ||||||
| 			"dsi_pll", |  | ||||||
| 			"dsi_phy", |  | ||||||
| 			"dsi_phy_regulator"; |  | ||||||
| 		reg =   <0xfd922a00 0xd4>, |  | ||||||
| 			<0xfd922b00 0x2b0>, |  | ||||||
| 			<0xfd922d80 0x7b>; |  | ||||||
| 		clock-names = "iface"; |  | ||||||
| 		clocks = <&mmcc MDSS_AHB_CLK>; |  | ||||||
| 		#clock-cells = <1>; |  | ||||||
| 		vddio-supply = <&pma8084_l12>; |  | ||||||
| 
 |  | ||||||
| 		qcom,dsi-phy-regulator-ldo-mode; |  | ||||||
| 	}; |  | ||||||
| @ -0,0 +1,74 @@ | |||||||
|  | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||||
|  | %YAML 1.2 | ||||||
|  | --- | ||||||
|  | $id: http://devicetree.org/schemas/display/panel/samsung,lms397kf04.yaml# | ||||||
|  | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||||
|  | 
 | ||||||
|  | title: Samsung LMS397KF04 display panel | ||||||
|  | 
 | ||||||
|  | description: The datasheet claims this is based around a display controller | ||||||
|  |   named DB7430 with a separate backlight controller. | ||||||
|  | 
 | ||||||
|  | maintainers: | ||||||
|  |   - Linus Walleij <linus.walleij@linaro.org> | ||||||
|  | 
 | ||||||
|  | allOf: | ||||||
|  |   - $ref: panel-common.yaml# | ||||||
|  | 
 | ||||||
|  | properties: | ||||||
|  |   compatible: | ||||||
|  |     const: samsung,lms397kf04 | ||||||
|  | 
 | ||||||
|  |   reg: true | ||||||
|  | 
 | ||||||
|  |   reset-gpios: true | ||||||
|  | 
 | ||||||
|  |   vci-supply: | ||||||
|  |     description: regulator that supplies the VCI analog voltage | ||||||
|  |       usually around 3.0 V | ||||||
|  | 
 | ||||||
|  |   vccio-supply: | ||||||
|  |     description: regulator that supplies the VCCIO voltage usually | ||||||
|  |       around 1.8 V | ||||||
|  | 
 | ||||||
|  |   backlight: true | ||||||
|  | 
 | ||||||
|  |   spi-max-frequency: | ||||||
|  |     $ref: /schemas/types.yaml#/definitions/uint32 | ||||||
|  |     description: inherited as a SPI client node, the datasheet specifies | ||||||
|  |       maximum 300 ns minimum cycle which gives around 3 MHz max frequency | ||||||
|  |     maximum: 3000000 | ||||||
|  | 
 | ||||||
|  |   port: true | ||||||
|  | 
 | ||||||
|  | required: | ||||||
|  |   - compatible | ||||||
|  |   - reg | ||||||
|  | 
 | ||||||
|  | additionalProperties: false | ||||||
|  | 
 | ||||||
|  | examples: | ||||||
|  |   - | | ||||||
|  |     #include <dt-bindings/gpio/gpio.h> | ||||||
|  | 
 | ||||||
|  |     spi { | ||||||
|  |       #address-cells = <1>; | ||||||
|  |       #size-cells = <0>; | ||||||
|  |       panel@0 { | ||||||
|  |         compatible = "samsung,lms397kf04"; | ||||||
|  |         spi-max-frequency = <3000000>; | ||||||
|  |         reg = <0>; | ||||||
|  |         vci-supply = <&lcd_3v0_reg>; | ||||||
|  |         vccio-supply = <&lcd_1v8_reg>; | ||||||
|  |         reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>; | ||||||
|  |         backlight = <&ktd259>; | ||||||
|  | 
 | ||||||
|  |         port { | ||||||
|  |           panel_in: endpoint { | ||||||
|  |             remote-endpoint = <&display_out>; | ||||||
|  |           }; | ||||||
|  |         }; | ||||||
|  |       }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | ... | ||||||
| @ -17,6 +17,7 @@ properties: | |||||||
|     items: |     items: | ||||||
|       - enum: |       - enum: | ||||||
|           - amlogic,meson-g12a-mali |           - amlogic,meson-g12a-mali | ||||||
|  |           - mediatek,mt8183-mali | ||||||
|           - realtek,rtd1619-mali |           - realtek,rtd1619-mali | ||||||
|           - rockchip,px30-mali |           - rockchip,px30-mali | ||||||
|       - const: arm,mali-bifrost # Mali Bifrost GPU model/revision is fully discoverable |       - const: arm,mali-bifrost # Mali Bifrost GPU model/revision is fully discoverable | ||||||
| @ -41,10 +42,13 @@ properties: | |||||||
| 
 | 
 | ||||||
|   mali-supply: true |   mali-supply: true | ||||||
| 
 | 
 | ||||||
|  |   sram-supply: true | ||||||
|  | 
 | ||||||
|   operating-points-v2: true |   operating-points-v2: true | ||||||
| 
 | 
 | ||||||
|   power-domains: |   power-domains: | ||||||
|     maxItems: 1 |     minItems: 1 | ||||||
|  |     maxItems: 3 | ||||||
| 
 | 
 | ||||||
|   resets: |   resets: | ||||||
|     maxItems: 2 |     maxItems: 2 | ||||||
| @ -89,6 +93,30 @@ allOf: | |||||||
|     then: |     then: | ||||||
|       required: |       required: | ||||||
|         - resets |         - resets | ||||||
|  |   - if: | ||||||
|  |       properties: | ||||||
|  |         compatible: | ||||||
|  |           contains: | ||||||
|  |             const: mediatek,mt8183-mali | ||||||
|  |     then: | ||||||
|  |       properties: | ||||||
|  |         power-domains: | ||||||
|  |           minItems: 3 | ||||||
|  |         power-domain-names: | ||||||
|  |           items: | ||||||
|  |             - const: core0 | ||||||
|  |             - const: core1 | ||||||
|  |             - const: core2 | ||||||
|  | 
 | ||||||
|  |       required: | ||||||
|  |         - sram-supply | ||||||
|  |         - power-domains | ||||||
|  |         - power-domain-names | ||||||
|  |     else: | ||||||
|  |       properties: | ||||||
|  |         power-domains: | ||||||
|  |           maxItems: 1 | ||||||
|  |         sram-supply: false | ||||||
| 
 | 
 | ||||||
| examples: | examples: | ||||||
|   - | |   - | | ||||||
|  | |||||||
| @ -178,6 +178,15 @@ DMA Fence Array | |||||||
| .. kernel-doc:: include/linux/dma-fence-array.h | .. kernel-doc:: include/linux/dma-fence-array.h | ||||||
|    :internal: |    :internal: | ||||||
| 
 | 
 | ||||||
|  | DMA Fence Chain | ||||||
|  | ~~~~~~~~~~~~~~~ | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: drivers/dma-buf/dma-fence-chain.c | ||||||
|  |    :export: | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: include/linux/dma-fence-chain.h | ||||||
|  |    :internal: | ||||||
|  | 
 | ||||||
| DMA Fence uABI/Sync File | DMA Fence uABI/Sync File | ||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -66,3 +66,9 @@ Display Core | |||||||
| ============ | ============ | ||||||
| 
 | 
 | ||||||
| **WIP** | **WIP** | ||||||
|  | 
 | ||||||
|  | FreeSync Video | ||||||
|  | -------------- | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | ||||||
|  |    :doc: FreeSync Video | ||||||
|  | |||||||
| @ -300,4 +300,25 @@ pcie_replay_count | |||||||
| .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | .. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | ||||||
|    :doc: pcie_replay_count |    :doc: pcie_replay_count | ||||||
| 
 | 
 | ||||||
|  | +GPU SmartShift Information | ||||||
|  | ============================ | ||||||
| 
 | 
 | ||||||
|  | GPU SmartShift information via sysfs | ||||||
|  | 
 | ||||||
|  | smartshift_apu_power | ||||||
|  | -------------------- | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c | ||||||
|  |    :doc: smartshift_apu_power | ||||||
|  | 
 | ||||||
|  | smartshift_dgpu_power | ||||||
|  | --------------------- | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c | ||||||
|  |    :doc: smartshift_dgpu_power | ||||||
|  | 
 | ||||||
|  | smartshift_bias | ||||||
|  | --------------- | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c | ||||||
|  |    :doc: smartshift_bias | ||||||
|  | |||||||
							
								
								
									
										8
									
								
								Documentation/gpu/driver-uapi.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Documentation/gpu/driver-uapi.rst
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | =============== | ||||||
|  | DRM Driver uAPI | ||||||
|  | =============== | ||||||
|  | 
 | ||||||
|  | drm/i915 uAPI | ||||||
|  | ============= | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: include/uapi/drm/i915_drm.h | ||||||
| @ -75,6 +75,18 @@ update it, its value is mostly useless. The DRM core prints it to the | |||||||
| kernel log at initialization time and passes it to userspace through the | kernel log at initialization time and passes it to userspace through the | ||||||
| DRM_IOCTL_VERSION ioctl. | DRM_IOCTL_VERSION ioctl. | ||||||
| 
 | 
 | ||||||
|  | Managing Ownership of the Framebuffer Aperture | ||||||
|  | ---------------------------------------------- | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: drivers/gpu/drm/drm_aperture.c | ||||||
|  |    :doc: overview | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: include/drm/drm_aperture.h | ||||||
|  |    :internal: | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: drivers/gpu/drm/drm_aperture.c | ||||||
|  |    :export: | ||||||
|  | 
 | ||||||
| Device Instance and Driver Handling | Device Instance and Driver Handling | ||||||
| ----------------------------------- | ----------------------------------- | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -469,8 +469,8 @@ DRM MM Range Allocator Function References | |||||||
| .. kernel-doc:: drivers/gpu/drm/drm_mm.c | .. kernel-doc:: drivers/gpu/drm/drm_mm.c | ||||||
|    :export: |    :export: | ||||||
| 
 | 
 | ||||||
| DRM Cache Handling | DRM Cache Handling and Fast WC memcpy() | ||||||
| ================== | ======================================= | ||||||
| 
 | 
 | ||||||
| .. kernel-doc:: drivers/gpu/drm/drm_cache.c | .. kernel-doc:: drivers/gpu/drm/drm_cache.c | ||||||
|    :export: |    :export: | ||||||
|  | |||||||
| @ -210,13 +210,13 @@ DPIO | |||||||
| .. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpio_phy.c | .. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpio_phy.c | ||||||
|    :doc: DPIO |    :doc: DPIO | ||||||
| 
 | 
 | ||||||
| CSR firmware support for DMC | DMC Firmware Support | ||||||
| ---------------------------- | -------------------- | ||||||
| 
 | 
 | ||||||
| .. kernel-doc:: drivers/gpu/drm/i915/display/intel_csr.c | .. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c | ||||||
|    :doc: csr support for dmc |    :doc: DMC Firmware Support | ||||||
| 
 | 
 | ||||||
| .. kernel-doc:: drivers/gpu/drm/i915/display/intel_csr.c | .. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c | ||||||
|    :internal: |    :internal: | ||||||
| 
 | 
 | ||||||
| Video BIOS Table (VBT) | Video BIOS Table (VBT) | ||||||
| @ -537,7 +537,7 @@ The HuC FW layout is the same as the GuC one, see `GuC Firmware Layout`_ | |||||||
| 
 | 
 | ||||||
| DMC | DMC | ||||||
| --- | --- | ||||||
| See `CSR firmware support for DMC`_ | See `DMC Firmware Support`_ | ||||||
| 
 | 
 | ||||||
| Tracing | Tracing | ||||||
| ======= | ======= | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ Linux GPU Driver Developer's Guide | |||||||
|    drm-kms |    drm-kms | ||||||
|    drm-kms-helpers |    drm-kms-helpers | ||||||
|    drm-uapi |    drm-uapi | ||||||
|  |    driver-uapi | ||||||
|    drm-client |    drm-client | ||||||
|    drivers |    drivers | ||||||
|    backlight |    backlight | ||||||
|  | |||||||
							
								
								
									
										131
									
								
								Documentation/gpu/rfc/i915_gem_lmem.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								Documentation/gpu/rfc/i915_gem_lmem.rst
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,131 @@ | |||||||
|  | ========================= | ||||||
|  | I915 DG1/LMEM RFC Section | ||||||
|  | ========================= | ||||||
|  | 
 | ||||||
|  | Upstream plan | ||||||
|  | ============= | ||||||
|  | For upstream the overall plan for landing all the DG1 stuff and turning it for | ||||||
|  | real, with all the uAPI bits is: | ||||||
|  | 
 | ||||||
|  | * Merge basic HW enabling of DG1(still without pciid) | ||||||
|  | * Merge the uAPI bits behind special CONFIG_BROKEN(or so) flag | ||||||
|  |         * At this point we can still make changes, but importantly this lets us | ||||||
|  |           start running IGTs which can utilize local-memory in CI | ||||||
|  | * Convert over to TTM, make sure it all keeps working. Some of the work items: | ||||||
|  |         * TTM shrinker for discrete | ||||||
|  |         * dma_resv_lockitem for full dma_resv_lock, i.e not just trylock | ||||||
|  |         * Use TTM CPU pagefault handler | ||||||
|  |         * Route shmem backend over to TTM SYSTEM for discrete | ||||||
|  |         * TTM purgeable object support | ||||||
|  |         * Move i915 buddy allocator over to TTM | ||||||
|  |         * MMAP ioctl mode(see `I915 MMAP`_) | ||||||
|  |         * SET/GET ioctl caching(see `I915 SET/GET CACHING`_) | ||||||
|  | * Send RFC(with mesa-dev on cc) for final sign off on the uAPI | ||||||
|  | * Add pciid for DG1 and turn on uAPI for real | ||||||
|  | 
 | ||||||
|  | New object placement and region query uAPI | ||||||
|  | ========================================== | ||||||
|  | Starting from DG1 we need to give userspace the ability to allocate buffers from | ||||||
|  | device local-memory. Currently the driver supports gem_create, which can place | ||||||
|  | buffers in system memory via shmem, and the usual assortment of other | ||||||
|  | interfaces, like dumb buffers and userptr. | ||||||
|  | 
 | ||||||
|  | To support this new capability, while also providing a uAPI which will work | ||||||
|  | beyond just DG1, we propose to offer three new bits of uAPI: | ||||||
|  | 
 | ||||||
|  | DRM_I915_QUERY_MEMORY_REGIONS | ||||||
|  | ----------------------------- | ||||||
|  | New query ID which allows userspace to discover the list of supported memory | ||||||
|  | regions(like system-memory and local-memory) for a given device. We identify | ||||||
|  | each region with a class and instance pair, which should be unique. The class | ||||||
|  | here would be DEVICE or SYSTEM, and the instance would be zero, on platforms | ||||||
|  | like DG1. | ||||||
|  | 
 | ||||||
|  | Side note: The class/instance design is borrowed from our existing engine uAPI, | ||||||
|  | where we describe every physical engine in terms of its class, and the | ||||||
|  | particular instance, since we can have more than one per class. | ||||||
|  | 
 | ||||||
|  | In the future we also want to expose more information which can further | ||||||
|  | describe the capabilities of a region. | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: include/uapi/drm/i915_drm.h | ||||||
|  |         :functions: drm_i915_gem_memory_class drm_i915_gem_memory_class_instance drm_i915_memory_region_info drm_i915_query_memory_regions | ||||||
|  | 
 | ||||||
|  | GEM_CREATE_EXT | ||||||
|  | -------------- | ||||||
|  | New ioctl which is basically just gem_create but now allows userspace to provide | ||||||
|  | a chain of possible extensions. Note that if we don't provide any extensions and | ||||||
|  | set flags=0 then we get the exact same behaviour as gem_create. | ||||||
|  | 
 | ||||||
|  | Side note: We also need to support PXP[1] in the near future, which is also | ||||||
|  | applicable to integrated platforms, and adds its own gem_create_ext extension, | ||||||
|  | which basically lets userspace mark a buffer as "protected". | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: include/uapi/drm/i915_drm.h | ||||||
|  |         :functions: drm_i915_gem_create_ext | ||||||
|  | 
 | ||||||
|  | I915_GEM_CREATE_EXT_MEMORY_REGIONS | ||||||
|  | ---------------------------------- | ||||||
|  | Implemented as an extension for gem_create_ext, we would now allow userspace to | ||||||
|  | optionally provide an immutable list of preferred placements at creation time, | ||||||
|  | in priority order, for a given buffer object.  For the placements we expect | ||||||
|  | them each to use the class/instance encoding, as per the output of the regions | ||||||
|  | query. Having the list in priority order will be useful in the future when | ||||||
|  | placing an object, say during eviction. | ||||||
|  | 
 | ||||||
|  | .. kernel-doc:: include/uapi/drm/i915_drm.h | ||||||
|  |         :functions: drm_i915_gem_create_ext_memory_regions | ||||||
|  | 
 | ||||||
|  | One fair criticism here is that this seems a little over-engineered[2]. If we | ||||||
|  | just consider DG1 then yes, a simple gem_create.flags or something is totally | ||||||
|  | all that's needed to tell the kernel to allocate the buffer in local-memory or | ||||||
|  | whatever. However looking to the future we need uAPI which can also support | ||||||
|  | upcoming Xe HP multi-tile architecture in a sane way, where there can be | ||||||
|  | multiple local-memory instances for a given device, and so using both class and | ||||||
|  | instance in our uAPI to describe regions is desirable, although specifically | ||||||
|  | for DG1 it's uninteresting, since we only have a single local-memory instance. | ||||||
|  | 
 | ||||||
|  | Existing uAPI issues | ||||||
|  | ==================== | ||||||
|  | Some potential issues we still need to resolve. | ||||||
|  | 
 | ||||||
|  | I915 MMAP | ||||||
|  | --------- | ||||||
|  | In i915 there are multiple ways to MMAP GEM object, including mapping the same | ||||||
|  | object using different mapping types(WC vs WB), i.e multiple active mmaps per | ||||||
|  | object. TTM expects one MMAP at most for the lifetime of the object. If it | ||||||
|  | turns out that we have to backpedal here, there might be some potential | ||||||
|  | userspace fallout. | ||||||
|  | 
 | ||||||
|  | I915 SET/GET CACHING | ||||||
|  | -------------------- | ||||||
|  | In i915 we have set/get_caching ioctl. TTM doesn't let us to change this, but | ||||||
|  | DG1 doesn't support non-snooped pcie transactions, so we can just always | ||||||
|  | allocate as WB for smem-only buffers.  If/when our hw gains support for | ||||||
|  | non-snooped pcie transactions then we must fix this mode at allocation time as | ||||||
|  | a new GEM extension. | ||||||
|  | 
 | ||||||
|  | This is related to the mmap problem, because in general (meaning, when we're | ||||||
|  | not running on intel cpus) the cpu mmap must not, ever, be inconsistent with | ||||||
|  | allocation mode. | ||||||
|  | 
 | ||||||
|  | Possible idea is to let the kernel picks the mmap mode for userspace from the | ||||||
|  | following table: | ||||||
|  | 
 | ||||||
|  | smem-only: WB. Userspace does not need to call clflush. | ||||||
|  | 
 | ||||||
|  | smem+lmem: We only ever allow a single mode, so simply allocate this as uncached | ||||||
|  | memory, and always give userspace a WC mapping. GPU still does snooped access | ||||||
|  | here(assuming we can't turn it off like on DG1), which is a bit inefficient. | ||||||
|  | 
 | ||||||
|  | lmem only: always WC | ||||||
|  | 
 | ||||||
|  | This means on discrete you only get a single mmap mode, all others must be | ||||||
|  | rejected. That's probably going to be a new default mode or something like | ||||||
|  | that. | ||||||
|  | 
 | ||||||
|  | Links | ||||||
|  | ===== | ||||||
|  | [1] https://patchwork.freedesktop.org/series/86798/ | ||||||
|  | 
 | ||||||
|  | [2] https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5599#note_553791 | ||||||
| @ -15,3 +15,7 @@ host such documentation: | |||||||
| 
 | 
 | ||||||
| * Once the code has landed move all the documentation to the right places in | * Once the code has landed move all the documentation to the right places in | ||||||
|   the main core, helper or driver sections. |   the main core, helper or driver sections. | ||||||
|  | 
 | ||||||
|  | .. toctree:: | ||||||
|  | 
 | ||||||
|  |     i915_gem_lmem.rst | ||||||
|  | |||||||
| @ -546,6 +546,8 @@ There's a bunch of issues with it: | |||||||
|   this (together with the drm_minor->drm_device move) would allow us to remove |   this (together with the drm_minor->drm_device move) would allow us to remove | ||||||
|   debugfs_init. |   debugfs_init. | ||||||
| 
 | 
 | ||||||
|  | Previous RFC that hasn't landed yet: https://lore.kernel.org/dri-devel/20200513114130.28641-2-wambui.karugax@gmail.com/ | ||||||
|  | 
 | ||||||
| Contact: Daniel Vetter | Contact: Daniel Vetter | ||||||
| 
 | 
 | ||||||
| Level: Intermediate | Level: Intermediate | ||||||
|  | |||||||
							
								
								
									
										30
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								MAINTAINERS
									
									
									
									
									
								
							| @ -878,7 +878,7 @@ M:	Harry Wentland <harry.wentland@amd.com> | |||||||
| M:	Leo Li <sunpeng.li@amd.com> | M:	Leo Li <sunpeng.li@amd.com> | ||||||
| L:	amd-gfx@lists.freedesktop.org | L:	amd-gfx@lists.freedesktop.org | ||||||
| S:	Supported | S:	Supported | ||||||
| T:	git git://people.freedesktop.org/~agd5f/linux | T:	git https://gitlab.freedesktop.org/agd5f/linux.git | ||||||
| F:	drivers/gpu/drm/amd/display/ | F:	drivers/gpu/drm/amd/display/ | ||||||
| 
 | 
 | ||||||
| AMD FAM15H PROCESSOR POWER MONITORING DRIVER | AMD FAM15H PROCESSOR POWER MONITORING DRIVER | ||||||
| @ -954,7 +954,7 @@ AMD POWERPLAY | |||||||
| M:	Evan Quan <evan.quan@amd.com> | M:	Evan Quan <evan.quan@amd.com> | ||||||
| L:	amd-gfx@lists.freedesktop.org | L:	amd-gfx@lists.freedesktop.org | ||||||
| S:	Supported | S:	Supported | ||||||
| T:	git git://people.freedesktop.org/~agd5f/linux | T:	git https://gitlab.freedesktop.org/agd5f/linux.git | ||||||
| F:	drivers/gpu/drm/amd/pm/powerplay/ | F:	drivers/gpu/drm/amd/pm/powerplay/ | ||||||
| 
 | 
 | ||||||
| AMD SEATTLE DEVICE TREE SUPPORT | AMD SEATTLE DEVICE TREE SUPPORT | ||||||
| @ -5912,6 +5912,13 @@ S:	Orphan / Obsolete | |||||||
| F:	drivers/gpu/drm/savage/ | F:	drivers/gpu/drm/savage/ | ||||||
| F:	include/uapi/drm/savage_drm.h | F:	include/uapi/drm/savage_drm.h | ||||||
| 
 | 
 | ||||||
|  | DRM DRIVER FOR SIMPLE FRAMEBUFFERS | ||||||
|  | M:	Thomas Zimmermann <tzimmermann@suse.de> | ||||||
|  | L:	dri-devel@lists.freedesktop.org | ||||||
|  | S:	Maintained | ||||||
|  | T:	git git://anongit.freedesktop.org/drm/drm-misc | ||||||
|  | F:	drivers/gpu/drm/tiny/simpledrm.c | ||||||
|  | 
 | ||||||
| DRM DRIVER FOR SIS VIDEO CARDS | DRM DRIVER FOR SIS VIDEO CARDS | ||||||
| S:	Orphan / Obsolete | S:	Orphan / Obsolete | ||||||
| F:	drivers/gpu/drm/sis/ | F:	drivers/gpu/drm/sis/ | ||||||
| @ -6119,6 +6126,14 @@ T:	git git://anongit.freedesktop.org/drm/drm-misc | |||||||
| F:	Documentation/devicetree/bindings/display/hisilicon/ | F:	Documentation/devicetree/bindings/display/hisilicon/ | ||||||
| F:	drivers/gpu/drm/hisilicon/ | F:	drivers/gpu/drm/hisilicon/ | ||||||
| 
 | 
 | ||||||
|  | DRM DRIVER FOR HYPERV SYNTHETIC VIDEO DEVICE | ||||||
|  | M:	Deepak Rawat <drawat.floss@gmail.com> | ||||||
|  | L:	linux-hyperv@vger.kernel.org | ||||||
|  | L:	dri-devel@lists.freedesktop.org | ||||||
|  | S:	Maintained | ||||||
|  | T:	git git://anongit.freedesktop.org/drm/drm-misc | ||||||
|  | F:	drivers/gpu/drm/hyperv | ||||||
|  | 
 | ||||||
| DRM DRIVERS FOR LIMA | DRM DRIVERS FOR LIMA | ||||||
| M:	Qiang Yu <yuq825@gmail.com> | M:	Qiang Yu <yuq825@gmail.com> | ||||||
| L:	dri-devel@lists.freedesktop.org | L:	dri-devel@lists.freedesktop.org | ||||||
| @ -6281,7 +6296,7 @@ M:	Christian Koenig <christian.koenig@amd.com> | |||||||
| M:	Huang Rui <ray.huang@amd.com> | M:	Huang Rui <ray.huang@amd.com> | ||||||
| L:	dri-devel@lists.freedesktop.org | L:	dri-devel@lists.freedesktop.org | ||||||
| S:	Maintained | S:	Maintained | ||||||
| T:	git git://people.freedesktop.org/~agd5f/linux | T:	git git://anongit.freedesktop.org/drm/drm-misc | ||||||
| F:	drivers/gpu/drm/ttm/ | F:	drivers/gpu/drm/ttm/ | ||||||
| F:	include/drm/ttm/ | F:	include/drm/ttm/ | ||||||
| 
 | 
 | ||||||
| @ -9773,6 +9788,14 @@ Q:	http://patchwork.linuxtv.org/project/linux-media/list/ | |||||||
| T:	git git://linuxtv.org/anttip/media_tree.git | T:	git git://linuxtv.org/anttip/media_tree.git | ||||||
| F:	drivers/media/tuners/it913x* | F:	drivers/media/tuners/it913x* | ||||||
| 
 | 
 | ||||||
|  | ITE IT66121 HDMI BRIDGE DRIVER | ||||||
|  | M:	Phong LE <ple@baylibre.com> | ||||||
|  | M:	Neil Armstrong <narmstrong@baylibre.com> | ||||||
|  | S:	Maintained | ||||||
|  | T:	git git://anongit.freedesktop.org/drm/drm-misc | ||||||
|  | F:	Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml | ||||||
|  | F:	drivers/gpu/drm/bridge/ite-it66121.c | ||||||
|  | 
 | ||||||
| IVTV VIDEO4LINUX DRIVER | IVTV VIDEO4LINUX DRIVER | ||||||
| M:	Andy Walls <awalls@md.metrocast.net> | M:	Andy Walls <awalls@md.metrocast.net> | ||||||
| L:	linux-media@vger.kernel.org | L:	linux-media@vger.kernel.org | ||||||
| @ -15336,6 +15359,7 @@ F:	drivers/net/wireless/quantenna | |||||||
| RADEON and AMDGPU DRM DRIVERS | RADEON and AMDGPU DRM DRIVERS | ||||||
| M:	Alex Deucher <alexander.deucher@amd.com> | M:	Alex Deucher <alexander.deucher@amd.com> | ||||||
| M:	Christian König <christian.koenig@amd.com> | M:	Christian König <christian.koenig@amd.com> | ||||||
|  | M:	Pan, Xinhui <Xinhui.Pan@amd.com> | ||||||
| L:	amd-gfx@lists.freedesktop.org | L:	amd-gfx@lists.freedesktop.org | ||||||
| S:	Supported | S:	Supported | ||||||
| T:	git https://gitlab.freedesktop.org/agd5f/linux.git | T:	git https://gitlab.freedesktop.org/agd5f/linux.git | ||||||
|  | |||||||
| @ -549,9 +549,11 @@ static const struct pci_device_id intel_early_ids[] __initconst = { | |||||||
| 	INTEL_CNL_IDS(&gen9_early_ops), | 	INTEL_CNL_IDS(&gen9_early_ops), | ||||||
| 	INTEL_ICL_11_IDS(&gen11_early_ops), | 	INTEL_ICL_11_IDS(&gen11_early_ops), | ||||||
| 	INTEL_EHL_IDS(&gen11_early_ops), | 	INTEL_EHL_IDS(&gen11_early_ops), | ||||||
|  | 	INTEL_JSL_IDS(&gen11_early_ops), | ||||||
| 	INTEL_TGL_12_IDS(&gen11_early_ops), | 	INTEL_TGL_12_IDS(&gen11_early_ops), | ||||||
| 	INTEL_RKL_IDS(&gen11_early_ops), | 	INTEL_RKL_IDS(&gen11_early_ops), | ||||||
| 	INTEL_ADLS_IDS(&gen11_early_ops), | 	INTEL_ADLS_IDS(&gen11_early_ops), | ||||||
|  | 	INTEL_ADLP_IDS(&gen11_early_ops), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0); | struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0); | ||||||
|  | |||||||
| @ -234,7 +234,7 @@ retry: | |||||||
| 		shared_count = fobj->shared_count; | 		shared_count = fobj->shared_count; | ||||||
| 	else | 	else | ||||||
| 		shared_count = 0; | 		shared_count = 0; | ||||||
| 	fence_excl = rcu_dereference(resv->fence_excl); | 	fence_excl = dma_resv_excl_fence(resv); | ||||||
| 	if (read_seqcount_retry(&resv->seq, seq)) { | 	if (read_seqcount_retry(&resv->seq, seq)) { | ||||||
| 		rcu_read_unlock(); | 		rcu_read_unlock(); | ||||||
| 		goto retry; | 		goto retry; | ||||||
| @ -1147,8 +1147,7 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf, | |||||||
| 	long ret; | 	long ret; | ||||||
| 
 | 
 | ||||||
| 	/* Wait on any implicit rendering fences */ | 	/* Wait on any implicit rendering fences */ | ||||||
| 	ret = dma_resv_wait_timeout_rcu(resv, write, true, | 	ret = dma_resv_wait_timeout(resv, write, true, MAX_SCHEDULE_TIMEOUT); | ||||||
| 						  MAX_SCHEDULE_TIMEOUT); |  | ||||||
| 	if (ret < 0) | 	if (ret < 0) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| @ -1349,15 +1348,14 @@ EXPORT_SYMBOL_GPL(dma_buf_vunmap); | |||||||
| #ifdef CONFIG_DEBUG_FS | #ifdef CONFIG_DEBUG_FS | ||||||
| static int dma_buf_debug_show(struct seq_file *s, void *unused) | static int dma_buf_debug_show(struct seq_file *s, void *unused) | ||||||
| { | { | ||||||
| 	int ret; |  | ||||||
| 	struct dma_buf *buf_obj; | 	struct dma_buf *buf_obj; | ||||||
| 	struct dma_buf_attachment *attach_obj; | 	struct dma_buf_attachment *attach_obj; | ||||||
| 	struct dma_resv *robj; | 	struct dma_resv *robj; | ||||||
| 	struct dma_resv_list *fobj; | 	struct dma_resv_list *fobj; | ||||||
| 	struct dma_fence *fence; | 	struct dma_fence *fence; | ||||||
| 	unsigned seq; |  | ||||||
| 	int count = 0, attach_count, shared_count, i; | 	int count = 0, attach_count, shared_count, i; | ||||||
| 	size_t size = 0; | 	size_t size = 0; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	ret = mutex_lock_interruptible(&db_list.lock); | 	ret = mutex_lock_interruptible(&db_list.lock); | ||||||
| 
 | 
 | ||||||
| @ -1383,33 +1381,24 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) | |||||||
| 				buf_obj->name ?: ""); | 				buf_obj->name ?: ""); | ||||||
| 
 | 
 | ||||||
| 		robj = buf_obj->resv; | 		robj = buf_obj->resv; | ||||||
| 		while (true) { | 		fence = dma_resv_excl_fence(robj); | ||||||
| 			seq = read_seqcount_begin(&robj->seq); |  | ||||||
| 			rcu_read_lock(); |  | ||||||
| 			fobj = rcu_dereference(robj->fence); |  | ||||||
| 			shared_count = fobj ? fobj->shared_count : 0; |  | ||||||
| 			fence = rcu_dereference(robj->fence_excl); |  | ||||||
| 			if (!read_seqcount_retry(&robj->seq, seq)) |  | ||||||
| 				break; |  | ||||||
| 			rcu_read_unlock(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (fence) | 		if (fence) | ||||||
| 			seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n", | 			seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n", | ||||||
| 				   fence->ops->get_driver_name(fence), | 				   fence->ops->get_driver_name(fence), | ||||||
| 				   fence->ops->get_timeline_name(fence), | 				   fence->ops->get_timeline_name(fence), | ||||||
| 				   dma_fence_is_signaled(fence) ? "" : "un"); | 				   dma_fence_is_signaled(fence) ? "" : "un"); | ||||||
|  | 
 | ||||||
|  | 		fobj = rcu_dereference_protected(robj->fence, | ||||||
|  | 						 dma_resv_held(robj)); | ||||||
|  | 		shared_count = fobj ? fobj->shared_count : 0; | ||||||
| 		for (i = 0; i < shared_count; i++) { | 		for (i = 0; i < shared_count; i++) { | ||||||
| 			fence = rcu_dereference(fobj->shared[i]); | 			fence = rcu_dereference_protected(fobj->shared[i], | ||||||
| 			if (!dma_fence_get_rcu(fence)) | 							  dma_resv_held(robj)); | ||||||
| 				continue; |  | ||||||
| 			seq_printf(s, "\tShared fence: %s %s %ssignalled\n", | 			seq_printf(s, "\tShared fence: %s %s %ssignalled\n", | ||||||
| 				   fence->ops->get_driver_name(fence), | 				   fence->ops->get_driver_name(fence), | ||||||
| 				   fence->ops->get_timeline_name(fence), | 				   fence->ops->get_timeline_name(fence), | ||||||
| 				   dma_fence_is_signaled(fence) ? "" : "un"); | 				   dma_fence_is_signaled(fence) ? "" : "un"); | ||||||
| 			dma_fence_put(fence); |  | ||||||
| 		} | 		} | ||||||
| 		rcu_read_unlock(); |  | ||||||
| 
 | 
 | ||||||
| 		seq_puts(s, "\tAttached Devices:\n"); | 		seq_puts(s, "\tAttached Devices:\n"); | ||||||
| 		attach_count = 0; | 		attach_count = 0; | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | // SPDX-License-Identifier: MIT
 | ||||||
| /*
 | /*
 | ||||||
|  * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst) |  * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst) | ||||||
|  * |  * | ||||||
| @ -92,49 +93,6 @@ static void dma_resv_list_free(struct dma_resv_list *list) | |||||||
| 	kfree_rcu(list, rcu); | 	kfree_rcu(list, rcu); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #if IS_ENABLED(CONFIG_LOCKDEP) |  | ||||||
| static int __init dma_resv_lockdep(void) |  | ||||||
| { |  | ||||||
| 	struct mm_struct *mm = mm_alloc(); |  | ||||||
| 	struct ww_acquire_ctx ctx; |  | ||||||
| 	struct dma_resv obj; |  | ||||||
| 	struct address_space mapping; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	if (!mm) |  | ||||||
| 		return -ENOMEM; |  | ||||||
| 
 |  | ||||||
| 	dma_resv_init(&obj); |  | ||||||
| 	address_space_init_once(&mapping); |  | ||||||
| 
 |  | ||||||
| 	mmap_read_lock(mm); |  | ||||||
| 	ww_acquire_init(&ctx, &reservation_ww_class); |  | ||||||
| 	ret = dma_resv_lock(&obj, &ctx); |  | ||||||
| 	if (ret == -EDEADLK) |  | ||||||
| 		dma_resv_lock_slow(&obj, &ctx); |  | ||||||
| 	fs_reclaim_acquire(GFP_KERNEL); |  | ||||||
| 	/* for unmap_mapping_range on trylocked buffer objects in shrinkers */ |  | ||||||
| 	i_mmap_lock_write(&mapping); |  | ||||||
| 	i_mmap_unlock_write(&mapping); |  | ||||||
| #ifdef CONFIG_MMU_NOTIFIER |  | ||||||
| 	lock_map_acquire(&__mmu_notifier_invalidate_range_start_map); |  | ||||||
| 	__dma_fence_might_wait(); |  | ||||||
| 	lock_map_release(&__mmu_notifier_invalidate_range_start_map); |  | ||||||
| #else |  | ||||||
| 	__dma_fence_might_wait(); |  | ||||||
| #endif |  | ||||||
| 	fs_reclaim_release(GFP_KERNEL); |  | ||||||
| 	ww_mutex_unlock(&obj.lock); |  | ||||||
| 	ww_acquire_fini(&ctx); |  | ||||||
| 	mmap_read_unlock(mm); |  | ||||||
| 	 |  | ||||||
| 	mmput(mm); |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| subsys_initcall(dma_resv_lockdep); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * dma_resv_init - initialize a reservation object |  * dma_resv_init - initialize a reservation object | ||||||
|  * @obj: the reservation object |  * @obj: the reservation object | ||||||
| @ -191,14 +149,11 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences) | |||||||
| 
 | 
 | ||||||
| 	dma_resv_assert_held(obj); | 	dma_resv_assert_held(obj); | ||||||
| 
 | 
 | ||||||
| 	old = dma_resv_get_list(obj); | 	old = dma_resv_shared_list(obj); | ||||||
| 
 |  | ||||||
| 	if (old && old->shared_max) { | 	if (old && old->shared_max) { | ||||||
| 		if ((old->shared_count + num_fences) <= old->shared_max) | 		if ((old->shared_count + num_fences) <= old->shared_max) | ||||||
| 			return 0; | 			return 0; | ||||||
| 		else | 		max = max(old->shared_count + num_fences, old->shared_max * 2); | ||||||
| 			max = max(old->shared_count + num_fences, |  | ||||||
| 				  old->shared_max * 2); |  | ||||||
| 	} else { | 	} else { | ||||||
| 		max = max(4ul, roundup_pow_of_two(num_fences)); | 		max = max(4ul, roundup_pow_of_two(num_fences)); | ||||||
| 	} | 	} | ||||||
| @ -252,6 +207,28 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences) | |||||||
| } | } | ||||||
| EXPORT_SYMBOL(dma_resv_reserve_shared); | EXPORT_SYMBOL(dma_resv_reserve_shared); | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_DEBUG_MUTEXES | ||||||
|  | /**
 | ||||||
|  |  * dma_resv_reset_shared_max - reset shared fences for debugging | ||||||
|  |  * @obj: the dma_resv object to reset | ||||||
|  |  * | ||||||
|  |  * Reset the number of pre-reserved shared slots to test that drivers do | ||||||
|  |  * correct slot allocation using dma_resv_reserve_shared(). See also | ||||||
|  |  * &dma_resv_list.shared_max. | ||||||
|  |  */ | ||||||
|  | void dma_resv_reset_shared_max(struct dma_resv *obj) | ||||||
|  | { | ||||||
|  | 	struct dma_resv_list *fences = dma_resv_shared_list(obj); | ||||||
|  | 
 | ||||||
|  | 	dma_resv_assert_held(obj); | ||||||
|  | 
 | ||||||
|  | 	/* Test shared fence slot reservation */ | ||||||
|  | 	if (fences) | ||||||
|  | 		fences->shared_max = fences->shared_count; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(dma_resv_reset_shared_max); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * dma_resv_add_shared_fence - Add a fence to a shared slot |  * dma_resv_add_shared_fence - Add a fence to a shared slot | ||||||
|  * @obj: the reservation object |  * @obj: the reservation object | ||||||
| @ -270,7 +247,7 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence) | |||||||
| 
 | 
 | ||||||
| 	dma_resv_assert_held(obj); | 	dma_resv_assert_held(obj); | ||||||
| 
 | 
 | ||||||
| 	fobj = dma_resv_get_list(obj); | 	fobj = dma_resv_shared_list(obj); | ||||||
| 	count = fobj->shared_count; | 	count = fobj->shared_count; | ||||||
| 
 | 
 | ||||||
| 	write_seqcount_begin(&obj->seq); | 	write_seqcount_begin(&obj->seq); | ||||||
| @ -307,13 +284,13 @@ EXPORT_SYMBOL(dma_resv_add_shared_fence); | |||||||
|  */ |  */ | ||||||
| void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence) | void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence) | ||||||
| { | { | ||||||
| 	struct dma_fence *old_fence = dma_resv_get_excl(obj); | 	struct dma_fence *old_fence = dma_resv_excl_fence(obj); | ||||||
| 	struct dma_resv_list *old; | 	struct dma_resv_list *old; | ||||||
| 	u32 i = 0; | 	u32 i = 0; | ||||||
| 
 | 
 | ||||||
| 	dma_resv_assert_held(obj); | 	dma_resv_assert_held(obj); | ||||||
| 
 | 
 | ||||||
| 	old = dma_resv_get_list(obj); | 	old = dma_resv_shared_list(obj); | ||||||
| 	if (old) | 	if (old) | ||||||
| 		i = old->shared_count; | 		i = old->shared_count; | ||||||
| 
 | 
 | ||||||
| @ -347,16 +324,16 @@ int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src) | |||||||
| { | { | ||||||
| 	struct dma_resv_list *src_list, *dst_list; | 	struct dma_resv_list *src_list, *dst_list; | ||||||
| 	struct dma_fence *old, *new; | 	struct dma_fence *old, *new; | ||||||
| 	unsigned i; | 	unsigned int i; | ||||||
| 
 | 
 | ||||||
| 	dma_resv_assert_held(dst); | 	dma_resv_assert_held(dst); | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	src_list = rcu_dereference(src->fence); | 	src_list = dma_resv_shared_list(src); | ||||||
| 
 | 
 | ||||||
| retry: | retry: | ||||||
| 	if (src_list) { | 	if (src_list) { | ||||||
| 		unsigned shared_count = src_list->shared_count; | 		unsigned int shared_count = src_list->shared_count; | ||||||
| 
 | 
 | ||||||
| 		rcu_read_unlock(); | 		rcu_read_unlock(); | ||||||
| 
 | 
 | ||||||
| @ -365,7 +342,7 @@ retry: | |||||||
| 			return -ENOMEM; | 			return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 		rcu_read_lock(); | 		rcu_read_lock(); | ||||||
| 		src_list = rcu_dereference(src->fence); | 		src_list = dma_resv_shared_list(src); | ||||||
| 		if (!src_list || src_list->shared_count > shared_count) { | 		if (!src_list || src_list->shared_count > shared_count) { | ||||||
| 			kfree(dst_list); | 			kfree(dst_list); | ||||||
| 			goto retry; | 			goto retry; | ||||||
| @ -373,6 +350,7 @@ retry: | |||||||
| 
 | 
 | ||||||
| 		dst_list->shared_count = 0; | 		dst_list->shared_count = 0; | ||||||
| 		for (i = 0; i < src_list->shared_count; ++i) { | 		for (i = 0; i < src_list->shared_count; ++i) { | ||||||
|  | 			struct dma_fence __rcu **dst; | ||||||
| 			struct dma_fence *fence; | 			struct dma_fence *fence; | ||||||
| 
 | 
 | ||||||
| 			fence = rcu_dereference(src_list->shared[i]); | 			fence = rcu_dereference(src_list->shared[i]); | ||||||
| @ -382,7 +360,7 @@ retry: | |||||||
| 
 | 
 | ||||||
| 			if (!dma_fence_get_rcu(fence)) { | 			if (!dma_fence_get_rcu(fence)) { | ||||||
| 				dma_resv_list_free(dst_list); | 				dma_resv_list_free(dst_list); | ||||||
| 				src_list = rcu_dereference(src->fence); | 				src_list = dma_resv_shared_list(src); | ||||||
| 				goto retry; | 				goto retry; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| @ -391,7 +369,8 @@ retry: | |||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence); | 			dst = &dst_list->shared[dst_list->shared_count++]; | ||||||
|  | 			rcu_assign_pointer(*dst, fence); | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		dst_list = NULL; | 		dst_list = NULL; | ||||||
| @ -400,8 +379,8 @@ retry: | |||||||
| 	new = dma_fence_get_rcu_safe(&src->fence_excl); | 	new = dma_fence_get_rcu_safe(&src->fence_excl); | ||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 
 | 
 | ||||||
| 	src_list = dma_resv_get_list(dst); | 	src_list = dma_resv_shared_list(dst); | ||||||
| 	old = dma_resv_get_excl(dst); | 	old = dma_resv_excl_fence(dst); | ||||||
| 
 | 
 | ||||||
| 	write_seqcount_begin(&dst->seq); | 	write_seqcount_begin(&dst->seq); | ||||||
| 	/* write_seqcount_begin provides the necessary memory barrier */ | 	/* write_seqcount_begin provides the necessary memory barrier */ | ||||||
| @ -417,7 +396,7 @@ retry: | |||||||
| EXPORT_SYMBOL(dma_resv_copy_fences); | EXPORT_SYMBOL(dma_resv_copy_fences); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * dma_resv_get_fences_rcu - Get an object's shared and exclusive |  * dma_resv_get_fences - Get an object's shared and exclusive | ||||||
|  * fences without update side lock held |  * fences without update side lock held | ||||||
|  * @obj: the reservation object |  * @obj: the reservation object | ||||||
|  * @pfence_excl: the returned exclusive fence (or NULL) |  * @pfence_excl: the returned exclusive fence (or NULL) | ||||||
| @ -429,9 +408,8 @@ EXPORT_SYMBOL(dma_resv_copy_fences); | |||||||
|  * exclusive fence is not specified the fence is put into the array of the |  * exclusive fence is not specified the fence is put into the array of the | ||||||
|  * shared fences as well. Returns either zero or -ENOMEM. |  * shared fences as well. Returns either zero or -ENOMEM. | ||||||
|  */ |  */ | ||||||
| int dma_resv_get_fences_rcu(struct dma_resv *obj, | int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, | ||||||
| 			    struct dma_fence **pfence_excl, | 			unsigned int *pshared_count, | ||||||
| 			    unsigned *pshared_count, |  | ||||||
| 			struct dma_fence ***pshared) | 			struct dma_fence ***pshared) | ||||||
| { | { | ||||||
| 	struct dma_fence **shared = NULL; | 	struct dma_fence **shared = NULL; | ||||||
| @ -449,11 +427,11 @@ int dma_resv_get_fences_rcu(struct dma_resv *obj, | |||||||
| 		rcu_read_lock(); | 		rcu_read_lock(); | ||||||
| 		seq = read_seqcount_begin(&obj->seq); | 		seq = read_seqcount_begin(&obj->seq); | ||||||
| 
 | 
 | ||||||
| 		fence_excl = rcu_dereference(obj->fence_excl); | 		fence_excl = dma_resv_excl_fence(obj); | ||||||
| 		if (fence_excl && !dma_fence_get_rcu(fence_excl)) | 		if (fence_excl && !dma_fence_get_rcu(fence_excl)) | ||||||
| 			goto unlock; | 			goto unlock; | ||||||
| 
 | 
 | ||||||
| 		fobj = rcu_dereference(obj->fence); | 		fobj = dma_resv_shared_list(obj); | ||||||
| 		if (fobj) | 		if (fobj) | ||||||
| 			sz += sizeof(*shared) * fobj->shared_max; | 			sz += sizeof(*shared) * fobj->shared_max; | ||||||
| 
 | 
 | ||||||
| @ -515,27 +493,28 @@ unlock: | |||||||
| 	*pshared = shared; | 	*pshared = shared; | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu); | EXPORT_SYMBOL_GPL(dma_resv_get_fences); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * dma_resv_wait_timeout_rcu - Wait on reservation's objects |  * dma_resv_wait_timeout - Wait on reservation's objects | ||||||
|  * shared and/or exclusive fences. |  * shared and/or exclusive fences. | ||||||
|  * @obj: the reservation object |  * @obj: the reservation object | ||||||
|  * @wait_all: if true, wait on all fences, else wait on just exclusive fence |  * @wait_all: if true, wait on all fences, else wait on just exclusive fence | ||||||
|  * @intr: if true, do interruptible wait |  * @intr: if true, do interruptible wait | ||||||
|  * @timeout: timeout value in jiffies or zero to return immediately |  * @timeout: timeout value in jiffies or zero to return immediately | ||||||
|  * |  * | ||||||
|  |  * Callers are not required to hold specific locks, but maybe hold | ||||||
|  |  * dma_resv_lock() already | ||||||
|  * RETURNS |  * RETURNS | ||||||
|  * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or |  * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or | ||||||
|  * greater than zer on success. |  * greater than zer on success. | ||||||
|  */ |  */ | ||||||
| long dma_resv_wait_timeout_rcu(struct dma_resv *obj, | long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, | ||||||
| 			       bool wait_all, bool intr, |  | ||||||
| 			   unsigned long timeout) | 			   unsigned long timeout) | ||||||
| { | { | ||||||
| 	struct dma_fence *fence; |  | ||||||
| 	unsigned seq, shared_count; |  | ||||||
| 	long ret = timeout ? timeout : 1; | 	long ret = timeout ? timeout : 1; | ||||||
|  | 	unsigned int seq, shared_count; | ||||||
|  | 	struct dma_fence *fence; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| retry: | retry: | ||||||
| @ -544,7 +523,7 @@ retry: | |||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| 	i = -1; | 	i = -1; | ||||||
| 
 | 
 | ||||||
| 	fence = rcu_dereference(obj->fence_excl); | 	fence = dma_resv_excl_fence(obj); | ||||||
| 	if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { | 	if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { | ||||||
| 		if (!dma_fence_get_rcu(fence)) | 		if (!dma_fence_get_rcu(fence)) | ||||||
| 			goto unlock_retry; | 			goto unlock_retry; | ||||||
| @ -559,14 +538,15 @@ retry: | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (wait_all) { | 	if (wait_all) { | ||||||
| 		struct dma_resv_list *fobj = rcu_dereference(obj->fence); | 		struct dma_resv_list *fobj = dma_resv_shared_list(obj); | ||||||
| 
 | 
 | ||||||
| 		if (fobj) | 		if (fobj) | ||||||
| 			shared_count = fobj->shared_count; | 			shared_count = fobj->shared_count; | ||||||
| 
 | 
 | ||||||
| 		for (i = 0; !fence && i < shared_count; ++i) { | 		for (i = 0; !fence && i < shared_count; ++i) { | ||||||
| 			struct dma_fence *lfence = rcu_dereference(fobj->shared[i]); | 			struct dma_fence *lfence; | ||||||
| 
 | 
 | ||||||
|  | 			lfence = rcu_dereference(fobj->shared[i]); | ||||||
| 			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, | 			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, | ||||||
| 				     &lfence->flags)) | 				     &lfence->flags)) | ||||||
| 				continue; | 				continue; | ||||||
| @ -602,7 +582,7 @@ unlock_retry: | |||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 	goto retry; | 	goto retry; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu); | EXPORT_SYMBOL_GPL(dma_resv_wait_timeout); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) | static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) | ||||||
| @ -622,18 +602,20 @@ static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * dma_resv_test_signaled_rcu - Test if a reservation object's |  * dma_resv_test_signaled - Test if a reservation object's fences have been | ||||||
|  * fences have been signaled. |  * signaled. | ||||||
|  * @obj: the reservation object |  * @obj: the reservation object | ||||||
|  * @test_all: if true, test all fences, otherwise only test the exclusive |  * @test_all: if true, test all fences, otherwise only test the exclusive | ||||||
|  * fence |  * fence | ||||||
|  * |  * | ||||||
|  |  * Callers are not required to hold specific locks, but maybe hold | ||||||
|  |  * dma_resv_lock() already | ||||||
|  * RETURNS |  * RETURNS | ||||||
|  * true if all fences signaled, else false |  * true if all fences signaled, else false | ||||||
|  */ |  */ | ||||||
| bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool test_all) | bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all) | ||||||
| { | { | ||||||
| 	unsigned seq, shared_count; | 	unsigned int seq, shared_count; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	rcu_read_lock(); | 	rcu_read_lock(); | ||||||
| @ -643,16 +625,16 @@ retry: | |||||||
| 	seq = read_seqcount_begin(&obj->seq); | 	seq = read_seqcount_begin(&obj->seq); | ||||||
| 
 | 
 | ||||||
| 	if (test_all) { | 	if (test_all) { | ||||||
| 		unsigned i; | 		struct dma_resv_list *fobj = dma_resv_shared_list(obj); | ||||||
| 
 | 		unsigned int i; | ||||||
| 		struct dma_resv_list *fobj = rcu_dereference(obj->fence); |  | ||||||
| 
 | 
 | ||||||
| 		if (fobj) | 		if (fobj) | ||||||
| 			shared_count = fobj->shared_count; | 			shared_count = fobj->shared_count; | ||||||
| 
 | 
 | ||||||
| 		for (i = 0; i < shared_count; ++i) { | 		for (i = 0; i < shared_count; ++i) { | ||||||
| 			struct dma_fence *fence = rcu_dereference(fobj->shared[i]); | 			struct dma_fence *fence; | ||||||
| 
 | 
 | ||||||
|  | 			fence = rcu_dereference(fobj->shared[i]); | ||||||
| 			ret = dma_resv_test_signaled_single(fence); | 			ret = dma_resv_test_signaled_single(fence); | ||||||
| 			if (ret < 0) | 			if (ret < 0) | ||||||
| 				goto retry; | 				goto retry; | ||||||
| @ -665,7 +647,7 @@ retry: | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!shared_count) { | 	if (!shared_count) { | ||||||
| 		struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl); | 		struct dma_fence *fence_excl = dma_resv_excl_fence(obj); | ||||||
| 
 | 
 | ||||||
| 		if (fence_excl) { | 		if (fence_excl) { | ||||||
| 			ret = dma_resv_test_signaled_single(fence_excl); | 			ret = dma_resv_test_signaled_single(fence_excl); | ||||||
| @ -680,4 +662,47 @@ retry: | |||||||
| 	rcu_read_unlock(); | 	rcu_read_unlock(); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu); | EXPORT_SYMBOL_GPL(dma_resv_test_signaled); | ||||||
|  | 
 | ||||||
|  | #if IS_ENABLED(CONFIG_LOCKDEP) | ||||||
|  | static int __init dma_resv_lockdep(void) | ||||||
|  | { | ||||||
|  | 	struct mm_struct *mm = mm_alloc(); | ||||||
|  | 	struct ww_acquire_ctx ctx; | ||||||
|  | 	struct dma_resv obj; | ||||||
|  | 	struct address_space mapping; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (!mm) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	dma_resv_init(&obj); | ||||||
|  | 	address_space_init_once(&mapping); | ||||||
|  | 
 | ||||||
|  | 	mmap_read_lock(mm); | ||||||
|  | 	ww_acquire_init(&ctx, &reservation_ww_class); | ||||||
|  | 	ret = dma_resv_lock(&obj, &ctx); | ||||||
|  | 	if (ret == -EDEADLK) | ||||||
|  | 		dma_resv_lock_slow(&obj, &ctx); | ||||||
|  | 	fs_reclaim_acquire(GFP_KERNEL); | ||||||
|  | 	/* for unmap_mapping_range on trylocked buffer objects in shrinkers */ | ||||||
|  | 	i_mmap_lock_write(&mapping); | ||||||
|  | 	i_mmap_unlock_write(&mapping); | ||||||
|  | #ifdef CONFIG_MMU_NOTIFIER | ||||||
|  | 	lock_map_acquire(&__mmu_notifier_invalidate_range_start_map); | ||||||
|  | 	__dma_fence_might_wait(); | ||||||
|  | 	lock_map_release(&__mmu_notifier_invalidate_range_start_map); | ||||||
|  | #else | ||||||
|  | 	__dma_fence_might_wait(); | ||||||
|  | #endif | ||||||
|  | 	fs_reclaim_release(GFP_KERNEL); | ||||||
|  | 	ww_mutex_unlock(&obj.lock); | ||||||
|  | 	ww_acquire_fini(&ctx); | ||||||
|  | 	mmap_read_unlock(mm); | ||||||
|  | 
 | ||||||
|  | 	mmput(mm); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | subsys_initcall(dma_resv_lockdep); | ||||||
|  | #endif | ||||||
|  | |||||||
| @ -80,23 +80,6 @@ config DRM_KMS_HELPER | |||||||
| 	help | 	help | ||||||
| 	  CRTC helpers for KMS drivers. | 	  CRTC helpers for KMS drivers. | ||||||
| 
 | 
 | ||||||
| config DRM_KMS_FB_HELPER |  | ||||||
| 	bool |  | ||||||
| 	depends on DRM_KMS_HELPER |  | ||||||
| 	select FB |  | ||||||
| 	select FRAMEBUFFER_CONSOLE if !EXPERT |  | ||||||
| 	select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE |  | ||||||
| 	select FB_SYS_FOPS |  | ||||||
| 	select FB_SYS_FILLRECT |  | ||||||
| 	select FB_SYS_COPYAREA |  | ||||||
| 	select FB_SYS_IMAGEBLIT |  | ||||||
| 	select FB_CFB_FILLRECT |  | ||||||
| 	select FB_CFB_COPYAREA |  | ||||||
| 	select FB_CFB_IMAGEBLIT |  | ||||||
| 	select FB_DEFERRED_IO |  | ||||||
| 	help |  | ||||||
| 	  FBDEV helpers for KMS drivers. |  | ||||||
| 
 |  | ||||||
| config DRM_DEBUG_DP_MST_TOPOLOGY_REFS | config DRM_DEBUG_DP_MST_TOPOLOGY_REFS | ||||||
|         bool "Enable refcount backtrace history in the DP MST helpers" |         bool "Enable refcount backtrace history in the DP MST helpers" | ||||||
| 	depends on STACKTRACE_SUPPORT | 	depends on STACKTRACE_SUPPORT | ||||||
| @ -115,8 +98,18 @@ config DRM_DEBUG_DP_MST_TOPOLOGY_REFS | |||||||
| config DRM_FBDEV_EMULATION | config DRM_FBDEV_EMULATION | ||||||
| 	bool "Enable legacy fbdev support for your modesetting driver" | 	bool "Enable legacy fbdev support for your modesetting driver" | ||||||
| 	depends on DRM | 	depends on DRM | ||||||
|  | 	depends on FB | ||||||
| 	select DRM_KMS_HELPER | 	select DRM_KMS_HELPER | ||||||
| 	select DRM_KMS_FB_HELPER | 	select FB_CFB_FILLRECT | ||||||
|  | 	select FB_CFB_COPYAREA | ||||||
|  | 	select FB_CFB_IMAGEBLIT | ||||||
|  | 	select FB_DEFERRED_IO | ||||||
|  | 	select FB_SYS_FOPS | ||||||
|  | 	select FB_SYS_FILLRECT | ||||||
|  | 	select FB_SYS_COPYAREA | ||||||
|  | 	select FB_SYS_IMAGEBLIT | ||||||
|  | 	select FRAMEBUFFER_CONSOLE if !EXPERT | ||||||
|  | 	select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE | ||||||
| 	default y | 	default y | ||||||
| 	help | 	help | ||||||
| 	  Choose this option if you have a need for the legacy fbdev | 	  Choose this option if you have a need for the legacy fbdev | ||||||
| @ -386,6 +379,19 @@ source "drivers/gpu/drm/xlnx/Kconfig" | |||||||
| 
 | 
 | ||||||
| source "drivers/gpu/drm/gud/Kconfig" | source "drivers/gpu/drm/gud/Kconfig" | ||||||
| 
 | 
 | ||||||
|  | config DRM_HYPERV | ||||||
|  | 	tristate "DRM Support for Hyper-V synthetic video device" | ||||||
|  | 	depends on DRM && PCI && MMU && HYPERV | ||||||
|  | 	select DRM_KMS_HELPER | ||||||
|  | 	select DRM_GEM_SHMEM_HELPER | ||||||
|  | 	help | ||||||
|  | 	 This is a KMS driver for Hyper-V synthetic video device. Choose this | ||||||
|  | 	 option if you would like to enable drm driver for Hyper-V virtual | ||||||
|  | 	 machine. Unselect Hyper-V framebuffer driver (CONFIG_FB_HYPERV) so | ||||||
|  | 	 that DRM driver is used by default. | ||||||
|  | 
 | ||||||
|  | 	 If M is selected the module will be called hyperv_drm. | ||||||
|  | 
 | ||||||
| # Keep legacy drivers last | # Keep legacy drivers last | ||||||
| 
 | 
 | ||||||
| menuconfig DRM_LEGACY | menuconfig DRM_LEGACY | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ | |||||||
| # Makefile for the drm device driver.  This driver provides support for the
 | # Makefile for the drm device driver.  This driver provides support for the
 | ||||||
| # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 | # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 | ||||||
| 
 | 
 | ||||||
| drm-y       :=	drm_auth.o drm_cache.o \
 | drm-y       :=	drm_aperture.o drm_auth.o drm_cache.o \
 | ||||||
| 		drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \
 | 		drm_file.o drm_gem.o drm_ioctl.o drm_irq.o \
 | ||||||
| 		drm_drv.o \
 | 		drm_drv.o \
 | ||||||
| 		drm_sysfs.o drm_hashtab.o drm_mm.o \
 | 		drm_sysfs.o drm_hashtab.o drm_mm.o \
 | ||||||
| @ -20,15 +20,15 @@ drm-y       :=	drm_auth.o drm_cache.o \ | |||||||
| 		drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o \
 | 		drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o \
 | ||||||
| 		drm_managed.o drm_vblank_work.o | 		drm_managed.o drm_vblank_work.o | ||||||
| 
 | 
 | ||||||
| drm-$(CONFIG_DRM_LEGACY) += drm_bufs.o drm_context.o drm_dma.o drm_legacy_misc.o drm_lock.o \
 | drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.o \
 | ||||||
| 		drm_memory.o drm_scatter.o drm_vm.o | 			    drm_legacy_misc.o drm_lock.o drm_memory.o drm_scatter.o \
 | ||||||
|  | 			    drm_vm.o | ||||||
| drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o | drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o | ||||||
| drm-$(CONFIG_COMPAT) += drm_ioc32.o | drm-$(CONFIG_COMPAT) += drm_ioc32.o | ||||||
| drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | ||||||
| drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o | drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o | ||||||
| drm-$(CONFIG_DRM_PANEL) += drm_panel.o | drm-$(CONFIG_DRM_PANEL) += drm_panel.o | ||||||
| drm-$(CONFIG_OF) += drm_of.o | drm-$(CONFIG_OF) += drm_of.o | ||||||
| drm-$(CONFIG_AGP) += drm_agpsupport.o |  | ||||||
| drm-$(CONFIG_PCI) += drm_pci.o | drm-$(CONFIG_PCI) += drm_pci.o | ||||||
| drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o | drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o | ||||||
| drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | ||||||
| @ -126,3 +126,4 @@ obj-$(CONFIG_DRM_MCDE) += mcde/ | |||||||
| obj-$(CONFIG_DRM_TIDSS) += tidss/ | obj-$(CONFIG_DRM_TIDSS) += tidss/ | ||||||
| obj-y			+= xlnx/ | obj-y			+= xlnx/ | ||||||
| obj-y			+= gud/ | obj-y			+= gud/ | ||||||
|  | obj-$(CONFIG_DRM_HYPERV) += hyperv/ | ||||||
|  | |||||||
| @ -51,12 +51,15 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \ | |||||||
| 	atombios_encoders.o amdgpu_sa.o atombios_i2c.o \
 | 	atombios_encoders.o amdgpu_sa.o atombios_i2c.o \
 | ||||||
| 	amdgpu_dma_buf.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
 | 	amdgpu_dma_buf.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
 | ||||||
| 	amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
 | 	amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
 | ||||||
| 	amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o \
 | 	amdgpu_gtt_mgr.o amdgpu_preempt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o \
 | ||||||
| 	amdgpu_vf_error.o amdgpu_sched.o amdgpu_debugfs.o amdgpu_ids.o \
 | 	amdgpu_atomfirmware.o amdgpu_vf_error.o amdgpu_sched.o \
 | ||||||
| 	amdgpu_gmc.o amdgpu_mmhub.o amdgpu_xgmi.o amdgpu_csa.o amdgpu_ras.o amdgpu_vm_cpu.o \
 | 	amdgpu_debugfs.o amdgpu_ids.o amdgpu_gmc.o amdgpu_mmhub.o \
 | ||||||
|  | 	amdgpu_xgmi.o amdgpu_csa.o amdgpu_ras.o amdgpu_vm_cpu.o \
 | ||||||
| 	amdgpu_vm_sdma.o amdgpu_discovery.o amdgpu_ras_eeprom.o amdgpu_nbio.o \
 | 	amdgpu_vm_sdma.o amdgpu_discovery.o amdgpu_ras_eeprom.o amdgpu_nbio.o \
 | ||||||
| 	amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \
 | 	amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \
 | ||||||
| 	amdgpu_fw_attestation.o amdgpu_securedisplay.o | 	amdgpu_fw_attestation.o amdgpu_securedisplay.o amdgpu_hdp.o | ||||||
|  | 
 | ||||||
|  | amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o | ||||||
| 
 | 
 | ||||||
| amdgpu-$(CONFIG_PERF_EVENTS) += amdgpu_pmu.o | amdgpu-$(CONFIG_PERF_EVENTS) += amdgpu_pmu.o | ||||||
| 
 | 
 | ||||||
| @ -71,7 +74,8 @@ amdgpu-y += \ | |||||||
| 	vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \
 | 	vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \
 | ||||||
| 	vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o navi14_reg_init.o \
 | 	vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o navi14_reg_init.o \
 | ||||||
| 	arct_reg_init.o navi12_reg_init.o mxgpu_nv.o sienna_cichlid_reg_init.o vangogh_reg_init.o \
 | 	arct_reg_init.o navi12_reg_init.o mxgpu_nv.o sienna_cichlid_reg_init.o vangogh_reg_init.o \
 | ||||||
| 	nbio_v7_2.o dimgrey_cavefish_reg_init.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o | 	nbio_v7_2.o dimgrey_cavefish_reg_init.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o \
 | ||||||
|  | 	beige_goby_reg_init.o yellow_carp_reg_init.o | ||||||
| 
 | 
 | ||||||
| # add DF block
 | # add DF block
 | ||||||
| amdgpu-y += \
 | amdgpu-y += \
 | ||||||
|  | |||||||
| @ -227,7 +227,7 @@ static int aldebaran_mode2_restore_ip(struct amdgpu_device *adev) | |||||||
| 			break; | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			break; | 			break; | ||||||
| 		}; | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Reinit NBIF block */ | 	/* Reinit NBIF block */ | ||||||
|  | |||||||
| @ -107,6 +107,7 @@ | |||||||
| #include "amdgpu_gfxhub.h" | #include "amdgpu_gfxhub.h" | ||||||
| #include "amdgpu_df.h" | #include "amdgpu_df.h" | ||||||
| #include "amdgpu_smuio.h" | #include "amdgpu_smuio.h" | ||||||
|  | #include "amdgpu_fdinfo.h" | ||||||
| 
 | 
 | ||||||
| #define MAX_GPU_INSTANCE		16 | #define MAX_GPU_INSTANCE		16 | ||||||
| 
 | 
 | ||||||
| @ -129,6 +130,13 @@ struct amdgpu_mgpu_info | |||||||
| 	bool				pending_reset; | 	bool				pending_reset; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum amdgpu_ss { | ||||||
|  | 	AMDGPU_SS_DRV_LOAD, | ||||||
|  | 	AMDGPU_SS_DEV_D0, | ||||||
|  | 	AMDGPU_SS_DEV_D3, | ||||||
|  | 	AMDGPU_SS_DRV_UNLOAD | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct amdgpu_watchdog_timer | struct amdgpu_watchdog_timer | ||||||
| { | { | ||||||
| 	bool timeout_fatal_disable; | 	bool timeout_fatal_disable; | ||||||
| @ -203,6 +211,7 @@ extern int amdgpu_discovery; | |||||||
| extern int amdgpu_mes; | extern int amdgpu_mes; | ||||||
| extern int amdgpu_noretry; | extern int amdgpu_noretry; | ||||||
| extern int amdgpu_force_asic_type; | extern int amdgpu_force_asic_type; | ||||||
|  | extern int amdgpu_smartshift_bias; | ||||||
| #ifdef CONFIG_HSA_AMD | #ifdef CONFIG_HSA_AMD | ||||||
| extern int sched_policy; | extern int sched_policy; | ||||||
| extern bool debug_evictions; | extern bool debug_evictions; | ||||||
| @ -260,6 +269,10 @@ extern int amdgpu_num_kcq; | |||||||
| #define CIK_CURSOR_WIDTH 128 | #define CIK_CURSOR_WIDTH 128 | ||||||
| #define CIK_CURSOR_HEIGHT 128 | #define CIK_CURSOR_HEIGHT 128 | ||||||
| 
 | 
 | ||||||
|  | /* smasrt shift bias level limits */ | ||||||
|  | #define AMDGPU_SMARTSHIFT_MAX_BIAS (100) | ||||||
|  | #define AMDGPU_SMARTSHIFT_MIN_BIAS (-100) | ||||||
|  | 
 | ||||||
| struct amdgpu_device; | struct amdgpu_device; | ||||||
| struct amdgpu_ib; | struct amdgpu_ib; | ||||||
| struct amdgpu_cs_parser; | struct amdgpu_cs_parser; | ||||||
| @ -267,7 +280,6 @@ struct amdgpu_job; | |||||||
| struct amdgpu_irq_src; | struct amdgpu_irq_src; | ||||||
| struct amdgpu_fpriv; | struct amdgpu_fpriv; | ||||||
| struct amdgpu_bo_va_mapping; | struct amdgpu_bo_va_mapping; | ||||||
| struct amdgpu_atif; |  | ||||||
| struct kfd_vm_fault_info; | struct kfd_vm_fault_info; | ||||||
| struct amdgpu_hive_info; | struct amdgpu_hive_info; | ||||||
| struct amdgpu_reset_context; | struct amdgpu_reset_context; | ||||||
| @ -681,20 +693,6 @@ struct amdgpu_vram_scratch { | |||||||
| 	u64				gpu_addr; | 	u64				gpu_addr; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * ACPI |  | ||||||
|  */ |  | ||||||
| struct amdgpu_atcs_functions { |  | ||||||
| 	bool get_ext_state; |  | ||||||
| 	bool pcie_perf_req; |  | ||||||
| 	bool pcie_dev_rdy; |  | ||||||
| 	bool pcie_bus_width; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct amdgpu_atcs { |  | ||||||
| 	struct amdgpu_atcs_functions functions; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * CGS |  * CGS | ||||||
|  */ |  */ | ||||||
| @ -824,8 +822,6 @@ struct amdgpu_device { | |||||||
| 	struct notifier_block		acpi_nb; | 	struct notifier_block		acpi_nb; | ||||||
| 	struct amdgpu_i2c_chan		*i2c_bus[AMDGPU_MAX_I2C_BUS]; | 	struct amdgpu_i2c_chan		*i2c_bus[AMDGPU_MAX_I2C_BUS]; | ||||||
| 	struct debugfs_blob_wrapper     debugfs_vbios_blob; | 	struct debugfs_blob_wrapper     debugfs_vbios_blob; | ||||||
| 	struct amdgpu_atif		*atif; |  | ||||||
| 	struct amdgpu_atcs		atcs; |  | ||||||
| 	struct mutex			srbm_mutex; | 	struct mutex			srbm_mutex; | ||||||
| 	/* GRBM index mutex. Protects concurrent access to GRBM index */ | 	/* GRBM index mutex. Protects concurrent access to GRBM index */ | ||||||
| 	struct mutex                    grbm_idx_mutex; | 	struct mutex                    grbm_idx_mutex; | ||||||
| @ -1074,9 +1070,10 @@ struct amdgpu_device { | |||||||
| 
 | 
 | ||||||
| 	atomic_t			throttling_logging_enabled; | 	atomic_t			throttling_logging_enabled; | ||||||
| 	struct ratelimit_state		throttling_logging_rs; | 	struct ratelimit_state		throttling_logging_rs; | ||||||
| 	uint32_t			ras_features; | 	uint32_t                        ras_hw_enabled; | ||||||
|  | 	uint32_t                        ras_enabled; | ||||||
| 
 | 
 | ||||||
| 	bool                            in_pci_err_recovery; | 	bool                            no_hw_access; | ||||||
| 	struct pci_saved_state          *pci_state; | 	struct pci_saved_state          *pci_state; | ||||||
| 
 | 
 | ||||||
| 	struct amdgpu_reset_control     *reset_cntl; | 	struct amdgpu_reset_control     *reset_cntl; | ||||||
| @ -1099,7 +1096,9 @@ static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_device *bdev) | |||||||
| 
 | 
 | ||||||
| int amdgpu_device_init(struct amdgpu_device *adev, | int amdgpu_device_init(struct amdgpu_device *adev, | ||||||
| 		       uint32_t flags); | 		       uint32_t flags); | ||||||
| void amdgpu_device_fini(struct amdgpu_device *adev); | void amdgpu_device_fini_hw(struct amdgpu_device *adev); | ||||||
|  | void amdgpu_device_fini_sw(struct amdgpu_device *adev); | ||||||
|  | 
 | ||||||
| int amdgpu_gpu_wait_for_idle(struct amdgpu_device *adev); | int amdgpu_gpu_wait_for_idle(struct amdgpu_device *adev); | ||||||
| 
 | 
 | ||||||
| void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, | void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, | ||||||
| @ -1142,6 +1141,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev); | |||||||
|  * Registers read & write functions. |  * Registers read & write functions. | ||||||
|  */ |  */ | ||||||
| #define AMDGPU_REGS_NO_KIQ    (1<<1) | #define AMDGPU_REGS_NO_KIQ    (1<<1) | ||||||
|  | #define AMDGPU_REGS_RLC	(1<<2) | ||||||
| 
 | 
 | ||||||
| #define RREG32_NO_KIQ(reg) amdgpu_device_rreg(adev, (reg), AMDGPU_REGS_NO_KIQ) | #define RREG32_NO_KIQ(reg) amdgpu_device_rreg(adev, (reg), AMDGPU_REGS_NO_KIQ) | ||||||
| #define WREG32_NO_KIQ(reg, v) amdgpu_device_wreg(adev, (reg), (v), AMDGPU_REGS_NO_KIQ) | #define WREG32_NO_KIQ(reg, v) amdgpu_device_wreg(adev, (reg), (v), AMDGPU_REGS_NO_KIQ) | ||||||
| @ -1278,12 +1278,18 @@ int amdgpu_device_mode1_reset(struct amdgpu_device *adev); | |||||||
| bool amdgpu_device_supports_atpx(struct drm_device *dev); | bool amdgpu_device_supports_atpx(struct drm_device *dev); | ||||||
| bool amdgpu_device_supports_px(struct drm_device *dev); | bool amdgpu_device_supports_px(struct drm_device *dev); | ||||||
| bool amdgpu_device_supports_boco(struct drm_device *dev); | bool amdgpu_device_supports_boco(struct drm_device *dev); | ||||||
|  | bool amdgpu_device_supports_smart_shift(struct drm_device *dev); | ||||||
| bool amdgpu_device_supports_baco(struct drm_device *dev); | bool amdgpu_device_supports_baco(struct drm_device *dev); | ||||||
| bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, | bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, | ||||||
| 				      struct amdgpu_device *peer_adev); | 				      struct amdgpu_device *peer_adev); | ||||||
| int amdgpu_device_baco_enter(struct drm_device *dev); | int amdgpu_device_baco_enter(struct drm_device *dev); | ||||||
| int amdgpu_device_baco_exit(struct drm_device *dev); | int amdgpu_device_baco_exit(struct drm_device *dev); | ||||||
| 
 | 
 | ||||||
|  | void amdgpu_device_flush_hdp(struct amdgpu_device *adev, | ||||||
|  | 		struct amdgpu_ring *ring); | ||||||
|  | void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev, | ||||||
|  | 		struct amdgpu_ring *ring); | ||||||
|  | 
 | ||||||
| /* atpx handler */ | /* atpx handler */ | ||||||
| #if defined(CONFIG_VGA_SWITCHEROO) | #if defined(CONFIG_VGA_SWITCHEROO) | ||||||
| void amdgpu_register_atpx_handler(void); | void amdgpu_register_atpx_handler(void); | ||||||
| @ -1319,6 +1325,8 @@ void amdgpu_driver_lastclose_kms(struct drm_device *dev); | |||||||
| int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv); | int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv); | ||||||
| void amdgpu_driver_postclose_kms(struct drm_device *dev, | void amdgpu_driver_postclose_kms(struct drm_device *dev, | ||||||
| 				 struct drm_file *file_priv); | 				 struct drm_file *file_priv); | ||||||
|  | void amdgpu_driver_release_kms(struct drm_device *dev); | ||||||
|  | 
 | ||||||
| int amdgpu_device_ip_suspend(struct amdgpu_device *adev); | int amdgpu_device_ip_suspend(struct amdgpu_device *adev); | ||||||
| int amdgpu_device_suspend(struct drm_device *dev, bool fbcon); | int amdgpu_device_suspend(struct drm_device *dev, bool fbcon); | ||||||
| int amdgpu_device_resume(struct drm_device *dev, bool fbcon); | int amdgpu_device_resume(struct drm_device *dev, bool fbcon); | ||||||
| @ -1350,21 +1358,38 @@ struct amdgpu_afmt_acr { | |||||||
| struct amdgpu_afmt_acr amdgpu_afmt_acr(uint32_t clock); | struct amdgpu_afmt_acr amdgpu_afmt_acr(uint32_t clock); | ||||||
| 
 | 
 | ||||||
| /* amdgpu_acpi.c */ | /* amdgpu_acpi.c */ | ||||||
|  | 
 | ||||||
|  | /* ATCS Device/Driver State */ | ||||||
|  | #define AMDGPU_ATCS_PSC_DEV_STATE_D0		0 | ||||||
|  | #define AMDGPU_ATCS_PSC_DEV_STATE_D3_HOT	3 | ||||||
|  | #define AMDGPU_ATCS_PSC_DRV_STATE_OPR		0 | ||||||
|  | #define AMDGPU_ATCS_PSC_DRV_STATE_NOT_OPR	1 | ||||||
|  | 
 | ||||||
| #if defined(CONFIG_ACPI) | #if defined(CONFIG_ACPI) | ||||||
| int amdgpu_acpi_init(struct amdgpu_device *adev); | int amdgpu_acpi_init(struct amdgpu_device *adev); | ||||||
| void amdgpu_acpi_fini(struct amdgpu_device *adev); | void amdgpu_acpi_fini(struct amdgpu_device *adev); | ||||||
| bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev); | bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev); | ||||||
|  | bool amdgpu_acpi_is_power_shift_control_supported(void); | ||||||
| int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, | int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, | ||||||
| 						u8 perf_req, bool advertise); | 						u8 perf_req, bool advertise); | ||||||
|  | int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev, | ||||||
|  | 				    u8 dev_state, bool drv_state); | ||||||
|  | int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_state); | ||||||
| int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev); | int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev); | ||||||
| 
 | 
 | ||||||
| void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev, | void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps); | ||||||
| 		struct amdgpu_dm_backlight_caps *caps); |  | ||||||
| bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev); | bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev); | ||||||
|  | void amdgpu_acpi_detect(void); | ||||||
| #else | #else | ||||||
| static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; } | static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; } | ||||||
| static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { } | static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { } | ||||||
| static inline bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev) { return false; } | static inline bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev) { return false; } | ||||||
|  | static inline void amdgpu_acpi_detect(void) { } | ||||||
|  | static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; } | ||||||
|  | static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev, | ||||||
|  | 						  u8 dev_state, bool drv_state) { return 0; } | ||||||
|  | static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev, | ||||||
|  | 						 enum amdgpu_ss ss_state) { return 0; } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, | int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, | ||||||
|  | |||||||
| @ -71,12 +71,31 @@ struct amdgpu_atif { | |||||||
| 	struct amdgpu_dm_backlight_caps backlight_caps; | 	struct amdgpu_dm_backlight_caps backlight_caps; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct amdgpu_atcs_functions { | ||||||
|  | 	bool get_ext_state; | ||||||
|  | 	bool pcie_perf_req; | ||||||
|  | 	bool pcie_dev_rdy; | ||||||
|  | 	bool pcie_bus_width; | ||||||
|  | 	bool power_shift_control; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct amdgpu_atcs { | ||||||
|  | 	acpi_handle handle; | ||||||
|  | 
 | ||||||
|  | 	struct amdgpu_atcs_functions functions; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static struct amdgpu_acpi_priv { | ||||||
|  | 	struct amdgpu_atif atif; | ||||||
|  | 	struct amdgpu_atcs atcs; | ||||||
|  | } amdgpu_acpi_priv; | ||||||
|  | 
 | ||||||
| /* Call the ATIF method
 | /* Call the ATIF method
 | ||||||
|  */ |  */ | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atif_call - call an ATIF method |  * amdgpu_atif_call - call an ATIF method | ||||||
|  * |  * | ||||||
|  * @handle: acpi handle |  * @atif: atif structure | ||||||
|  * @function: the ATIF function to execute |  * @function: the ATIF function to execute | ||||||
|  * @params: ATIF function params |  * @params: ATIF function params | ||||||
|  * |  * | ||||||
| @ -166,7 +185,6 @@ static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mas | |||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atif_verify_interface - verify ATIF |  * amdgpu_atif_verify_interface - verify ATIF | ||||||
|  * |  * | ||||||
|  * @handle: acpi handle |  | ||||||
|  * @atif: amdgpu atif struct |  * @atif: amdgpu atif struct | ||||||
|  * |  * | ||||||
|  * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function |  * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function | ||||||
| @ -208,40 +226,10 @@ out: | |||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static acpi_handle amdgpu_atif_probe_handle(acpi_handle dhandle) |  | ||||||
| { |  | ||||||
| 	acpi_handle handle = NULL; |  | ||||||
| 	char acpi_method_name[255] = { 0 }; |  | ||||||
| 	struct acpi_buffer buffer = { sizeof(acpi_method_name), acpi_method_name }; |  | ||||||
| 	acpi_status status; |  | ||||||
| 
 |  | ||||||
| 	/* For PX/HG systems, ATIF and ATPX are in the iGPU's namespace, on dGPU only
 |  | ||||||
| 	 * systems, ATIF is in the dGPU's namespace. |  | ||||||
| 	 */ |  | ||||||
| 	status = acpi_get_handle(dhandle, "ATIF", &handle); |  | ||||||
| 	if (ACPI_SUCCESS(status)) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	if (amdgpu_has_atpx()) { |  | ||||||
| 		status = acpi_get_handle(amdgpu_atpx_get_dhandle(), "ATIF", |  | ||||||
| 					 &handle); |  | ||||||
| 		if (ACPI_SUCCESS(status)) |  | ||||||
| 			goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG_DRIVER("No ATIF handle found\n"); |  | ||||||
| 	return NULL; |  | ||||||
| out: |  | ||||||
| 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |  | ||||||
| 	DRM_DEBUG_DRIVER("Found ATIF handle %s\n", acpi_method_name); |  | ||||||
| 	return handle; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atif_get_notification_params - determine notify configuration |  * amdgpu_atif_get_notification_params - determine notify configuration | ||||||
|  * |  * | ||||||
|  * @handle: acpi handle |  * @atif: acpi handle | ||||||
|  * @n: atif notification configuration struct |  | ||||||
|  * |  * | ||||||
|  * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function |  * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function | ||||||
|  * to determine if a notifier is used and if so which one |  * to determine if a notifier is used and if so which one | ||||||
| @ -304,7 +292,7 @@ out: | |||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atif_query_backlight_caps - get min and max backlight input signal |  * amdgpu_atif_query_backlight_caps - get min and max backlight input signal | ||||||
|  * |  * | ||||||
|  * @handle: acpi handle |  * @atif: acpi handle | ||||||
|  * |  * | ||||||
|  * Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function |  * Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function | ||||||
|  * to determine the acceptable range of backlight values |  * to determine the acceptable range of backlight values | ||||||
| @ -363,7 +351,7 @@ out: | |||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atif_get_sbios_requests - get requested sbios event |  * amdgpu_atif_get_sbios_requests - get requested sbios event | ||||||
|  * |  * | ||||||
|  * @handle: acpi handle |  * @atif: acpi handle | ||||||
|  * @req: atif sbios request struct |  * @req: atif sbios request struct | ||||||
|  * |  * | ||||||
|  * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function |  * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function | ||||||
| @ -416,7 +404,7 @@ out: | |||||||
| static int amdgpu_atif_handler(struct amdgpu_device *adev, | static int amdgpu_atif_handler(struct amdgpu_device *adev, | ||||||
| 			       struct acpi_bus_event *event) | 			       struct acpi_bus_event *event) | ||||||
| { | { | ||||||
| 	struct amdgpu_atif *atif = adev->atif; | 	struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; | ||||||
| 	int count; | 	int count; | ||||||
| 
 | 
 | ||||||
| 	DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", | 	DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n", | ||||||
| @ -426,8 +414,7 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, | |||||||
| 		return NOTIFY_DONE; | 		return NOTIFY_DONE; | ||||||
| 
 | 
 | ||||||
| 	/* Is this actually our event? */ | 	/* Is this actually our event? */ | ||||||
| 	if (!atif || | 	if (!atif->notification_cfg.enabled || | ||||||
| 	    !atif->notification_cfg.enabled || |  | ||||||
| 	    event->type != atif->notification_cfg.command_code) { | 	    event->type != atif->notification_cfg.command_code) { | ||||||
| 		/* These events will generate keypresses otherwise */ | 		/* These events will generate keypresses otherwise */ | ||||||
| 		if (event->type == ACPI_VIDEO_NOTIFY_PROBE) | 		if (event->type == ACPI_VIDEO_NOTIFY_PROBE) | ||||||
| @ -487,14 +474,15 @@ static int amdgpu_atif_handler(struct amdgpu_device *adev, | |||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atcs_call - call an ATCS method |  * amdgpu_atcs_call - call an ATCS method | ||||||
|  * |  * | ||||||
|  * @handle: acpi handle |  * @atcs: atcs structure | ||||||
|  * @function: the ATCS function to execute |  * @function: the ATCS function to execute | ||||||
|  * @params: ATCS function params |  * @params: ATCS function params | ||||||
|  * |  * | ||||||
|  * Executes the requested ATCS function (all asics). |  * Executes the requested ATCS function (all asics). | ||||||
|  * Returns a pointer to the acpi output buffer. |  * Returns a pointer to the acpi output buffer. | ||||||
|  */ |  */ | ||||||
| static union acpi_object *amdgpu_atcs_call(acpi_handle handle, int function, | static union acpi_object *amdgpu_atcs_call(struct amdgpu_atcs *atcs, | ||||||
|  | 					   int function, | ||||||
| 					   struct acpi_buffer *params) | 					   struct acpi_buffer *params) | ||||||
| { | { | ||||||
| 	acpi_status status; | 	acpi_status status; | ||||||
| @ -518,7 +506,7 @@ static union acpi_object *amdgpu_atcs_call(acpi_handle handle, int function, | |||||||
| 		atcs_arg_elements[1].integer.value = 0; | 		atcs_arg_elements[1].integer.value = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	status = acpi_evaluate_object(handle, "ATCS", &atcs_arg, &buffer); | 	status = acpi_evaluate_object(atcs->handle, NULL, &atcs_arg, &buffer); | ||||||
| 
 | 
 | ||||||
| 	/* Fail only if calling the method fails and ATIF is supported */ | 	/* Fail only if calling the method fails and ATIF is supported */ | ||||||
| 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||||||
| @ -547,12 +535,12 @@ static void amdgpu_atcs_parse_functions(struct amdgpu_atcs_functions *f, u32 mas | |||||||
| 	f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; | 	f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; | ||||||
| 	f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; | 	f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; | ||||||
| 	f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; | 	f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; | ||||||
|  | 	f->power_shift_control = mask & ATCS_SET_POWER_SHIFT_CONTROL_SUPPORTED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atcs_verify_interface - verify ATCS |  * amdgpu_atcs_verify_interface - verify ATCS | ||||||
|  * |  * | ||||||
|  * @handle: acpi handle |  | ||||||
|  * @atcs: amdgpu atcs struct |  * @atcs: amdgpu atcs struct | ||||||
|  * |  * | ||||||
|  * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function |  * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function | ||||||
| @ -560,15 +548,14 @@ static void amdgpu_atcs_parse_functions(struct amdgpu_atcs_functions *f, u32 mas | |||||||
|  * (all asics). |  * (all asics). | ||||||
|  * returns 0 on success, error on failure. |  * returns 0 on success, error on failure. | ||||||
|  */ |  */ | ||||||
| static int amdgpu_atcs_verify_interface(acpi_handle handle, | static int amdgpu_atcs_verify_interface(struct amdgpu_atcs *atcs) | ||||||
| 					struct amdgpu_atcs *atcs) |  | ||||||
| { | { | ||||||
| 	union acpi_object *info; | 	union acpi_object *info; | ||||||
| 	struct atcs_verify_interface output; | 	struct atcs_verify_interface output; | ||||||
| 	size_t size; | 	size_t size; | ||||||
| 	int err = 0; | 	int err = 0; | ||||||
| 
 | 
 | ||||||
| 	info = amdgpu_atcs_call(handle, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); | 	info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); | ||||||
| 	if (!info) | 	if (!info) | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
| 
 | 
 | ||||||
| @ -605,7 +592,7 @@ out: | |||||||
|  */ |  */ | ||||||
| bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev) | bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	struct amdgpu_atcs *atcs = &adev->atcs; | 	struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; | ||||||
| 
 | 
 | ||||||
| 	if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy) | 	if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy) | ||||||
| 		return true; | 		return true; | ||||||
| @ -613,6 +600,18 @@ bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *ade | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_acpi_is_power_shift_control_supported | ||||||
|  |  * | ||||||
|  |  * Check if the ATCS power shift control method | ||||||
|  |  * is supported. | ||||||
|  |  * returns true if supported, false if not. | ||||||
|  |  */ | ||||||
|  | bool amdgpu_acpi_is_power_shift_control_supported(void) | ||||||
|  | { | ||||||
|  | 	return amdgpu_acpi_priv.atcs.functions.power_shift_control; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_acpi_pcie_notify_device_ready |  * amdgpu_acpi_pcie_notify_device_ready | ||||||
|  * |  * | ||||||
| @ -624,19 +623,13 @@ bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *ade | |||||||
|  */ |  */ | ||||||
| int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev) | int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	acpi_handle handle; |  | ||||||
| 	union acpi_object *info; | 	union acpi_object *info; | ||||||
| 	struct amdgpu_atcs *atcs = &adev->atcs; | 	struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; | ||||||
| 
 |  | ||||||
| 	/* Get the device handle */ |  | ||||||
| 	handle = ACPI_HANDLE(&adev->pdev->dev); |  | ||||||
| 	if (!handle) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 | 
 | ||||||
| 	if (!atcs->functions.pcie_dev_rdy) | 	if (!atcs->functions.pcie_dev_rdy) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL); | 	info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL); | ||||||
| 	if (!info) | 	if (!info) | ||||||
| 		return -EIO; | 		return -EIO; | ||||||
| 
 | 
 | ||||||
| @ -659,9 +652,8 @@ int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev) | |||||||
| int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, | int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, | ||||||
| 					 u8 perf_req, bool advertise) | 					 u8 perf_req, bool advertise) | ||||||
| { | { | ||||||
| 	acpi_handle handle; |  | ||||||
| 	union acpi_object *info; | 	union acpi_object *info; | ||||||
| 	struct amdgpu_atcs *atcs = &adev->atcs; | 	struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; | ||||||
| 	struct atcs_pref_req_input atcs_input; | 	struct atcs_pref_req_input atcs_input; | ||||||
| 	struct atcs_pref_req_output atcs_output; | 	struct atcs_pref_req_output atcs_output; | ||||||
| 	struct acpi_buffer params; | 	struct acpi_buffer params; | ||||||
| @ -671,11 +663,6 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, | |||||||
| 	if (amdgpu_acpi_pcie_notify_device_ready(adev)) | 	if (amdgpu_acpi_pcie_notify_device_ready(adev)) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	/* Get the device handle */ |  | ||||||
| 	handle = ACPI_HANDLE(&adev->pdev->dev); |  | ||||||
| 	if (!handle) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	if (!atcs->functions.pcie_perf_req) | 	if (!atcs->functions.pcie_perf_req) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| @ -693,7 +680,7 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, | |||||||
| 	params.pointer = &atcs_input; | 	params.pointer = &atcs_input; | ||||||
| 
 | 
 | ||||||
| 	while (retry--) { | 	while (retry--) { | ||||||
| 		info = amdgpu_atcs_call(handle, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, ¶ms); | 		info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, ¶ms); | ||||||
| 		if (!info) | 		if (!info) | ||||||
| 			return -EIO; | 			return -EIO; | ||||||
| 
 | 
 | ||||||
| @ -726,6 +713,96 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_acpi_power_shift_control | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * @dev_state: device acpi state | ||||||
|  |  * @drv_state: driver state | ||||||
|  |  * | ||||||
|  |  * Executes the POWER_SHIFT_CONTROL method to | ||||||
|  |  * communicate current dGPU device state and | ||||||
|  |  * driver state to APU/SBIOS. | ||||||
|  |  * returns 0 on success, error on failure. | ||||||
|  |  */ | ||||||
|  | int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev, | ||||||
|  | 				    u8 dev_state, bool drv_state) | ||||||
|  | { | ||||||
|  | 	union acpi_object *info; | ||||||
|  | 	struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; | ||||||
|  | 	struct atcs_pwr_shift_input atcs_input; | ||||||
|  | 	struct acpi_buffer params; | ||||||
|  | 
 | ||||||
|  | 	if (!amdgpu_acpi_is_power_shift_control_supported()) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	atcs_input.size = sizeof(struct atcs_pwr_shift_input); | ||||||
|  | 	/* dGPU id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ | ||||||
|  | 	atcs_input.dgpu_id = adev->pdev->devfn | (adev->pdev->bus->number << 8); | ||||||
|  | 	atcs_input.dev_acpi_state = dev_state; | ||||||
|  | 	atcs_input.drv_state = drv_state; | ||||||
|  | 
 | ||||||
|  | 	params.length = sizeof(struct atcs_pwr_shift_input); | ||||||
|  | 	params.pointer = &atcs_input; | ||||||
|  | 
 | ||||||
|  | 	info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_POWER_SHIFT_CONTROL, ¶ms); | ||||||
|  | 	if (!info) { | ||||||
|  | 		DRM_ERROR("ATCS PSC update failed\n"); | ||||||
|  | 		return -EIO; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_acpi_smart_shift_update - update dGPU device state to SBIOS | ||||||
|  |  * | ||||||
|  |  * @dev: drm_device pointer | ||||||
|  |  * @ss_state: current smart shift event | ||||||
|  |  * | ||||||
|  |  * returns 0 on success, | ||||||
|  |  * otherwise return error number. | ||||||
|  |  */ | ||||||
|  | int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_state) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_device *adev = drm_to_adev(dev); | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	if (!amdgpu_device_supports_smart_shift(dev)) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	switch (ss_state) { | ||||||
|  | 	/* SBIOS trigger “stop”, “enable” and “start” at D0, Driver Operational.
 | ||||||
|  | 	 * SBIOS trigger “stop” at D3, Driver Not Operational. | ||||||
|  | 	 * SBIOS trigger “stop” and “disable” at D0, Driver NOT operational. | ||||||
|  | 	 */ | ||||||
|  | 	case AMDGPU_SS_DRV_LOAD: | ||||||
|  | 		r = amdgpu_acpi_power_shift_control(adev, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DEV_STATE_D0, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DRV_STATE_OPR); | ||||||
|  | 		break; | ||||||
|  | 	case AMDGPU_SS_DEV_D0: | ||||||
|  | 		r = amdgpu_acpi_power_shift_control(adev, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DEV_STATE_D0, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DRV_STATE_OPR); | ||||||
|  | 		break; | ||||||
|  | 	case AMDGPU_SS_DEV_D3: | ||||||
|  | 		r = amdgpu_acpi_power_shift_control(adev, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DEV_STATE_D3_HOT, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DRV_STATE_NOT_OPR); | ||||||
|  | 		break; | ||||||
|  | 	case AMDGPU_SS_DRV_UNLOAD: | ||||||
|  | 		r = amdgpu_acpi_power_shift_control(adev, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DEV_STATE_D0, | ||||||
|  | 						    AMDGPU_ATCS_PSC_DRV_STATE_NOT_OPR); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_acpi_event - handle notify events |  * amdgpu_acpi_event - handle notify events | ||||||
|  * |  * | ||||||
| @ -769,49 +846,14 @@ static int amdgpu_acpi_event(struct notifier_block *nb, | |||||||
|  */ |  */ | ||||||
| int amdgpu_acpi_init(struct amdgpu_device *adev) | int amdgpu_acpi_init(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	acpi_handle handle, atif_handle; | 	struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; | ||||||
| 	struct amdgpu_atif *atif; |  | ||||||
| 	struct amdgpu_atcs *atcs = &adev->atcs; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	/* Get the device handle */ |  | ||||||
| 	handle = ACPI_HANDLE(&adev->pdev->dev); |  | ||||||
| 
 |  | ||||||
| 	if (!adev->bios || !handle) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	/* Call the ATCS method */ |  | ||||||
| 	ret = amdgpu_atcs_verify_interface(handle, atcs); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_DEBUG_DRIVER("Call to ATCS verify_interface failed: %d\n", ret); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Probe for ATIF, and initialize it if found */ |  | ||||||
| 	atif_handle = amdgpu_atif_probe_handle(handle); |  | ||||||
| 	if (!atif_handle) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	atif = kzalloc(sizeof(*atif), GFP_KERNEL); |  | ||||||
| 	if (!atif) { |  | ||||||
| 		DRM_WARN("Not enough memory to initialize ATIF\n"); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 	atif->handle = atif_handle; |  | ||||||
| 
 |  | ||||||
| 	/* Call the ATIF method */ |  | ||||||
| 	ret = amdgpu_atif_verify_interface(atif); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_DEBUG_DRIVER("Call to ATIF verify_interface failed: %d\n", ret); |  | ||||||
| 		kfree(atif); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 	adev->atif = atif; |  | ||||||
| 
 | 
 | ||||||
| #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) | ||||||
| 	if (atif->notifications.brightness_change) { | 	if (atif->notifications.brightness_change) { | ||||||
| 		if (amdgpu_device_has_dc_support(adev)) { | 		if (amdgpu_device_has_dc_support(adev)) { | ||||||
| #if defined(CONFIG_DRM_AMD_DC) | #if defined(CONFIG_DRM_AMD_DC) | ||||||
| 			struct amdgpu_display_manager *dm = &adev->dm; | 			struct amdgpu_display_manager *dm = &adev->dm; | ||||||
|  | 			if (dm->backlight_dev) | ||||||
| 				atif->bd = dm->backlight_dev; | 				atif->bd = dm->backlight_dev; | ||||||
| #endif | #endif | ||||||
| 		} else { | 		} else { | ||||||
| @ -834,6 +876,129 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  | 	adev->acpi_nb.notifier_call = amdgpu_acpi_event; | ||||||
|  | 	register_acpi_notifier(&adev->acpi_nb); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; | ||||||
|  | 
 | ||||||
|  | 	caps->caps_valid = atif->backlight_caps.caps_valid; | ||||||
|  | 	caps->min_input_signal = atif->backlight_caps.min_input_signal; | ||||||
|  | 	caps->max_input_signal = atif->backlight_caps.max_input_signal; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_acpi_fini - tear down driver acpi support | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Unregisters with the acpi notifier chain (all asics). | ||||||
|  |  */ | ||||||
|  | void amdgpu_acpi_fini(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	unregister_acpi_notifier(&adev->acpi_nb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_atif_pci_probe_handle - look up the ATIF handle | ||||||
|  |  * | ||||||
|  |  * @pdev: pci device | ||||||
|  |  * | ||||||
|  |  * Look up the ATIF handles (all asics). | ||||||
|  |  * Returns true if the handle is found, false if not. | ||||||
|  |  */ | ||||||
|  | static bool amdgpu_atif_pci_probe_handle(struct pci_dev *pdev) | ||||||
|  | { | ||||||
|  | 	char acpi_method_name[255] = { 0 }; | ||||||
|  | 	struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; | ||||||
|  | 	acpi_handle dhandle, atif_handle; | ||||||
|  | 	acpi_status status; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	dhandle = ACPI_HANDLE(&pdev->dev); | ||||||
|  | 	if (!dhandle) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	status = acpi_get_handle(dhandle, "ATIF", &atif_handle); | ||||||
|  | 	if (ACPI_FAILURE(status)) { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	amdgpu_acpi_priv.atif.handle = atif_handle; | ||||||
|  | 	acpi_get_name(amdgpu_acpi_priv.atif.handle, ACPI_FULL_PATHNAME, &buffer); | ||||||
|  | 	DRM_DEBUG_DRIVER("Found ATIF handle %s\n", acpi_method_name); | ||||||
|  | 	ret = amdgpu_atif_verify_interface(&amdgpu_acpi_priv.atif); | ||||||
|  | 	if (ret) { | ||||||
|  | 		amdgpu_acpi_priv.atif.handle = 0; | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_atcs_pci_probe_handle - look up the ATCS handle | ||||||
|  |  * | ||||||
|  |  * @pdev: pci device | ||||||
|  |  * | ||||||
|  |  * Look up the ATCS handles (all asics). | ||||||
|  |  * Returns true if the handle is found, false if not. | ||||||
|  |  */ | ||||||
|  | static bool amdgpu_atcs_pci_probe_handle(struct pci_dev *pdev) | ||||||
|  | { | ||||||
|  | 	char acpi_method_name[255] = { 0 }; | ||||||
|  | 	struct acpi_buffer buffer = { sizeof(acpi_method_name), acpi_method_name }; | ||||||
|  | 	acpi_handle dhandle, atcs_handle; | ||||||
|  | 	acpi_status status; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	dhandle = ACPI_HANDLE(&pdev->dev); | ||||||
|  | 	if (!dhandle) | ||||||
|  | 		return false; | ||||||
|  | 
 | ||||||
|  | 	status = acpi_get_handle(dhandle, "ATCS", &atcs_handle); | ||||||
|  | 	if (ACPI_FAILURE(status)) { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	amdgpu_acpi_priv.atcs.handle = atcs_handle; | ||||||
|  | 	acpi_get_name(amdgpu_acpi_priv.atcs.handle, ACPI_FULL_PATHNAME, &buffer); | ||||||
|  | 	DRM_DEBUG_DRIVER("Found ATCS handle %s\n", acpi_method_name); | ||||||
|  | 	ret = amdgpu_atcs_verify_interface(&amdgpu_acpi_priv.atcs); | ||||||
|  | 	if (ret) { | ||||||
|  | 		amdgpu_acpi_priv.atcs.handle = 0; | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * amdgpu_acpi_detect - detect ACPI ATIF/ATCS methods | ||||||
|  |  * | ||||||
|  |  * Check if we have the ATIF/ATCS methods and populate | ||||||
|  |  * the structures in the driver. | ||||||
|  |  */ | ||||||
|  | void amdgpu_acpi_detect(void) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; | ||||||
|  | 	struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; | ||||||
|  | 	struct pci_dev *pdev = NULL; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { | ||||||
|  | 		if (!atif->handle) | ||||||
|  | 			amdgpu_atif_pci_probe_handle(pdev); | ||||||
|  | 		if (!atcs->handle) | ||||||
|  | 			amdgpu_atcs_pci_probe_handle(pdev); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { | ||||||
|  | 		if (!atif->handle) | ||||||
|  | 			amdgpu_atif_pci_probe_handle(pdev); | ||||||
|  | 		if (!atcs->handle) | ||||||
|  | 			amdgpu_atcs_pci_probe_handle(pdev); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (atif->functions.sbios_requests && !atif->functions.system_params) { | 	if (atif->functions.sbios_requests && !atif->functions.system_params) { | ||||||
| 		/* XXX check this workraround, if sbios request function is
 | 		/* XXX check this workraround, if sbios request function is
 | ||||||
| @ -863,42 +1028,13 @@ int amdgpu_acpi_init(struct amdgpu_device *adev) | |||||||
| 	} else { | 	} else { | ||||||
| 		atif->backlight_caps.caps_valid = false; | 		atif->backlight_caps.caps_valid = false; | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	adev->acpi_nb.notifier_call = amdgpu_acpi_event; |  | ||||||
| 	register_acpi_notifier(&adev->acpi_nb); |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev, |  | ||||||
| 		struct amdgpu_dm_backlight_caps *caps) |  | ||||||
| { |  | ||||||
| 	if (!adev->atif) { |  | ||||||
| 		caps->caps_valid = false; |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 	caps->caps_valid = adev->atif->backlight_caps.caps_valid; |  | ||||||
| 	caps->min_input_signal = adev->atif->backlight_caps.min_input_signal; |  | ||||||
| 	caps->max_input_signal = adev->atif->backlight_caps.max_input_signal; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * amdgpu_acpi_fini - tear down driver acpi support |  | ||||||
|  * |  | ||||||
|  * @adev: amdgpu_device pointer |  | ||||||
|  * |  | ||||||
|  * Unregisters with the acpi notifier chain (all asics). |  | ||||||
|  */ |  | ||||||
| void amdgpu_acpi_fini(struct amdgpu_device *adev) |  | ||||||
| { |  | ||||||
| 	unregister_acpi_notifier(&adev->acpi_nb); |  | ||||||
| 	kfree(adev->atif); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_acpi_is_s0ix_supported |  * amdgpu_acpi_is_s0ix_supported | ||||||
|  * |  * | ||||||
|  |  * @adev: amdgpu_device_pointer | ||||||
|  |  * | ||||||
|  * returns true if supported, false if not. |  * returns true if supported, false if not. | ||||||
|  */ |  */ | ||||||
| bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev) | bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev) | ||||||
|  | |||||||
| @ -170,7 +170,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void amdgpu_amdkfd_device_fini(struct amdgpu_device *adev) | void amdgpu_amdkfd_device_fini_sw(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	if (adev->kfd.dev) { | 	if (adev->kfd.dev) { | ||||||
| 		kgd2kfd_device_exit(adev->kfd.dev); | 		kgd2kfd_device_exit(adev->kfd.dev); | ||||||
| @ -670,10 +670,10 @@ int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct kgd_dev *kgd, uint16_t vmid) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct kgd_dev *kgd, uint16_t pasid) | int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct kgd_dev *kgd, uint16_t pasid, | ||||||
|  | 				      enum TLB_FLUSH_TYPE flush_type) | ||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = (struct amdgpu_device *)kgd; | 	struct amdgpu_device *adev = (struct amdgpu_device *)kgd; | ||||||
| 	const uint32_t flush_type = 0; |  | ||||||
| 	bool all_hub = false; | 	bool all_hub = false; | ||||||
| 
 | 
 | ||||||
| 	if (adev->family == AMDGPU_FAMILY_AI) | 	if (adev->family == AMDGPU_FAMILY_AI) | ||||||
|  | |||||||
| @ -36,13 +36,26 @@ | |||||||
| 
 | 
 | ||||||
| extern uint64_t amdgpu_amdkfd_total_mem_size; | extern uint64_t amdgpu_amdkfd_total_mem_size; | ||||||
| 
 | 
 | ||||||
|  | enum TLB_FLUSH_TYPE { | ||||||
|  | 	TLB_FLUSH_LEGACY = 0, | ||||||
|  | 	TLB_FLUSH_LIGHTWEIGHT, | ||||||
|  | 	TLB_FLUSH_HEAVYWEIGHT | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct amdgpu_device; | struct amdgpu_device; | ||||||
| 
 | 
 | ||||||
| struct kfd_bo_va_list { | enum kfd_mem_attachment_type { | ||||||
| 	struct list_head bo_list; | 	KFD_MEM_ATT_SHARED,	/* Share kgd_mem->bo or another attachment's */ | ||||||
| 	struct amdgpu_bo_va *bo_va; | 	KFD_MEM_ATT_USERPTR,	/* SG bo to DMA map pages from a userptr bo */ | ||||||
| 	void *kgd_dev; | 	KFD_MEM_ATT_DMABUF,	/* DMAbuf to DMA map TTM BOs */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct kfd_mem_attachment { | ||||||
|  | 	struct list_head list; | ||||||
|  | 	enum kfd_mem_attachment_type type; | ||||||
| 	bool is_mapped; | 	bool is_mapped; | ||||||
|  | 	struct amdgpu_bo_va *bo_va; | ||||||
|  | 	struct amdgpu_device *adev; | ||||||
| 	uint64_t va; | 	uint64_t va; | ||||||
| 	uint64_t pte_flags; | 	uint64_t pte_flags; | ||||||
| }; | }; | ||||||
| @ -50,7 +63,8 @@ struct kfd_bo_va_list { | |||||||
| struct kgd_mem { | struct kgd_mem { | ||||||
| 	struct mutex lock; | 	struct mutex lock; | ||||||
| 	struct amdgpu_bo *bo; | 	struct amdgpu_bo *bo; | ||||||
| 	struct list_head bo_va_list; | 	struct dma_buf *dmabuf; | ||||||
|  | 	struct list_head attachments; | ||||||
| 	/* protected by amdkfd_process_info.lock */ | 	/* protected by amdkfd_process_info.lock */ | ||||||
| 	struct ttm_validate_buffer validate_list; | 	struct ttm_validate_buffer validate_list; | ||||||
| 	struct ttm_validate_buffer resv_list; | 	struct ttm_validate_buffer resv_list; | ||||||
| @ -75,6 +89,7 @@ struct amdgpu_amdkfd_fence { | |||||||
| 	struct mm_struct *mm; | 	struct mm_struct *mm; | ||||||
| 	spinlock_t lock; | 	spinlock_t lock; | ||||||
| 	char timeline_name[TASK_COMM_LEN]; | 	char timeline_name[TASK_COMM_LEN]; | ||||||
|  | 	struct svm_range_bo *svm_bo; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct amdgpu_kfd_dev { | struct amdgpu_kfd_dev { | ||||||
| @ -127,14 +142,15 @@ void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev, | |||||||
| 			const void *ih_ring_entry); | 			const void *ih_ring_entry); | ||||||
| void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev); | void amdgpu_amdkfd_device_probe(struct amdgpu_device *adev); | ||||||
| void amdgpu_amdkfd_device_init(struct amdgpu_device *adev); | void amdgpu_amdkfd_device_init(struct amdgpu_device *adev); | ||||||
| void amdgpu_amdkfd_device_fini(struct amdgpu_device *adev); | void amdgpu_amdkfd_device_fini_sw(struct amdgpu_device *adev); | ||||||
| int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine, | int amdgpu_amdkfd_submit_ib(struct kgd_dev *kgd, enum kgd_engine_type engine, | ||||||
| 				uint32_t vmid, uint64_t gpu_addr, | 				uint32_t vmid, uint64_t gpu_addr, | ||||||
| 				uint32_t *ib_cmd, uint32_t ib_len); | 				uint32_t *ib_cmd, uint32_t ib_len); | ||||||
| void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle); | void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle); | ||||||
| bool amdgpu_amdkfd_have_atomics_support(struct kgd_dev *kgd); | bool amdgpu_amdkfd_have_atomics_support(struct kgd_dev *kgd); | ||||||
| int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct kgd_dev *kgd, uint16_t vmid); | int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct kgd_dev *kgd, uint16_t vmid); | ||||||
| int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct kgd_dev *kgd, uint16_t pasid); | int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct kgd_dev *kgd, uint16_t pasid, | ||||||
|  | 				      enum TLB_FLUSH_TYPE flush_type); | ||||||
| 
 | 
 | ||||||
| bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); | bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); | ||||||
| 
 | 
 | ||||||
| @ -148,7 +164,8 @@ int amdgpu_queue_mask_bit_to_set_resource_bit(struct amdgpu_device *adev, | |||||||
| 					int queue_bit); | 					int queue_bit); | ||||||
| 
 | 
 | ||||||
| struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, | struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, | ||||||
| 								struct mm_struct *mm); | 				struct mm_struct *mm, | ||||||
|  | 				struct svm_range_bo *svm_bo); | ||||||
| #if IS_ENABLED(CONFIG_HSA_AMD) | #if IS_ENABLED(CONFIG_HSA_AMD) | ||||||
| bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm); | bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm); | ||||||
| struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f); | struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f); | ||||||
| @ -234,22 +251,27 @@ uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct kgd_dev *dst, struct kgd_dev *s | |||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| /* GPUVM API */ | /* GPUVM API */ | ||||||
|  | #define drm_priv_to_vm(drm_priv)					\ | ||||||
|  | 	(&((struct amdgpu_fpriv *)					\ | ||||||
|  | 		((struct drm_file *)(drm_priv))->driver_priv)->vm) | ||||||
|  | 
 | ||||||
| int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct kgd_dev *kgd, | int amdgpu_amdkfd_gpuvm_acquire_process_vm(struct kgd_dev *kgd, | ||||||
| 					struct file *filp, u32 pasid, | 					struct file *filp, u32 pasid, | ||||||
| 					void **vm, void **process_info, | 					void **process_info, | ||||||
| 					struct dma_fence **ef); | 					struct dma_fence **ef); | ||||||
| void amdgpu_amdkfd_gpuvm_release_process_vm(struct kgd_dev *kgd, void *vm); | void amdgpu_amdkfd_gpuvm_release_process_vm(struct kgd_dev *kgd, void *drm_priv); | ||||||
| uint64_t amdgpu_amdkfd_gpuvm_get_process_page_dir(void *vm); | uint64_t amdgpu_amdkfd_gpuvm_get_process_page_dir(void *drm_priv); | ||||||
| int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( | int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( | ||||||
| 		struct kgd_dev *kgd, uint64_t va, uint64_t size, | 		struct kgd_dev *kgd, uint64_t va, uint64_t size, | ||||||
| 		void *vm, struct kgd_mem **mem, | 		void *drm_priv, struct kgd_mem **mem, | ||||||
| 		uint64_t *offset, uint32_t flags); | 		uint64_t *offset, uint32_t flags); | ||||||
| int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( | int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( | ||||||
| 		struct kgd_dev *kgd, struct kgd_mem *mem, uint64_t *size); | 		struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv, | ||||||
|  | 		uint64_t *size); | ||||||
| int amdgpu_amdkfd_gpuvm_map_memory_to_gpu( | int amdgpu_amdkfd_gpuvm_map_memory_to_gpu( | ||||||
| 		struct kgd_dev *kgd, struct kgd_mem *mem, void *vm); | 		struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv, bool *table_freed); | ||||||
| int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( | int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( | ||||||
| 		struct kgd_dev *kgd, struct kgd_mem *mem, void *vm); | 		struct kgd_dev *kgd, struct kgd_mem *mem, void *drm_priv); | ||||||
| int amdgpu_amdkfd_gpuvm_sync_memory( | int amdgpu_amdkfd_gpuvm_sync_memory( | ||||||
| 		struct kgd_dev *kgd, struct kgd_mem *mem, bool intr); | 		struct kgd_dev *kgd, struct kgd_mem *mem, bool intr); | ||||||
| int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, | int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_dev *kgd, | ||||||
| @ -260,7 +282,7 @@ int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct kgd_dev *kgd, | |||||||
| 					      struct kfd_vm_fault_info *info); | 					      struct kfd_vm_fault_info *info); | ||||||
| int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd, | int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd, | ||||||
| 				      struct dma_buf *dmabuf, | 				      struct dma_buf *dmabuf, | ||||||
| 				      uint64_t va, void *vm, | 				      uint64_t va, void *drm_priv, | ||||||
| 				      struct kgd_mem **mem, uint64_t *size, | 				      struct kgd_mem **mem, uint64_t *size, | ||||||
| 				      uint64_t *mmap_offset); | 				      uint64_t *mmap_offset); | ||||||
| int amdgpu_amdkfd_get_tile_config(struct kgd_dev *kgd, | int amdgpu_amdkfd_get_tile_config(struct kgd_dev *kgd, | ||||||
| @ -270,6 +292,7 @@ void amdgpu_amdkfd_gpuvm_init_mem_limits(void); | |||||||
| void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev, | void amdgpu_amdkfd_gpuvm_destroy_cb(struct amdgpu_device *adev, | ||||||
| 				struct amdgpu_vm *vm); | 				struct amdgpu_vm *vm); | ||||||
| void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo); | void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo); | ||||||
|  | void amdgpu_amdkfd_reserve_system_mem(uint64_t size); | ||||||
| #else | #else | ||||||
| static inline | static inline | ||||||
| void amdgpu_amdkfd_gpuvm_init_mem_limits(void) | void amdgpu_amdkfd_gpuvm_init_mem_limits(void) | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ | |||||||
| #include <linux/firmware.h> | #include <linux/firmware.h> | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| #include "amdgpu_amdkfd.h" | #include "amdgpu_amdkfd.h" | ||||||
|  | #include "amdgpu_amdkfd_arcturus.h" | ||||||
| #include "sdma0/sdma0_4_2_2_offset.h" | #include "sdma0/sdma0_4_2_2_offset.h" | ||||||
| #include "sdma0/sdma0_4_2_2_sh_mask.h" | #include "sdma0/sdma0_4_2_2_sh_mask.h" | ||||||
| #include "sdma1/sdma1_4_2_2_offset.h" | #include "sdma1/sdma1_4_2_2_offset.h" | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ | |||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <linux/sched/mm.h> | #include <linux/sched/mm.h> | ||||||
| #include "amdgpu_amdkfd.h" | #include "amdgpu_amdkfd.h" | ||||||
|  | #include "kfd_svm.h" | ||||||
| 
 | 
 | ||||||
| static const struct dma_fence_ops amdkfd_fence_ops; | static const struct dma_fence_ops amdkfd_fence_ops; | ||||||
| static atomic_t fence_seq = ATOMIC_INIT(0); | static atomic_t fence_seq = ATOMIC_INIT(0); | ||||||
| @ -60,7 +61,8 @@ static atomic_t fence_seq = ATOMIC_INIT(0); | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, | struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, | ||||||
| 						       struct mm_struct *mm) | 				struct mm_struct *mm, | ||||||
|  | 				struct svm_range_bo *svm_bo) | ||||||
| { | { | ||||||
| 	struct amdgpu_amdkfd_fence *fence; | 	struct amdgpu_amdkfd_fence *fence; | ||||||
| 
 | 
 | ||||||
| @ -73,7 +75,7 @@ struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context, | |||||||
| 	fence->mm = mm; | 	fence->mm = mm; | ||||||
| 	get_task_comm(fence->timeline_name, current); | 	get_task_comm(fence->timeline_name, current); | ||||||
| 	spin_lock_init(&fence->lock); | 	spin_lock_init(&fence->lock); | ||||||
| 
 | 	fence->svm_bo = svm_bo; | ||||||
| 	dma_fence_init(&fence->base, &amdkfd_fence_ops, &fence->lock, | 	dma_fence_init(&fence->base, &amdkfd_fence_ops, &fence->lock, | ||||||
| 		   context, atomic_inc_return(&fence_seq)); | 		   context, atomic_inc_return(&fence_seq)); | ||||||
| 
 | 
 | ||||||
| @ -111,6 +113,8 @@ static const char *amdkfd_fence_get_timeline_name(struct dma_fence *f) | |||||||
|  *  a KFD BO and schedules a job to move the BO. |  *  a KFD BO and schedules a job to move the BO. | ||||||
|  *  If fence is already signaled return true. |  *  If fence is already signaled return true. | ||||||
|  *  If fence is not signaled schedule a evict KFD process work item. |  *  If fence is not signaled schedule a evict KFD process work item. | ||||||
|  |  * | ||||||
|  |  *  @f: dma_fence | ||||||
|  */ |  */ | ||||||
| static bool amdkfd_fence_enable_signaling(struct dma_fence *f) | static bool amdkfd_fence_enable_signaling(struct dma_fence *f) | ||||||
| { | { | ||||||
| @ -122,16 +126,20 @@ static bool amdkfd_fence_enable_signaling(struct dma_fence *f) | |||||||
| 	if (dma_fence_is_signaled(f)) | 	if (dma_fence_is_signaled(f)) | ||||||
| 		return true; | 		return true; | ||||||
| 
 | 
 | ||||||
|  | 	if (!fence->svm_bo) { | ||||||
| 		if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, f)) | 		if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, f)) | ||||||
| 			return true; | 			return true; | ||||||
| 
 | 	} else { | ||||||
|  | 		if (!svm_range_schedule_evict_svm_bo(fence)) | ||||||
|  | 			return true; | ||||||
|  | 	} | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdkfd_fence_release - callback that fence can be freed |  * amdkfd_fence_release - callback that fence can be freed | ||||||
|  * |  * | ||||||
|  * @fence: fence |  * @f: dma_fence | ||||||
|  * |  * | ||||||
|  * This function is called when the reference count becomes zero. |  * This function is called when the reference count becomes zero. | ||||||
|  * Drops the mm_struct reference and RCU schedules freeing up the fence. |  * Drops the mm_struct reference and RCU schedules freeing up the fence. | ||||||
|  | |||||||
| @ -96,8 +96,8 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, | |||||||
| 
 | 
 | ||||||
| 	lock_srbm(kgd, 0, 0, 0, vmid); | 	lock_srbm(kgd, 0, 0, 0, vmid); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmSH_MEM_CONFIG), sh_mem_config); | 	WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, sh_mem_config); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmSH_MEM_BASES), sh_mem_bases); | 	WREG32_SOC15(GC, 0, mmSH_MEM_BASES, sh_mem_bases); | ||||||
| 	/* APE1 no longer exists on GFX9 */ | 	/* APE1 no longer exists on GFX9 */ | ||||||
| 
 | 
 | ||||||
| 	unlock_srbm(kgd); | 	unlock_srbm(kgd); | ||||||
| @ -161,7 +161,7 @@ static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id) | |||||||
| 
 | 
 | ||||||
| 	lock_srbm(kgd, mec, pipe, 0, 0); | 	lock_srbm(kgd, mec, pipe, 0, 0); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCPC_INT_CNTL), | 	WREG32_SOC15(GC, 0, mmCPC_INT_CNTL, | ||||||
| 		CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | | 		CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | | ||||||
| 		CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); | 		CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); | ||||||
| 
 | 
 | ||||||
| @ -239,13 +239,13 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, | |||||||
| 
 | 
 | ||||||
| 	for (reg = hqd_base; | 	for (reg = hqd_base; | ||||||
| 	     reg <= SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_HI); reg++) | 	     reg <= SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_HI); reg++) | ||||||
| 		WREG32(reg, mqd_hqd[reg - hqd_base]); | 		WREG32_SOC15_IP(GC, reg, mqd_hqd[reg - hqd_base]); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/* Activate doorbell logic before triggering WPTR poll. */ | 	/* Activate doorbell logic before triggering WPTR poll. */ | ||||||
| 	data = REG_SET_FIELD(m->cp_hqd_pq_doorbell_control, | 	data = REG_SET_FIELD(m->cp_hqd_pq_doorbell_control, | ||||||
| 			     CP_HQD_PQ_DOORBELL_CONTROL, DOORBELL_EN, 1); | 			     CP_HQD_PQ_DOORBELL_CONTROL, DOORBELL_EN, 1); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_DOORBELL_CONTROL), data); | 	WREG32_SOC15(GC, 0, mmCP_HQD_PQ_DOORBELL_CONTROL, data); | ||||||
| 
 | 
 | ||||||
| 	if (wptr) { | 	if (wptr) { | ||||||
| 		/* Don't read wptr with get_user because the user
 | 		/* Don't read wptr with get_user because the user
 | ||||||
| @ -274,27 +274,27 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, | |||||||
| 		guessed_wptr += m->cp_hqd_pq_wptr_lo & ~(queue_size - 1); | 		guessed_wptr += m->cp_hqd_pq_wptr_lo & ~(queue_size - 1); | ||||||
| 		guessed_wptr += (uint64_t)m->cp_hqd_pq_wptr_hi << 32; | 		guessed_wptr += (uint64_t)m->cp_hqd_pq_wptr_hi << 32; | ||||||
| 
 | 
 | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_LO), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_LO, | ||||||
| 		       lower_32_bits(guessed_wptr)); | 		       lower_32_bits(guessed_wptr)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_HI), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_HI, | ||||||
| 		       upper_32_bits(guessed_wptr)); | 		       upper_32_bits(guessed_wptr)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR, | ||||||
| 		       lower_32_bits((uint64_t)wptr)); | 		       lower_32_bits((uint64_t)wptr)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI, | ||||||
| 		       upper_32_bits((uint64_t)wptr)); | 		       upper_32_bits((uint64_t)wptr)); | ||||||
| 		pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__, | 		pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__, | ||||||
| 			 (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | 			 (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1), | 		WREG32_SOC15(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1, | ||||||
| 		       (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | 		       (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Start the EOP fetcher */ | 	/* Start the EOP fetcher */ | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_EOP_RPTR), | 	WREG32_SOC15(GC, 0, mmCP_HQD_EOP_RPTR, | ||||||
| 	       REG_SET_FIELD(m->cp_hqd_eop_rptr, | 	       REG_SET_FIELD(m->cp_hqd_eop_rptr, | ||||||
| 			     CP_HQD_EOP_RPTR, INIT_FETCHER, 1)); | 			     CP_HQD_EOP_RPTR, INIT_FETCHER, 1)); | ||||||
| 
 | 
 | ||||||
| 	data = REG_SET_FIELD(m->cp_hqd_active, CP_HQD_ACTIVE, ACTIVE, 1); | 	data = REG_SET_FIELD(m->cp_hqd_active, CP_HQD_ACTIVE, ACTIVE, 1); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE), data); | 	WREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE, data); | ||||||
| 
 | 
 | ||||||
| 	release_queue(kgd); | 	release_queue(kgd); | ||||||
| 
 | 
 | ||||||
| @ -365,7 +365,7 @@ static int kgd_hqd_dump(struct kgd_dev *kgd, | |||||||
| 		if (WARN_ON_ONCE(i >= HQD_N_REGS))	\ | 		if (WARN_ON_ONCE(i >= HQD_N_REGS))	\ | ||||||
| 			break;				\ | 			break;				\ | ||||||
| 		(*dump)[i][0] = (addr) << 2;		\ | 		(*dump)[i][0] = (addr) << 2;		\ | ||||||
| 		(*dump)[i++][1] = RREG32(addr);		\ | 		(*dump)[i++][1] = RREG32_SOC15_IP(GC, addr);		\ | ||||||
| 	} while (0) | 	} while (0) | ||||||
| 
 | 
 | ||||||
| 	*dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); | 	*dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); | ||||||
| @ -497,13 +497,13 @@ static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, | |||||||
| 	uint32_t low, high; | 	uint32_t low, high; | ||||||
| 
 | 
 | ||||||
| 	acquire_queue(kgd, pipe_id, queue_id); | 	acquire_queue(kgd, pipe_id, queue_id); | ||||||
| 	act = RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE)); | 	act = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); | ||||||
| 	if (act) { | 	if (act) { | ||||||
| 		low = lower_32_bits(queue_address >> 8); | 		low = lower_32_bits(queue_address >> 8); | ||||||
| 		high = upper_32_bits(queue_address >> 8); | 		high = upper_32_bits(queue_address >> 8); | ||||||
| 
 | 
 | ||||||
| 		if (low == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE)) && | 		if (low == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE) && | ||||||
| 		   high == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE_HI))) | 		   high == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE_HI)) | ||||||
| 			retval = true; | 			retval = true; | ||||||
| 	} | 	} | ||||||
| 	release_queue(kgd); | 	release_queue(kgd); | ||||||
| @ -621,11 +621,11 @@ loop: | |||||||
| 	preempt_enable(); | 	preempt_enable(); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_DEQUEUE_REQUEST), type); | 	WREG32_SOC15(GC, 0, mmCP_HQD_DEQUEUE_REQUEST, type); | ||||||
| 
 | 
 | ||||||
| 	end_jiffies = (utimeout * HZ / 1000) + jiffies; | 	end_jiffies = (utimeout * HZ / 1000) + jiffies; | ||||||
| 	while (true) { | 	while (true) { | ||||||
| 		temp = RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE)); | 		temp = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); | ||||||
| 		if (!(temp & CP_HQD_ACTIVE__ACTIVE_MASK)) | 		if (!(temp & CP_HQD_ACTIVE__ACTIVE_MASK)) | ||||||
| 			break; | 			break; | ||||||
| 		if (time_after(jiffies, end_jiffies)) { | 		if (time_after(jiffies, end_jiffies)) { | ||||||
| @ -716,8 +716,8 @@ static int kgd_wave_control_execute(struct kgd_dev *kgd, | |||||||
| 
 | 
 | ||||||
| 	mutex_lock(&adev->grbm_idx_mutex); | 	mutex_lock(&adev->grbm_idx_mutex); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmGRBM_GFX_INDEX), gfx_index_val); | 	WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, gfx_index_val); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_CMD), sq_cmd); | 	WREG32_SOC15(GC, 0, mmSQ_CMD, sq_cmd); | ||||||
| 
 | 
 | ||||||
| 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | ||||||
| 		INSTANCE_BROADCAST_WRITES, 1); | 		INSTANCE_BROADCAST_WRITES, 1); | ||||||
| @ -726,7 +726,7 @@ static int kgd_wave_control_execute(struct kgd_dev *kgd, | |||||||
| 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | ||||||
| 		SE_BROADCAST_WRITES, 1); | 		SE_BROADCAST_WRITES, 1); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmGRBM_GFX_INDEX), data); | 	WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, data); | ||||||
| 	mutex_unlock(&adev->grbm_idx_mutex); | 	mutex_unlock(&adev->grbm_idx_mutex); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | |||||||
| @ -95,8 +95,8 @@ static void program_sh_mem_settings_v10_3(struct kgd_dev *kgd, uint32_t vmid, | |||||||
| 
 | 
 | ||||||
| 	lock_srbm(kgd, 0, 0, 0, vmid); | 	lock_srbm(kgd, 0, 0, 0, vmid); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmSH_MEM_CONFIG), sh_mem_config); | 	WREG32_SOC15(GC, 0, mmSH_MEM_CONFIG, sh_mem_config); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmSH_MEM_BASES), sh_mem_bases); | 	WREG32_SOC15(GC, 0, mmSH_MEM_BASES, sh_mem_bases); | ||||||
| 	/* APE1 no longer exists on GFX9 */ | 	/* APE1 no longer exists on GFX9 */ | ||||||
| 
 | 
 | ||||||
| 	unlock_srbm(kgd); | 	unlock_srbm(kgd); | ||||||
| @ -129,7 +129,7 @@ static int init_interrupts_v10_3(struct kgd_dev *kgd, uint32_t pipe_id) | |||||||
| 
 | 
 | ||||||
| 	lock_srbm(kgd, mec, pipe, 0, 0); | 	lock_srbm(kgd, mec, pipe, 0, 0); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCPC_INT_CNTL), | 	WREG32_SOC15(GC, 0, mmCPC_INT_CNTL, | ||||||
| 		CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | | 		CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | | ||||||
| 		CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); | 		CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); | ||||||
| 
 | 
 | ||||||
| @ -212,10 +212,10 @@ static int hqd_load_v10_3(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, | |||||||
| 
 | 
 | ||||||
| 		pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n", | 		pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n", | ||||||
| 			mec, pipe, queue_id); | 			mec, pipe, queue_id); | ||||||
| 		value = RREG32(SOC15_REG_OFFSET(GC, 0, mmRLC_CP_SCHEDULERS)); | 		value = RREG32_SOC15(GC, 0, mmRLC_CP_SCHEDULERS); | ||||||
| 		value = REG_SET_FIELD(value, RLC_CP_SCHEDULERS, scheduler1, | 		value = REG_SET_FIELD(value, RLC_CP_SCHEDULERS, scheduler1, | ||||||
| 			((mec << 5) | (pipe << 3) | queue_id | 0x80)); | 			((mec << 5) | (pipe << 3) | queue_id | 0x80)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmRLC_CP_SCHEDULERS), value); | 		WREG32_SOC15(GC, 0, mmRLC_CP_SCHEDULERS, value); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* HQD registers extend from CP_MQD_BASE_ADDR to CP_HQD_EOP_WPTR_MEM. */ | 	/* HQD registers extend from CP_MQD_BASE_ADDR to CP_HQD_EOP_WPTR_MEM. */ | ||||||
| @ -224,13 +224,13 @@ static int hqd_load_v10_3(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, | |||||||
| 
 | 
 | ||||||
| 	for (reg = hqd_base; | 	for (reg = hqd_base; | ||||||
| 	     reg <= SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_HI); reg++) | 	     reg <= SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_HI); reg++) | ||||||
| 		WREG32(reg, mqd_hqd[reg - hqd_base]); | 		WREG32_SOC15_IP(GC, reg, mqd_hqd[reg - hqd_base]); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/* Activate doorbell logic before triggering WPTR poll. */ | 	/* Activate doorbell logic before triggering WPTR poll. */ | ||||||
| 	data = REG_SET_FIELD(m->cp_hqd_pq_doorbell_control, | 	data = REG_SET_FIELD(m->cp_hqd_pq_doorbell_control, | ||||||
| 			     CP_HQD_PQ_DOORBELL_CONTROL, DOORBELL_EN, 1); | 			     CP_HQD_PQ_DOORBELL_CONTROL, DOORBELL_EN, 1); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_DOORBELL_CONTROL), data); | 	WREG32_SOC15(GC, 0, mmCP_HQD_PQ_DOORBELL_CONTROL, data); | ||||||
| 
 | 
 | ||||||
| 	if (wptr) { | 	if (wptr) { | ||||||
| 		/* Don't read wptr with get_user because the user
 | 		/* Don't read wptr with get_user because the user
 | ||||||
| @ -259,17 +259,17 @@ static int hqd_load_v10_3(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, | |||||||
| 		guessed_wptr += m->cp_hqd_pq_wptr_lo & ~(queue_size - 1); | 		guessed_wptr += m->cp_hqd_pq_wptr_lo & ~(queue_size - 1); | ||||||
| 		guessed_wptr += (uint64_t)m->cp_hqd_pq_wptr_hi << 32; | 		guessed_wptr += (uint64_t)m->cp_hqd_pq_wptr_hi << 32; | ||||||
| 
 | 
 | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_LO), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_LO, | ||||||
| 		       lower_32_bits(guessed_wptr)); | 		       lower_32_bits(guessed_wptr)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_HI), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_HI, | ||||||
| 		       upper_32_bits(guessed_wptr)); | 		       upper_32_bits(guessed_wptr)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR, | ||||||
| 		       lower_32_bits((uint64_t)wptr)); | 		       lower_32_bits((uint64_t)wptr)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI), | 		WREG32_SOC15(GC, 0, mmCP_HQD_PQ_WPTR_POLL_ADDR_HI, | ||||||
| 		       upper_32_bits((uint64_t)wptr)); | 		       upper_32_bits((uint64_t)wptr)); | ||||||
| 		pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__, | 		pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__, | ||||||
| 			 (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | 			 (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | ||||||
| 		WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1), | 		WREG32_SOC15(GC, 0, mmCP_PQ_WPTR_POLL_CNTL1, | ||||||
| 		       (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | 		       (uint32_t)get_queue_mask(adev, pipe_id, queue_id)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -279,7 +279,7 @@ static int hqd_load_v10_3(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, | |||||||
| 			     CP_HQD_EOP_RPTR, INIT_FETCHER, 1)); | 			     CP_HQD_EOP_RPTR, INIT_FETCHER, 1)); | ||||||
| 
 | 
 | ||||||
| 	data = REG_SET_FIELD(m->cp_hqd_active, CP_HQD_ACTIVE, ACTIVE, 1); | 	data = REG_SET_FIELD(m->cp_hqd_active, CP_HQD_ACTIVE, ACTIVE, 1); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE), data); | 	WREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE, data); | ||||||
| 
 | 
 | ||||||
| 	release_queue(kgd); | 	release_queue(kgd); | ||||||
| 
 | 
 | ||||||
| @ -350,7 +350,7 @@ static int hqd_dump_v10_3(struct kgd_dev *kgd, | |||||||
| 		if (WARN_ON_ONCE(i >= HQD_N_REGS))	\ | 		if (WARN_ON_ONCE(i >= HQD_N_REGS))	\ | ||||||
| 			break;				\ | 			break;				\ | ||||||
| 		(*dump)[i][0] = (addr) << 2;		\ | 		(*dump)[i][0] = (addr) << 2;		\ | ||||||
| 		(*dump)[i++][1] = RREG32(addr);		\ | 		(*dump)[i++][1] = RREG32_SOC15_IP(GC, addr);		\ | ||||||
| 	} while (0) | 	} while (0) | ||||||
| 
 | 
 | ||||||
| 	*dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); | 	*dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL); | ||||||
| @ -482,13 +482,13 @@ static bool hqd_is_occupied_v10_3(struct kgd_dev *kgd, uint64_t queue_address, | |||||||
| 	uint32_t low, high; | 	uint32_t low, high; | ||||||
| 
 | 
 | ||||||
| 	acquire_queue(kgd, pipe_id, queue_id); | 	acquire_queue(kgd, pipe_id, queue_id); | ||||||
| 	act = RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE)); | 	act = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); | ||||||
| 	if (act) { | 	if (act) { | ||||||
| 		low = lower_32_bits(queue_address >> 8); | 		low = lower_32_bits(queue_address >> 8); | ||||||
| 		high = upper_32_bits(queue_address >> 8); | 		high = upper_32_bits(queue_address >> 8); | ||||||
| 
 | 
 | ||||||
| 		if (low == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE)) && | 		if (low == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE) && | ||||||
| 		   high == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE_HI))) | 		   high == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE_HI)) | ||||||
| 			retval = true; | 			retval = true; | ||||||
| 	} | 	} | ||||||
| 	release_queue(kgd); | 	release_queue(kgd); | ||||||
| @ -542,11 +542,11 @@ static int hqd_destroy_v10_3(struct kgd_dev *kgd, void *mqd, | |||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_DEQUEUE_REQUEST), type); | 	WREG32_SOC15(GC, 0, mmCP_HQD_DEQUEUE_REQUEST, type); | ||||||
| 
 | 
 | ||||||
| 	end_jiffies = (utimeout * HZ / 1000) + jiffies; | 	end_jiffies = (utimeout * HZ / 1000) + jiffies; | ||||||
| 	while (true) { | 	while (true) { | ||||||
| 		temp = RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_ACTIVE)); | 		temp = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE); | ||||||
| 		if (!(temp & CP_HQD_ACTIVE__ACTIVE_MASK)) | 		if (!(temp & CP_HQD_ACTIVE__ACTIVE_MASK)) | ||||||
| 			break; | 			break; | ||||||
| 		if (time_after(jiffies, end_jiffies)) { | 		if (time_after(jiffies, end_jiffies)) { | ||||||
| @ -626,7 +626,7 @@ static int wave_control_execute_v10_3(struct kgd_dev *kgd, | |||||||
| 
 | 
 | ||||||
| 	mutex_lock(&adev->grbm_idx_mutex); | 	mutex_lock(&adev->grbm_idx_mutex); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmGRBM_GFX_INDEX), gfx_index_val); | 	WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, gfx_index_val); | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_CMD), sq_cmd); | 	WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_CMD), sq_cmd); | ||||||
| 
 | 
 | ||||||
| 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | ||||||
| @ -636,7 +636,7 @@ static int wave_control_execute_v10_3(struct kgd_dev *kgd, | |||||||
| 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | 	data = REG_SET_FIELD(data, GRBM_GFX_INDEX, | ||||||
| 		SE_BROADCAST_WRITES, 1); | 		SE_BROADCAST_WRITES, 1); | ||||||
| 
 | 
 | ||||||
| 	WREG32(SOC15_REG_OFFSET(GC, 0, mmGRBM_GFX_INDEX), data); | 	WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, data); | ||||||
| 	mutex_unlock(&adev->grbm_idx_mutex); | 	mutex_unlock(&adev->grbm_idx_mutex); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | |||||||
| @ -719,7 +719,7 @@ static void unlock_spi_csq_mutexes(struct amdgpu_device *adev) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @get_wave_count: Read device registers to get number of waves in flight for |  * get_wave_count: Read device registers to get number of waves in flight for | ||||||
|  * a particular queue. The method also returns the VMID associated with the |  * a particular queue. The method also returns the VMID associated with the | ||||||
|  * queue. |  * queue. | ||||||
|  * |  * | ||||||
| @ -755,19 +755,19 @@ static void get_wave_count(struct amdgpu_device *adev, int queue_idx, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * @kgd_gfx_v9_get_cu_occupancy: Reads relevant registers associated with each |  * kgd_gfx_v9_get_cu_occupancy: Reads relevant registers associated with each | ||||||
|  * shader engine and aggregates the number of waves that are in flight for the |  * shader engine and aggregates the number of waves that are in flight for the | ||||||
|  * process whose pasid is provided as a parameter. The process could have ZERO |  * process whose pasid is provided as a parameter. The process could have ZERO | ||||||
|  * or more queues running and submitting waves to compute units. |  * or more queues running and submitting waves to compute units. | ||||||
|  * |  * | ||||||
|  * @kgd: Handle of device from which to get number of waves in flight |  * @kgd: Handle of device from which to get number of waves in flight | ||||||
|  * @pasid: Identifies the process for which this query call is invoked |  * @pasid: Identifies the process for which this query call is invoked | ||||||
|  * @wave_cnt: Output parameter updated with number of waves in flight that |  * @pasid_wave_cnt: Output parameter updated with number of waves in flight that | ||||||
|  * belong to process with given pasid |  * belong to process with given pasid | ||||||
|  * @max_waves_per_cu: Output parameter updated with maximum number of waves |  * @max_waves_per_cu: Output parameter updated with maximum number of waves | ||||||
|  * possible per Compute Unit |  * possible per Compute Unit | ||||||
|  * |  * | ||||||
|  * @note: It's possible that the device has too many queues (oversubscription) |  * Note: It's possible that the device has too many queues (oversubscription) | ||||||
|  * in which case a VMID could be remapped to a different PASID. This could lead |  * in which case a VMID could be remapped to a different PASID. This could lead | ||||||
|  * to an iaccurate wave count. Following is a high-level sequence: |  * to an iaccurate wave count. Following is a high-level sequence: | ||||||
|  *    Time T1: vmid = getVmid(); vmid is associated with Pasid P1 |  *    Time T1: vmid = getVmid(); vmid is associated with Pasid P1 | ||||||
|  | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1768,6 +1768,15 @@ static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev, | |||||||
| static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version, | static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version, | ||||||
| 		   NULL); | 		   NULL); | ||||||
| 
 | 
 | ||||||
|  | static struct attribute *amdgpu_vbios_version_attrs[] = { | ||||||
|  | 	&dev_attr_vbios_version.attr, | ||||||
|  | 	NULL | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const struct attribute_group amdgpu_vbios_version_attr_group = { | ||||||
|  | 	.attrs = amdgpu_vbios_version_attrs | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_atombios_fini - free the driver info and callbacks for atombios |  * amdgpu_atombios_fini - free the driver info and callbacks for atombios | ||||||
|  * |  * | ||||||
| @ -1787,7 +1796,6 @@ void amdgpu_atombios_fini(struct amdgpu_device *adev) | |||||||
| 	adev->mode_info.atom_context = NULL; | 	adev->mode_info.atom_context = NULL; | ||||||
| 	kfree(adev->mode_info.atom_card_info); | 	kfree(adev->mode_info.atom_card_info); | ||||||
| 	adev->mode_info.atom_card_info = NULL; | 	adev->mode_info.atom_card_info = NULL; | ||||||
| 	device_remove_file(adev->dev, &dev_attr_vbios_version); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -1804,7 +1812,6 @@ int amdgpu_atombios_init(struct amdgpu_device *adev) | |||||||
| { | { | ||||||
| 	struct card_info *atom_card_info = | 	struct card_info *atom_card_info = | ||||||
| 	    kzalloc(sizeof(struct card_info), GFP_KERNEL); | 	    kzalloc(sizeof(struct card_info), GFP_KERNEL); | ||||||
| 	int ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (!atom_card_info) | 	if (!atom_card_info) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| @ -1828,17 +1835,14 @@ int amdgpu_atombios_init(struct amdgpu_device *adev) | |||||||
| 	if (adev->is_atom_fw) { | 	if (adev->is_atom_fw) { | ||||||
| 		amdgpu_atomfirmware_scratch_regs_init(adev); | 		amdgpu_atomfirmware_scratch_regs_init(adev); | ||||||
| 		amdgpu_atomfirmware_allocate_fb_scratch(adev); | 		amdgpu_atomfirmware_allocate_fb_scratch(adev); | ||||||
|  | 		/* cached firmware_flags for further usage */ | ||||||
|  | 		adev->mode_info.firmware_flags = | ||||||
|  | 			amdgpu_atomfirmware_query_firmware_capability(adev); | ||||||
| 	} else { | 	} else { | ||||||
| 		amdgpu_atombios_scratch_regs_init(adev); | 		amdgpu_atombios_scratch_regs_init(adev); | ||||||
| 		amdgpu_atombios_allocate_fb_scratch(adev); | 		amdgpu_atombios_allocate_fb_scratch(adev); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = device_create_file(adev->dev, &dev_attr_vbios_version); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_ERROR("Failed to create device file for VBIOS version\n"); |  | ||||||
| 		return ret; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -29,23 +29,59 @@ | |||||||
| #include "atombios.h" | #include "atombios.h" | ||||||
| #include "soc15_hw_ip.h" | #include "soc15_hw_ip.h" | ||||||
| 
 | 
 | ||||||
| bool amdgpu_atomfirmware_gpu_supports_virtualization(struct amdgpu_device *adev) | union firmware_info { | ||||||
|  | 	struct atom_firmware_info_v3_1 v31; | ||||||
|  | 	struct atom_firmware_info_v3_2 v32; | ||||||
|  | 	struct atom_firmware_info_v3_3 v33; | ||||||
|  | 	struct atom_firmware_info_v3_4 v34; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Helper function to query firmware capability | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Return firmware_capability in firmwareinfo table on success or 0 if not | ||||||
|  |  */ | ||||||
|  | uint32_t amdgpu_atomfirmware_query_firmware_capability(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	int index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | 	struct amdgpu_mode_info *mode_info = &adev->mode_info; | ||||||
|  | 	int index; | ||||||
|  | 	u16 data_offset, size; | ||||||
|  | 	union firmware_info *firmware_info; | ||||||
|  | 	u8 frev, crev; | ||||||
|  | 	u32 fw_cap = 0; | ||||||
|  | 
 | ||||||
|  | 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | ||||||
| 			firmwareinfo); | 			firmwareinfo); | ||||||
| 	uint16_t data_offset; |  | ||||||
| 
 | 
 | ||||||
| 	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, NULL, | 	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, | ||||||
| 					  NULL, NULL, &data_offset)) { | 				index, &size, &frev, &crev, &data_offset)) { | ||||||
| 		struct atom_firmware_info_v3_1 *firmware_info = | 		/* support firmware_info 3.1 + */ | ||||||
| 			(struct atom_firmware_info_v3_1 *)(adev->mode_info.atom_context->bios + | 		if ((frev == 3 && crev >=1) || (frev > 3)) { | ||||||
| 							   data_offset); | 			firmware_info = (union firmware_info *) | ||||||
| 
 | 				(mode_info->atom_context->bios + data_offset); | ||||||
| 		if (le32_to_cpu(firmware_info->firmware_capability) & | 			fw_cap = le32_to_cpu(firmware_info->v31.firmware_capability); | ||||||
| 		    ATOM_FIRMWARE_CAP_GPU_VIRTUALIZATION) |  | ||||||
| 			return true; |  | ||||||
| 		} | 		} | ||||||
| 	return false; | 	} | ||||||
|  | 
 | ||||||
|  | 	return fw_cap; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Helper function to query gpu virtualizaiton capability | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Return true if gpu virtualization is supported or false if not | ||||||
|  |  */ | ||||||
|  | bool amdgpu_atomfirmware_gpu_virtualization_supported(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	u32 fw_cap; | ||||||
|  | 
 | ||||||
|  | 	fw_cap = adev->mode_info.firmware_flags; | ||||||
|  | 
 | ||||||
|  | 	return (fw_cap & ATOM_FIRMWARE_CAP_GPU_VIRTUALIZATION) ? true : false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev) | void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev) | ||||||
| @ -400,41 +436,36 @@ bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev) | |||||||
| 	return ecc_default_enabled; | 	return ecc_default_enabled; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| union firmware_info { |  | ||||||
| 	struct atom_firmware_info_v3_1 v31; |  | ||||||
| 	struct atom_firmware_info_v3_2 v32; |  | ||||||
| 	struct atom_firmware_info_v3_3 v33; |  | ||||||
| 	struct atom_firmware_info_v3_4 v34; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  |  * Helper function to query sram ecc capablity | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  * Return true if vbios supports sram ecc or false if not |  * Return true if vbios supports sram ecc or false if not | ||||||
|  */ |  */ | ||||||
| bool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev) | bool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	struct amdgpu_mode_info *mode_info = &adev->mode_info; | 	u32 fw_cap; | ||||||
| 	int index; |  | ||||||
| 	u16 data_offset, size; |  | ||||||
| 	union firmware_info *firmware_info; |  | ||||||
| 	u8 frev, crev; |  | ||||||
| 	bool sram_ecc_supported = false; |  | ||||||
| 
 | 
 | ||||||
| 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | 	fw_cap = adev->mode_info.firmware_flags; | ||||||
| 			firmwareinfo); |  | ||||||
| 
 | 
 | ||||||
| 	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, | 	return (fw_cap & ATOM_FIRMWARE_CAP_SRAM_ECC) ? true : false; | ||||||
| 				index, &size, &frev, &crev, &data_offset)) { |  | ||||||
| 		/* support firmware_info 3.1 + */ |  | ||||||
| 		if ((frev == 3 && crev >=1) || (frev > 3)) { |  | ||||||
| 			firmware_info = (union firmware_info *) |  | ||||||
| 				(mode_info->atom_context->bios + data_offset); |  | ||||||
| 			sram_ecc_supported = |  | ||||||
| 				(le32_to_cpu(firmware_info->v31.firmware_capability) & |  | ||||||
| 				 ATOM_FIRMWARE_CAP_SRAM_ECC) ? true : false; |  | ||||||
| 		} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 	return sram_ecc_supported; | /*
 | ||||||
|  |  * Helper function to query dynamic boot config capability | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Return true if vbios supports dynamic boot config or false if not | ||||||
|  |  */ | ||||||
|  | bool amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	u32 fw_cap; | ||||||
|  | 
 | ||||||
|  | 	fw_cap = adev->mode_info.firmware_flags; | ||||||
|  | 
 | ||||||
|  | 	return (fw_cap & ATOM_FIRMWARE_CAP_DYNAMIC_BOOT_CFG_ENABLE) ? true : false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| union smu_info { | union smu_info { | ||||||
| @ -466,10 +497,6 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev) | |||||||
| 		adev->pm.current_sclk = adev->clock.default_sclk; | 		adev->pm.current_sclk = adev->clock.default_sclk; | ||||||
| 		adev->pm.current_mclk = adev->clock.default_mclk; | 		adev->pm.current_mclk = adev->clock.default_mclk; | ||||||
| 
 | 
 | ||||||
| 		/* not technically a clock, but... */ |  | ||||||
| 		adev->mode_info.firmware_flags = |  | ||||||
| 			le32_to_cpu(firmware_info->v31.firmware_capability); |  | ||||||
| 
 |  | ||||||
| 		ret = 0; | 		ret = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -519,6 +546,21 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev) | |||||||
| 		ret = 0; | 		ret = 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/* if asic is Navi+, the rlc reference clock is used for system clock
 | ||||||
|  | 	 * from vbios gfx_info table */ | ||||||
|  | 	if (adev->asic_type >= CHIP_NAVI10) { | ||||||
|  | 		index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | ||||||
|  | 						   gfx_info); | ||||||
|  | 		if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL, | ||||||
|  | 					  &frev, &crev, &data_offset)) { | ||||||
|  | 			struct atom_gfx_info_v2_2 *gfx_info = (struct atom_gfx_info_v2_2*) | ||||||
|  | 				(mode_info->atom_context->bios + data_offset); | ||||||
|  | 			if ((frev == 2) && (crev >= 2)) | ||||||
|  | 				spll->reference_freq = le32_to_cpu(gfx_info->rlc_gpu_timer_refclk); | ||||||
|  | 			ret = 0; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -584,67 +626,19 @@ int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Check if VBIOS supports GDDR6 training data save/restore |  * Helper function to query two stage mem training capability | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Return true if two stage mem training is supported or false if not | ||||||
|  */ |  */ | ||||||
| static bool gddr6_mem_train_vbios_support(struct amdgpu_device *adev) | bool amdgpu_atomfirmware_mem_training_supported(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	uint16_t data_offset; | 	u32 fw_cap; | ||||||
| 	int index; |  | ||||||
| 
 | 
 | ||||||
| 	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, | 	fw_cap = adev->mode_info.firmware_flags; | ||||||
| 					    firmwareinfo); |  | ||||||
| 	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, NULL, |  | ||||||
| 					  NULL, NULL, &data_offset)) { |  | ||||||
| 		struct atom_firmware_info_v3_1 *firmware_info = |  | ||||||
| 			(struct atom_firmware_info_v3_1 *)(adev->mode_info.atom_context->bios + |  | ||||||
| 							   data_offset); |  | ||||||
| 
 | 
 | ||||||
| 		DRM_DEBUG("atom firmware capability:0x%08x.\n", | 	return (fw_cap & ATOM_FIRMWARE_CAP_ENABLE_2STAGE_BIST_TRAINING) ? true : false; | ||||||
| 			  le32_to_cpu(firmware_info->firmware_capability)); |  | ||||||
| 
 |  | ||||||
| 		if (le32_to_cpu(firmware_info->firmware_capability) & |  | ||||||
| 		    ATOM_FIRMWARE_CAP_ENABLE_2STAGE_BIST_TRAINING) |  | ||||||
| 			return true; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return false; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int amdgpu_mem_train_support(struct amdgpu_device *adev) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
| 	uint32_t major, minor, revision, hw_v; |  | ||||||
| 
 |  | ||||||
| 	if (gddr6_mem_train_vbios_support(adev)) { |  | ||||||
| 		amdgpu_discovery_get_ip_version(adev, MP0_HWID, &major, &minor, &revision); |  | ||||||
| 		hw_v = HW_REV(major, minor, revision); |  | ||||||
| 		/*
 |  | ||||||
| 		 * treat 0 revision as a special case since register for MP0 and MMHUB is missing |  | ||||||
| 		 * for some Navi10 A0, preventing driver from discovering the hwip information since |  | ||||||
| 		 * none of the functions will be initialized, it should not cause any problems |  | ||||||
| 		 */ |  | ||||||
| 		switch (hw_v) { |  | ||||||
| 		case HW_REV(11, 0, 0): |  | ||||||
| 		case HW_REV(11, 0, 5): |  | ||||||
| 		case HW_REV(11, 0, 7): |  | ||||||
| 		case HW_REV(11, 0, 11): |  | ||||||
| 		case HW_REV(11, 0, 12): |  | ||||||
| 			ret = 1; |  | ||||||
| 			break; |  | ||||||
| 		default: |  | ||||||
| 			DRM_ERROR("memory training vbios supports but psp hw(%08x)" |  | ||||||
| 				  " doesn't support!\n", hw_v); |  | ||||||
| 			ret = -1; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		ret = 0; |  | ||||||
| 		hw_v = -1; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	DRM_DEBUG("mp0 hw_v %08x, ret:%d.\n", hw_v, ret); |  | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev) | int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev) | ||||||
|  | |||||||
| @ -26,7 +26,8 @@ | |||||||
| 
 | 
 | ||||||
| #define get_index_into_master_table(master_table, table_name) (offsetof(struct master_table, table_name) / sizeof(uint16_t)) | #define get_index_into_master_table(master_table, table_name) (offsetof(struct master_table, table_name) / sizeof(uint16_t)) | ||||||
| 
 | 
 | ||||||
| bool amdgpu_atomfirmware_gpu_supports_virtualization(struct amdgpu_device *adev); | uint32_t amdgpu_atomfirmware_query_firmware_capability(struct amdgpu_device *adev); | ||||||
|  | bool amdgpu_atomfirmware_gpu_virtualization_supported(struct amdgpu_device *adev); | ||||||
| void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev); | void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev); | ||||||
| int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev); | int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev); | ||||||
| int amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev, | int amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev, | ||||||
| @ -35,7 +36,8 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev); | |||||||
| int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev); | int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev); | ||||||
| bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev); | bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev); | ||||||
| bool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev); | bool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev); | ||||||
|  | bool amdgpu_atomfirmware_mem_training_supported(struct amdgpu_device *adev); | ||||||
|  | bool amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device *adev); | ||||||
| int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev); | int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev); | ||||||
| int amdgpu_mem_train_support(struct amdgpu_device *adev); |  | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -396,10 +396,10 @@ void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes, | |||||||
| 	spin_unlock(&adev->mm_stats.lock); | 	spin_unlock(&adev->mm_stats.lock); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p, | static int amdgpu_cs_bo_validate(void *param, struct amdgpu_bo *bo) | ||||||
| 				 struct amdgpu_bo *bo) |  | ||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | ||||||
|  | 	struct amdgpu_cs_parser *p = param; | ||||||
| 	struct ttm_operation_ctx ctx = { | 	struct ttm_operation_ctx ctx = { | ||||||
| 		.interruptible = true, | 		.interruptible = true, | ||||||
| 		.no_wait_gpu = false, | 		.no_wait_gpu = false, | ||||||
| @ -451,21 +451,6 @@ retry: | |||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int amdgpu_cs_validate(void *param, struct amdgpu_bo *bo) |  | ||||||
| { |  | ||||||
| 	struct amdgpu_cs_parser *p = param; |  | ||||||
| 	int r; |  | ||||||
| 
 |  | ||||||
| 	r = amdgpu_cs_bo_validate(p, bo); |  | ||||||
| 	if (r) |  | ||||||
| 		return r; |  | ||||||
| 
 |  | ||||||
| 	if (bo->shadow) |  | ||||||
| 		r = amdgpu_cs_bo_validate(p, bo->shadow); |  | ||||||
| 
 |  | ||||||
| 	return r; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, | static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, | ||||||
| 			    struct list_head *validated) | 			    struct list_head *validated) | ||||||
| { | { | ||||||
| @ -493,7 +478,7 @@ static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p, | |||||||
| 						     lobj->user_pages); | 						     lobj->user_pages); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		r = amdgpu_cs_validate(p, bo); | 		r = amdgpu_cs_bo_validate(p, bo); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			return r; | 			return r; | ||||||
| 
 | 
 | ||||||
| @ -593,7 +578,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, | |||||||
| 	p->bytes_moved_vis = 0; | 	p->bytes_moved_vis = 0; | ||||||
| 
 | 
 | ||||||
| 	r = amdgpu_vm_validate_pt_bos(p->adev, &fpriv->vm, | 	r = amdgpu_vm_validate_pt_bos(p->adev, &fpriv->vm, | ||||||
| 				      amdgpu_cs_validate, p); | 				      amdgpu_cs_bo_validate, p); | ||||||
| 	if (r) { | 	if (r) { | ||||||
| 		DRM_ERROR("amdgpu_vm_validate_pt_bos() failed.\n"); | 		DRM_ERROR("amdgpu_vm_validate_pt_bos() failed.\n"); | ||||||
| 		goto error_validate; | 		goto error_validate; | ||||||
| @ -672,12 +657,12 @@ static int amdgpu_cs_sync_rings(struct amdgpu_cs_parser *p) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * cs_parser_fini() - clean parser states |  * amdgpu_cs_parser_fini() - clean parser states | ||||||
|  * @parser:	parser structure holding parsing context. |  * @parser:	parser structure holding parsing context. | ||||||
|  * @error:	error number |  * @error:	error number | ||||||
|  * @backoff:	indicator to backoff the reservation |  * @backoff:	indicator to backoff the reservation | ||||||
|  * |  * | ||||||
|  * If error is set than unvalidate buffer, otherwise just free memory |  * If error is set then unvalidate buffer, otherwise just free memory | ||||||
|  * used by parsing context. |  * used by parsing context. | ||||||
|  **/ |  **/ | ||||||
| static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, | static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, | ||||||
| @ -796,7 +781,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) | |||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| 	r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false); | 	r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false, NULL); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| @ -807,7 +792,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) | |||||||
| 	if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) { | 	if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) { | ||||||
| 		bo_va = fpriv->csa_va; | 		bo_va = fpriv->csa_va; | ||||||
| 		BUG_ON(!bo_va); | 		BUG_ON(!bo_va); | ||||||
| 		r = amdgpu_vm_bo_update(adev, bo_va, false); | 		r = amdgpu_vm_bo_update(adev, bo_va, false, NULL); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			return r; | 			return r; | ||||||
| 
 | 
 | ||||||
| @ -826,7 +811,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) | |||||||
| 		if (bo_va == NULL) | 		if (bo_va == NULL) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		r = amdgpu_vm_bo_update(adev, bo_va, false); | 		r = amdgpu_vm_bo_update(adev, bo_va, false, NULL); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			return r; | 			return r; | ||||||
| 
 | 
 | ||||||
| @ -847,7 +832,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p) | |||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| 	p->job->vm_pd_addr = amdgpu_gmc_pd_addr(vm->root.base.bo); | 	p->job->vm_pd_addr = amdgpu_gmc_pd_addr(vm->root.bo); | ||||||
| 
 | 
 | ||||||
| 	if (amdgpu_vm_debug) { | 	if (amdgpu_vm_debug) { | ||||||
| 		/* Invalidate all BOs to test for userspace bugs */ | 		/* Invalidate all BOs to test for userspace bugs */ | ||||||
| @ -1488,7 +1473,7 @@ int amdgpu_cs_fence_to_handle_ioctl(struct drm_device *dev, void *data, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_cs_wait_all_fence - wait on all fences to signal |  * amdgpu_cs_wait_all_fences - wait on all fences to signal | ||||||
|  * |  * | ||||||
|  * @adev: amdgpu device |  * @adev: amdgpu device | ||||||
|  * @filp: file private |  * @filp: file private | ||||||
| @ -1639,7 +1624,7 @@ err_free_fences: | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_cs_find_bo_va - find bo_va for VM address |  * amdgpu_cs_find_mapping - find bo_va for VM address | ||||||
|  * |  * | ||||||
|  * @parser: command submission parser context |  * @parser: command submission parser context | ||||||
|  * @addr: VM address |  * @addr: VM address | ||||||
|  | |||||||
| @ -331,10 +331,13 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev, | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define AMDGPU_RAS_COUNTE_DELAY_MS 3000 | ||||||
|  | 
 | ||||||
| static int amdgpu_ctx_query2(struct amdgpu_device *adev, | static int amdgpu_ctx_query2(struct amdgpu_device *adev, | ||||||
| 			     struct amdgpu_fpriv *fpriv, uint32_t id, | 			     struct amdgpu_fpriv *fpriv, uint32_t id, | ||||||
| 			     union drm_amdgpu_ctx_out *out) | 			     union drm_amdgpu_ctx_out *out) | ||||||
| { | { | ||||||
|  | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 	struct amdgpu_ctx *ctx; | 	struct amdgpu_ctx *ctx; | ||||||
| 	struct amdgpu_ctx_mgr *mgr; | 	struct amdgpu_ctx_mgr *mgr; | ||||||
| 
 | 
 | ||||||
| @ -361,6 +364,30 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev, | |||||||
| 	if (atomic_read(&ctx->guilty)) | 	if (atomic_read(&ctx->guilty)) | ||||||
| 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY; | 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY; | ||||||
| 
 | 
 | ||||||
|  | 	if (adev->ras_enabled && con) { | ||||||
|  | 		/* Return the cached values in O(1),
 | ||||||
|  | 		 * and schedule delayed work to cache | ||||||
|  | 		 * new vaues. | ||||||
|  | 		 */ | ||||||
|  | 		int ce_count, ue_count; | ||||||
|  | 
 | ||||||
|  | 		ce_count = atomic_read(&con->ras_ce_count); | ||||||
|  | 		ue_count = atomic_read(&con->ras_ue_count); | ||||||
|  | 
 | ||||||
|  | 		if (ce_count != ctx->ras_counter_ce) { | ||||||
|  | 			ctx->ras_counter_ce = ce_count; | ||||||
|  | 			out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_CE; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (ue_count != ctx->ras_counter_ue) { | ||||||
|  | 			ctx->ras_counter_ue = ue_count; | ||||||
|  | 			out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_UE; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		schedule_delayed_work(&con->ras_counte_delay_work, | ||||||
|  | 				      msecs_to_jiffies(AMDGPU_RAS_COUNTE_DELAY_MS)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	mutex_unlock(&mgr->lock); | 	mutex_unlock(&mgr->lock); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -635,3 +662,81 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) | |||||||
| 	idr_destroy(&mgr->ctx_handles); | 	idr_destroy(&mgr->ctx_handles); | ||||||
| 	mutex_destroy(&mgr->lock); | 	mutex_destroy(&mgr->lock); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static void amdgpu_ctx_fence_time(struct amdgpu_ctx *ctx, | ||||||
|  | 		struct amdgpu_ctx_entity *centity, ktime_t *total, ktime_t *max) | ||||||
|  | { | ||||||
|  | 	ktime_t now, t1; | ||||||
|  | 	uint32_t i; | ||||||
|  | 
 | ||||||
|  | 	*total = *max = 0; | ||||||
|  | 
 | ||||||
|  | 	now = ktime_get(); | ||||||
|  | 	for (i = 0; i < amdgpu_sched_jobs; i++) { | ||||||
|  | 		struct dma_fence *fence; | ||||||
|  | 		struct drm_sched_fence *s_fence; | ||||||
|  | 
 | ||||||
|  | 		spin_lock(&ctx->ring_lock); | ||||||
|  | 		fence = dma_fence_get(centity->fences[i]); | ||||||
|  | 		spin_unlock(&ctx->ring_lock); | ||||||
|  | 		if (!fence) | ||||||
|  | 			continue; | ||||||
|  | 		s_fence = to_drm_sched_fence(fence); | ||||||
|  | 		if (!dma_fence_is_signaled(&s_fence->scheduled)) { | ||||||
|  | 			dma_fence_put(fence); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		t1 = s_fence->scheduled.timestamp; | ||||||
|  | 		if (!ktime_before(t1, now)) { | ||||||
|  | 			dma_fence_put(fence); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		if (dma_fence_is_signaled(&s_fence->finished) && | ||||||
|  | 			s_fence->finished.timestamp < now) | ||||||
|  | 			*total += ktime_sub(s_fence->finished.timestamp, t1); | ||||||
|  | 		else | ||||||
|  | 			*total += ktime_sub(now, t1); | ||||||
|  | 		t1 = ktime_sub(now, t1); | ||||||
|  | 		dma_fence_put(fence); | ||||||
|  | 		*max = max(t1, *max); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ktime_t amdgpu_ctx_mgr_fence_usage(struct amdgpu_ctx_mgr *mgr, uint32_t hwip, | ||||||
|  | 		uint32_t idx, uint64_t *elapsed) | ||||||
|  | { | ||||||
|  | 	struct idr *idp; | ||||||
|  | 	struct amdgpu_ctx *ctx; | ||||||
|  | 	uint32_t id; | ||||||
|  | 	struct amdgpu_ctx_entity *centity; | ||||||
|  | 	ktime_t total = 0, max = 0; | ||||||
|  | 
 | ||||||
|  | 	if (idx >= AMDGPU_MAX_ENTITY_NUM) | ||||||
|  | 		return 0; | ||||||
|  | 	idp = &mgr->ctx_handles; | ||||||
|  | 	mutex_lock(&mgr->lock); | ||||||
|  | 	idr_for_each_entry(idp, ctx, id) { | ||||||
|  | 		ktime_t ttotal, tmax; | ||||||
|  | 
 | ||||||
|  | 		if (!ctx->entities[hwip][idx]) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		centity = ctx->entities[hwip][idx]; | ||||||
|  | 		amdgpu_ctx_fence_time(ctx, centity, &ttotal, &tmax); | ||||||
|  | 
 | ||||||
|  | 		/* Harmonic mean approximation diverges for very small
 | ||||||
|  | 		 * values. If ratio < 0.01% ignore | ||||||
|  | 		 */ | ||||||
|  | 		if (AMDGPU_CTX_FENCE_USAGE_MIN_RATIO(tmax, ttotal)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		total = ktime_add(total, ttotal); | ||||||
|  | 		max = ktime_after(tmax, max) ? tmax : max; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mutex_unlock(&mgr->lock); | ||||||
|  | 	if (elapsed) | ||||||
|  | 		*elapsed = max; | ||||||
|  | 
 | ||||||
|  | 	return total; | ||||||
|  | } | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ struct drm_file; | |||||||
| struct amdgpu_fpriv; | struct amdgpu_fpriv; | ||||||
| 
 | 
 | ||||||
| #define AMDGPU_MAX_ENTITY_NUM 4 | #define AMDGPU_MAX_ENTITY_NUM 4 | ||||||
|  | #define AMDGPU_CTX_FENCE_USAGE_MIN_RATIO(max, total) ((max) > 16384ULL*(total)) | ||||||
| 
 | 
 | ||||||
| struct amdgpu_ctx_entity { | struct amdgpu_ctx_entity { | ||||||
| 	uint64_t		sequence; | 	uint64_t		sequence; | ||||||
| @ -87,5 +88,6 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr); | |||||||
| void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr); | void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr); | ||||||
| long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout); | long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout); | ||||||
| void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr); | void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr); | ||||||
| 
 | ktime_t amdgpu_ctx_mgr_fence_usage(struct amdgpu_ctx_mgr *mgr, uint32_t hwip, | ||||||
|  | 		uint32_t idx, uint64_t *elapsed); | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -990,7 +990,7 @@ err: | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_debugfs_regs_gfxoff_write - Enable/disable GFXOFF |  * amdgpu_debugfs_gfxoff_write - Enable/disable GFXOFF | ||||||
|  * |  * | ||||||
|  * @f: open file handle |  * @f: open file handle | ||||||
|  * @buf: User buffer to write data from |  * @buf: User buffer to write data from | ||||||
| @ -1041,7 +1041,7 @@ static ssize_t amdgpu_debugfs_gfxoff_write(struct file *f, const char __user *bu | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_debugfs_regs_gfxoff_status - read gfxoff status |  * amdgpu_debugfs_gfxoff_read - read gfxoff status | ||||||
|  * |  * | ||||||
|  * @f: open file handle |  * @f: open file handle | ||||||
|  * @buf: User buffer to store read data in |  * @buf: User buffer to store read data in | ||||||
| @ -1304,11 +1304,11 @@ static int amdgpu_debugfs_vm_info_show(struct seq_file *m, void *unused) | |||||||
| 
 | 
 | ||||||
| 		seq_printf(m, "pid:%d\tProcess:%s ----------\n", | 		seq_printf(m, "pid:%d\tProcess:%s ----------\n", | ||||||
| 				vm->task_info.pid, vm->task_info.process_name); | 				vm->task_info.pid, vm->task_info.process_name); | ||||||
| 		r = amdgpu_bo_reserve(vm->root.base.bo, true); | 		r = amdgpu_bo_reserve(vm->root.bo, true); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			break; | 			break; | ||||||
| 		amdgpu_debugfs_vm_bo_info(vm, m); | 		amdgpu_debugfs_vm_bo_info(vm, m); | ||||||
| 		amdgpu_bo_unreserve(vm->root.base.bo); | 		amdgpu_bo_unreserve(vm->root.bo); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mutex_unlock(&dev->filelist_mutex); | 	mutex_unlock(&dev->filelist_mutex); | ||||||
|  | |||||||
| @ -71,6 +71,8 @@ | |||||||
| #include <drm/task_barrier.h> | #include <drm/task_barrier.h> | ||||||
| #include <linux/pm_runtime.h> | #include <linux/pm_runtime.h> | ||||||
| 
 | 
 | ||||||
|  | #include <drm/drm_drv.h> | ||||||
|  | 
 | ||||||
| MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin"); | MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin"); | ||||||
| MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin"); | MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin"); | ||||||
| MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin"); | MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin"); | ||||||
| @ -82,6 +84,7 @@ MODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin"); | |||||||
| MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin"); | MODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin"); | ||||||
| MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); | MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); | ||||||
| MODULE_FIRMWARE("amdgpu/vangogh_gpu_info.bin"); | MODULE_FIRMWARE("amdgpu/vangogh_gpu_info.bin"); | ||||||
|  | MODULE_FIRMWARE("amdgpu/yellow_carp_gpu_info.bin"); | ||||||
| 
 | 
 | ||||||
| #define AMDGPU_RESUME_MS		2000 | #define AMDGPU_RESUME_MS		2000 | ||||||
| 
 | 
 | ||||||
| @ -119,6 +122,8 @@ const char *amdgpu_asic_name[] = { | |||||||
| 	"NAVY_FLOUNDER", | 	"NAVY_FLOUNDER", | ||||||
| 	"VANGOGH", | 	"VANGOGH", | ||||||
| 	"DIMGREY_CAVEFISH", | 	"DIMGREY_CAVEFISH", | ||||||
|  | 	"BEIGE_GOBY", | ||||||
|  | 	"YELLOW_CARP", | ||||||
| 	"LAST", | 	"LAST", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -262,6 +267,21 @@ bool amdgpu_device_supports_baco(struct drm_device *dev) | |||||||
| 	return amdgpu_asic_supports_baco(adev); | 	return amdgpu_asic_supports_baco(adev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_device_supports_smart_shift - Is the device dGPU with | ||||||
|  |  * smart shift support | ||||||
|  |  * | ||||||
|  |  * @dev: drm_device pointer | ||||||
|  |  * | ||||||
|  |  * Returns true if the device is a dGPU with Smart Shift support, | ||||||
|  |  * otherwise returns false. | ||||||
|  |  */ | ||||||
|  | bool amdgpu_device_supports_smart_shift(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	return (amdgpu_device_supports_boco(dev) && | ||||||
|  | 		amdgpu_acpi_is_power_shift_control_supported()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * VRAM access helper functions |  * VRAM access helper functions | ||||||
|  */ |  */ | ||||||
| @ -281,7 +301,10 @@ void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, | |||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	uint32_t hi = ~0; | 	uint32_t hi = ~0; | ||||||
| 	uint64_t last; | 	uint64_t last; | ||||||
|  | 	int idx; | ||||||
| 
 | 
 | ||||||
|  | 	if (!drm_dev_enter(&adev->ddev, &idx)) | ||||||
|  | 		return; | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_64BIT | #ifdef CONFIG_64BIT | ||||||
| 	last = min(pos + size, adev->gmc.visible_vram_size); | 	last = min(pos + size, adev->gmc.visible_vram_size); | ||||||
| @ -292,15 +315,15 @@ void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, | |||||||
| 		if (write) { | 		if (write) { | ||||||
| 			memcpy_toio(addr, buf, count); | 			memcpy_toio(addr, buf, count); | ||||||
| 			mb(); | 			mb(); | ||||||
| 			amdgpu_asic_flush_hdp(adev, NULL); | 			amdgpu_device_flush_hdp(adev, NULL); | ||||||
| 		} else { | 		} else { | ||||||
| 			amdgpu_asic_invalidate_hdp(adev, NULL); | 			amdgpu_device_invalidate_hdp(adev, NULL); | ||||||
| 			mb(); | 			mb(); | ||||||
| 			memcpy_fromio(buf, addr, count); | 			memcpy_fromio(buf, addr, count); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (count == size) | 		if (count == size) | ||||||
| 			return; | 			goto exit; | ||||||
| 
 | 
 | ||||||
| 		pos += count; | 		pos += count; | ||||||
| 		buf += count / 4; | 		buf += count / 4; | ||||||
| @ -323,6 +346,11 @@ void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, | |||||||
| 			*buf++ = RREG32_NO_KIQ(mmMM_DATA); | 			*buf++ = RREG32_NO_KIQ(mmMM_DATA); | ||||||
| 	} | 	} | ||||||
| 	spin_unlock_irqrestore(&adev->mmio_idx_lock, flags); | 	spin_unlock_irqrestore(&adev->mmio_idx_lock, flags); | ||||||
|  | 
 | ||||||
|  | #ifdef CONFIG_64BIT | ||||||
|  | exit: | ||||||
|  | #endif | ||||||
|  | 	drm_dev_exit(idx); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -332,7 +360,7 @@ void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, | |||||||
| /* Check if hw access should be skipped because of hotplug or device error */ | /* Check if hw access should be skipped because of hotplug or device error */ | ||||||
| bool amdgpu_device_skip_hw_access(struct amdgpu_device *adev) | bool amdgpu_device_skip_hw_access(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	if (adev->in_pci_err_recovery) | 	if (adev->no_hw_access) | ||||||
| 		return true; | 		return true; | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_LOCKDEP | #ifdef CONFIG_LOCKDEP | ||||||
| @ -490,7 +518,7 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev, | |||||||
| 	    adev->gfx.rlc.funcs && | 	    adev->gfx.rlc.funcs && | ||||||
| 	    adev->gfx.rlc.funcs->is_rlcg_access_range) { | 	    adev->gfx.rlc.funcs->is_rlcg_access_range) { | ||||||
| 		if (adev->gfx.rlc.funcs->is_rlcg_access_range(adev, reg)) | 		if (adev->gfx.rlc.funcs->is_rlcg_access_range(adev, reg)) | ||||||
| 			return adev->gfx.rlc.funcs->rlcg_wreg(adev, reg, v, 0); | 			return adev->gfx.rlc.funcs->rlcg_wreg(adev, reg, v, 0, 0); | ||||||
| 	} else { | 	} else { | ||||||
| 		writel(v, ((void __iomem *)adev->rmmio) + (reg * 4)); | 		writel(v, ((void __iomem *)adev->rmmio) + (reg * 4)); | ||||||
| 	} | 	} | ||||||
| @ -1820,6 +1848,7 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) | |||||||
| 	case CHIP_SIENNA_CICHLID: | 	case CHIP_SIENNA_CICHLID: | ||||||
| 	case CHIP_NAVY_FLOUNDER: | 	case CHIP_NAVY_FLOUNDER: | ||||||
| 	case CHIP_DIMGREY_CAVEFISH: | 	case CHIP_DIMGREY_CAVEFISH: | ||||||
|  | 	case CHIP_BEIGE_GOBY: | ||||||
| 	default: | 	default: | ||||||
| 		return 0; | 		return 0; | ||||||
| 	case CHIP_VEGA10: | 	case CHIP_VEGA10: | ||||||
| @ -1857,6 +1886,9 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) | |||||||
| 	case CHIP_VANGOGH: | 	case CHIP_VANGOGH: | ||||||
| 		chip_name = "vangogh"; | 		chip_name = "vangogh"; | ||||||
| 		break; | 		break; | ||||||
|  | 	case CHIP_YELLOW_CARP: | ||||||
|  | 		chip_name = "yellow_carp"; | ||||||
|  | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_gpu_info.bin", chip_name); | 	snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_gpu_info.bin", chip_name); | ||||||
| @ -2033,9 +2065,13 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) | |||||||
| 	case  CHIP_SIENNA_CICHLID: | 	case  CHIP_SIENNA_CICHLID: | ||||||
| 	case  CHIP_NAVY_FLOUNDER: | 	case  CHIP_NAVY_FLOUNDER: | ||||||
| 	case  CHIP_DIMGREY_CAVEFISH: | 	case  CHIP_DIMGREY_CAVEFISH: | ||||||
|  | 	case  CHIP_BEIGE_GOBY: | ||||||
| 	case CHIP_VANGOGH: | 	case CHIP_VANGOGH: | ||||||
|  | 	case CHIP_YELLOW_CARP: | ||||||
| 		if (adev->asic_type == CHIP_VANGOGH) | 		if (adev->asic_type == CHIP_VANGOGH) | ||||||
| 			adev->family = AMDGPU_FAMILY_VGH; | 			adev->family = AMDGPU_FAMILY_VGH; | ||||||
|  | 		else if (adev->asic_type == CHIP_YELLOW_CARP) | ||||||
|  | 			adev->family = AMDGPU_FAMILY_YC; | ||||||
| 		else | 		else | ||||||
| 			adev->family = AMDGPU_FAMILY_NV; | 			adev->family = AMDGPU_FAMILY_NV; | ||||||
| 
 | 
 | ||||||
| @ -2571,34 +2607,26 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev) | ||||||
|  * amdgpu_device_ip_fini - run fini for hardware IPs |  | ||||||
|  * |  | ||||||
|  * @adev: amdgpu_device pointer |  | ||||||
|  * |  | ||||||
|  * Main teardown pass for hardware IPs.  The list of all the hardware |  | ||||||
|  * IPs that make up the asic is walked and the hw_fini and sw_fini callbacks |  | ||||||
|  * are run.  hw_fini tears down the hardware associated with each IP |  | ||||||
|  * and sw_fini tears down any software state associated with each IP. |  | ||||||
|  * Returns 0 on success, negative error code on failure. |  | ||||||
|  */ |  | ||||||
| static int amdgpu_device_ip_fini(struct amdgpu_device *adev) |  | ||||||
| { | { | ||||||
| 	int i, r; | 	int i, r; | ||||||
| 
 | 
 | ||||||
| 	if (amdgpu_sriov_vf(adev) && adev->virt.ras_init_done) | 	for (i = 0; i < adev->num_ip_blocks; i++) { | ||||||
| 		amdgpu_virt_release_ras_err_handler_data(adev); | 		if (!adev->ip_blocks[i].version->funcs->early_fini) | ||||||
|  | 			continue; | ||||||
| 
 | 
 | ||||||
| 	amdgpu_ras_pre_fini(adev); | 		r = adev->ip_blocks[i].version->funcs->early_fini((void *)adev); | ||||||
|  | 		if (r) { | ||||||
|  | 			DRM_DEBUG("early_fini of IP block <%s> failed %d\n", | ||||||
|  | 				  adev->ip_blocks[i].version->funcs->name, r); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (adev->gmc.xgmi.num_physical_nodes > 1) | 	amdgpu_amdkfd_suspend(adev, false); | ||||||
| 		amdgpu_xgmi_remove_device(adev); |  | ||||||
| 
 | 
 | ||||||
| 	amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); | 	amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); | ||||||
| 	amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); | 	amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); | ||||||
| 
 | 
 | ||||||
| 	amdgpu_amdkfd_device_fini(adev); |  | ||||||
| 
 |  | ||||||
| 	/* need to disable SMC first */ | 	/* need to disable SMC first */ | ||||||
| 	for (i = 0; i < adev->num_ip_blocks; i++) { | 	for (i = 0; i < adev->num_ip_blocks; i++) { | ||||||
| 		if (!adev->ip_blocks[i].status.hw) | 		if (!adev->ip_blocks[i].status.hw) | ||||||
| @ -2629,6 +2657,33 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) | |||||||
| 		adev->ip_blocks[i].status.hw = false; | 		adev->ip_blocks[i].status.hw = false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_device_ip_fini - run fini for hardware IPs | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Main teardown pass for hardware IPs.  The list of all the hardware | ||||||
|  |  * IPs that make up the asic is walked and the hw_fini and sw_fini callbacks | ||||||
|  |  * are run.  hw_fini tears down the hardware associated with each IP | ||||||
|  |  * and sw_fini tears down any software state associated with each IP. | ||||||
|  |  * Returns 0 on success, negative error code on failure. | ||||||
|  |  */ | ||||||
|  | static int amdgpu_device_ip_fini(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	int i, r; | ||||||
|  | 
 | ||||||
|  | 	if (amdgpu_sriov_vf(adev) && adev->virt.ras_init_done) | ||||||
|  | 		amdgpu_virt_release_ras_err_handler_data(adev); | ||||||
|  | 
 | ||||||
|  | 	amdgpu_ras_pre_fini(adev); | ||||||
|  | 
 | ||||||
|  | 	if (adev->gmc.xgmi.num_physical_nodes > 1) | ||||||
|  | 		amdgpu_xgmi_remove_device(adev); | ||||||
|  | 
 | ||||||
|  | 	amdgpu_amdkfd_device_fini_sw(adev); | ||||||
| 
 | 
 | ||||||
| 	for (i = adev->num_ip_blocks - 1; i >= 0; i--) { | 	for (i = adev->num_ip_blocks - 1; i >= 0; i--) { | ||||||
| 		if (!adev->ip_blocks[i].status.sw) | 		if (!adev->ip_blocks[i].status.sw) | ||||||
| @ -2856,7 +2911,7 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) | |||||||
| 		AMD_IP_BLOCK_TYPE_IH, | 		AMD_IP_BLOCK_TYPE_IH, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < ARRAY_SIZE(ip_order); i++) { | 	for (i = 0; i < adev->num_ip_blocks; i++) { | ||||||
| 		int j; | 		int j; | ||||||
| 		struct amdgpu_ip_block *block; | 		struct amdgpu_ip_block *block; | ||||||
| 
 | 
 | ||||||
| @ -3034,7 +3089,7 @@ static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev) | |||||||
| { | { | ||||||
| 	if (amdgpu_sriov_vf(adev)) { | 	if (amdgpu_sriov_vf(adev)) { | ||||||
| 		if (adev->is_atom_fw) { | 		if (adev->is_atom_fw) { | ||||||
| 			if (amdgpu_atomfirmware_gpu_supports_virtualization(adev)) | 			if (amdgpu_atomfirmware_gpu_virtualization_supported(adev)) | ||||||
| 				adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS; | 				adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS; | ||||||
| 		} else { | 		} else { | ||||||
| 			if (amdgpu_atombios_has_gpu_virtualization_table(adev)) | 			if (amdgpu_atombios_has_gpu_virtualization_table(adev)) | ||||||
| @ -3097,7 +3152,9 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) | |||||||
| 	case CHIP_SIENNA_CICHLID: | 	case CHIP_SIENNA_CICHLID: | ||||||
| 	case CHIP_NAVY_FLOUNDER: | 	case CHIP_NAVY_FLOUNDER: | ||||||
| 	case CHIP_DIMGREY_CAVEFISH: | 	case CHIP_DIMGREY_CAVEFISH: | ||||||
|  | 	case CHIP_BEIGE_GOBY: | ||||||
| 	case CHIP_VANGOGH: | 	case CHIP_VANGOGH: | ||||||
|  | 	case CHIP_YELLOW_CARP: | ||||||
| #endif | #endif | ||||||
| 		return amdgpu_dc != 0; | 		return amdgpu_dc != 0; | ||||||
| #endif | #endif | ||||||
| @ -3181,8 +3238,8 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) | |||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * By default timeout for non compute jobs is 10000. | 	 * By default timeout for non compute jobs is 10000 | ||||||
| 	 * And there is no timeout enforced on compute jobs. | 	 * and 60000 for compute jobs. | ||||||
| 	 * In SR-IOV or passthrough mode, timeout for compute | 	 * In SR-IOV or passthrough mode, timeout for compute | ||||||
| 	 * jobs are 60000 by default. | 	 * jobs are 60000 by default. | ||||||
| 	 */ | 	 */ | ||||||
| @ -3191,10 +3248,8 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) | |||||||
| 	if (amdgpu_sriov_vf(adev)) | 	if (amdgpu_sriov_vf(adev)) | ||||||
| 		adev->compute_timeout = amdgpu_sriov_is_pp_one_vf(adev) ? | 		adev->compute_timeout = amdgpu_sriov_is_pp_one_vf(adev) ? | ||||||
| 					msecs_to_jiffies(60000) : msecs_to_jiffies(10000); | 					msecs_to_jiffies(60000) : msecs_to_jiffies(10000); | ||||||
| 	else if (amdgpu_passthrough(adev)) |  | ||||||
| 		adev->compute_timeout =  msecs_to_jiffies(60000); |  | ||||||
| 	else | 	else | ||||||
| 		adev->compute_timeout = MAX_SCHEDULE_TIMEOUT; | 		adev->compute_timeout =  msecs_to_jiffies(60000); | ||||||
| 
 | 
 | ||||||
| 	if (strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) { | 	if (strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) { | ||||||
| 		while ((timeout_setting = strsep(&input, ",")) && | 		while ((timeout_setting = strsep(&input, ",")) && | ||||||
| @ -3251,7 +3306,6 @@ static const struct attribute *amdgpu_dev_attributes[] = { | |||||||
| 	NULL | 	NULL | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_device_init - initialize the driver |  * amdgpu_device_init - initialize the driver | ||||||
|  * |  * | ||||||
| @ -3653,6 +3707,27 @@ failed_unmap: | |||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	/* Clear all CPU mappings pointing to this device */ | ||||||
|  | 	unmap_mapping_range(adev->ddev.anon_inode->i_mapping, 0, 0, 1); | ||||||
|  | 
 | ||||||
|  | 	/* Unmap all mapped bars - Doorbell, registers and VRAM */ | ||||||
|  | 	amdgpu_device_doorbell_fini(adev); | ||||||
|  | 
 | ||||||
|  | 	iounmap(adev->rmmio); | ||||||
|  | 	adev->rmmio = NULL; | ||||||
|  | 	if (adev->mman.aper_base_kaddr) | ||||||
|  | 		iounmap(adev->mman.aper_base_kaddr); | ||||||
|  | 	adev->mman.aper_base_kaddr = NULL; | ||||||
|  | 
 | ||||||
|  | 	/* Memory manager related */ | ||||||
|  | 	if (!adev->gmc.xgmi.connected_to_cpu) { | ||||||
|  | 		arch_phys_wc_del(adev->gmc.vram_mtrr); | ||||||
|  | 		arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_device_fini - tear down the driver |  * amdgpu_device_fini - tear down the driver | ||||||
|  * |  * | ||||||
| @ -3661,15 +3736,13 @@ failed_unmap: | |||||||
|  * Tear down the driver info (all asics). |  * Tear down the driver info (all asics). | ||||||
|  * Called at driver shutdown. |  * Called at driver shutdown. | ||||||
|  */ |  */ | ||||||
| void amdgpu_device_fini(struct amdgpu_device *adev) | void amdgpu_device_fini_hw(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	dev_info(adev->dev, "amdgpu: finishing device.\n"); | 	dev_info(adev->dev, "amdgpu: finishing device.\n"); | ||||||
| 	flush_delayed_work(&adev->delayed_init_work); | 	flush_delayed_work(&adev->delayed_init_work); | ||||||
| 	ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); | 	ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); | ||||||
| 	adev->shutdown = true; | 	adev->shutdown = true; | ||||||
| 
 | 
 | ||||||
| 	kfree(adev->pci_state); |  | ||||||
| 
 |  | ||||||
| 	/* make sure IB test finished before entering exclusive mode
 | 	/* make sure IB test finished before entering exclusive mode
 | ||||||
| 	 * to avoid preemption on IB test | 	 * to avoid preemption on IB test | ||||||
| 	 * */ | 	 * */ | ||||||
| @ -3686,11 +3759,29 @@ void amdgpu_device_fini(struct amdgpu_device *adev) | |||||||
| 		else | 		else | ||||||
| 			drm_atomic_helper_shutdown(adev_to_drm(adev)); | 			drm_atomic_helper_shutdown(adev_to_drm(adev)); | ||||||
| 	} | 	} | ||||||
| 	amdgpu_fence_driver_fini(adev); | 	amdgpu_fence_driver_fini_hw(adev); | ||||||
|  | 
 | ||||||
| 	if (adev->pm_sysfs_en) | 	if (adev->pm_sysfs_en) | ||||||
| 		amdgpu_pm_sysfs_fini(adev); | 		amdgpu_pm_sysfs_fini(adev); | ||||||
|  | 	if (adev->ucode_sysfs_en) | ||||||
|  | 		amdgpu_ucode_sysfs_fini(adev); | ||||||
|  | 	sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes); | ||||||
|  | 
 | ||||||
| 	amdgpu_fbdev_fini(adev); | 	amdgpu_fbdev_fini(adev); | ||||||
|  | 
 | ||||||
|  | 	amdgpu_irq_fini_hw(adev); | ||||||
|  | 
 | ||||||
|  | 	amdgpu_device_ip_fini_early(adev); | ||||||
|  | 
 | ||||||
|  | 	amdgpu_gart_dummy_page_fini(adev); | ||||||
|  | 
 | ||||||
|  | 	amdgpu_device_unmap_mmio(adev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void amdgpu_device_fini_sw(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
| 	amdgpu_device_ip_fini(adev); | 	amdgpu_device_ip_fini(adev); | ||||||
|  | 	amdgpu_fence_driver_fini_sw(adev); | ||||||
| 	release_firmware(adev->firmware.gpu_info_fw); | 	release_firmware(adev->firmware.gpu_info_fw); | ||||||
| 	adev->firmware.gpu_info_fw = NULL; | 	adev->firmware.gpu_info_fw = NULL; | ||||||
| 	adev->accel_working = false; | 	adev->accel_working = false; | ||||||
| @ -3712,18 +3803,14 @@ void amdgpu_device_fini(struct amdgpu_device *adev) | |||||||
| 	} | 	} | ||||||
| 	if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) | 	if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) | ||||||
| 		vga_client_register(adev->pdev, NULL, NULL, NULL); | 		vga_client_register(adev->pdev, NULL, NULL, NULL); | ||||||
| 	iounmap(adev->rmmio); |  | ||||||
| 	adev->rmmio = NULL; |  | ||||||
| 	amdgpu_device_doorbell_fini(adev); |  | ||||||
| 
 | 
 | ||||||
| 	if (adev->ucode_sysfs_en) |  | ||||||
| 		amdgpu_ucode_sysfs_fini(adev); |  | ||||||
| 
 |  | ||||||
| 	sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes); |  | ||||||
| 	if (IS_ENABLED(CONFIG_PERF_EVENTS)) | 	if (IS_ENABLED(CONFIG_PERF_EVENTS)) | ||||||
| 		amdgpu_pmu_fini(adev); | 		amdgpu_pmu_fini(adev); | ||||||
| 	if (adev->mman.discovery_bin) | 	if (adev->mman.discovery_bin) | ||||||
| 		amdgpu_discovery_fini(adev); | 		amdgpu_discovery_fini(adev); | ||||||
|  | 
 | ||||||
|  | 	kfree(adev->pci_state); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -3743,12 +3830,15 @@ void amdgpu_device_fini(struct amdgpu_device *adev) | |||||||
| int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) | int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) | ||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = drm_to_adev(dev); | 	struct amdgpu_device *adev = drm_to_adev(dev); | ||||||
| 	int r; |  | ||||||
| 
 | 
 | ||||||
| 	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | 	if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	adev->in_suspend = true; | 	adev->in_suspend = true; | ||||||
|  | 
 | ||||||
|  | 	if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D3)) | ||||||
|  | 		DRM_WARN("smart shift update failed\n"); | ||||||
|  | 
 | ||||||
| 	drm_kms_helper_poll_disable(dev); | 	drm_kms_helper_poll_disable(dev); | ||||||
| 
 | 
 | ||||||
| 	if (fbcon) | 	if (fbcon) | ||||||
| @ -3758,7 +3848,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) | |||||||
| 
 | 
 | ||||||
| 	amdgpu_ras_suspend(adev); | 	amdgpu_ras_suspend(adev); | ||||||
| 
 | 
 | ||||||
| 	r = amdgpu_device_ip_suspend_phase1(adev); | 	amdgpu_device_ip_suspend_phase1(adev); | ||||||
| 
 | 
 | ||||||
| 	if (!adev->in_s0ix) | 	if (!adev->in_s0ix) | ||||||
| 		amdgpu_amdkfd_suspend(adev, adev->in_runpm); | 		amdgpu_amdkfd_suspend(adev, adev->in_runpm); | ||||||
| @ -3768,7 +3858,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) | |||||||
| 
 | 
 | ||||||
| 	amdgpu_fence_driver_suspend(adev); | 	amdgpu_fence_driver_suspend(adev); | ||||||
| 
 | 
 | ||||||
| 	r = amdgpu_device_ip_suspend_phase2(adev); | 	amdgpu_device_ip_suspend_phase2(adev); | ||||||
| 	/* evict remaining vram memory
 | 	/* evict remaining vram memory
 | ||||||
| 	 * This second call to evict vram is to evict the gart page table | 	 * This second call to evict vram is to evict the gart page table | ||||||
| 	 * using the CPU. | 	 * using the CPU. | ||||||
| @ -3858,6 +3948,9 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) | |||||||
| #endif | #endif | ||||||
| 	adev->in_suspend = false; | 	adev->in_suspend = false; | ||||||
| 
 | 
 | ||||||
|  | 	if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D0)) | ||||||
|  | 		DRM_WARN("smart shift update failed\n"); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -4031,6 +4124,7 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) | |||||||
| { | { | ||||||
| 	struct dma_fence *fence = NULL, *next = NULL; | 	struct dma_fence *fence = NULL, *next = NULL; | ||||||
| 	struct amdgpu_bo *shadow; | 	struct amdgpu_bo *shadow; | ||||||
|  | 	struct amdgpu_bo_vm *vmbo; | ||||||
| 	long r = 1, tmo; | 	long r = 1, tmo; | ||||||
| 
 | 
 | ||||||
| 	if (amdgpu_sriov_runtime(adev)) | 	if (amdgpu_sriov_runtime(adev)) | ||||||
| @ -4040,12 +4134,12 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev) | |||||||
| 
 | 
 | ||||||
| 	dev_info(adev->dev, "recover vram bo from shadow start\n"); | 	dev_info(adev->dev, "recover vram bo from shadow start\n"); | ||||||
| 	mutex_lock(&adev->shadow_list_lock); | 	mutex_lock(&adev->shadow_list_lock); | ||||||
| 	list_for_each_entry(shadow, &adev->shadow_list, shadow_list) { | 	list_for_each_entry(vmbo, &adev->shadow_list, shadow_list) { | ||||||
| 
 | 		shadow = &vmbo->bo; | ||||||
| 		/* No need to recover an evicted BO */ | 		/* No need to recover an evicted BO */ | ||||||
| 		if (shadow->tbo.mem.mem_type != TTM_PL_TT || | 		if (shadow->tbo.resource->mem_type != TTM_PL_TT || | ||||||
| 		    shadow->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET || | 		    shadow->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET || | ||||||
| 		    shadow->parent->tbo.mem.mem_type != TTM_PL_VRAM) | 		    shadow->parent->tbo.resource->mem_type != TTM_PL_VRAM) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		r = amdgpu_bo_restore_shadow(shadow, &next); | 		r = amdgpu_bo_restore_shadow(shadow, &next); | ||||||
| @ -4634,7 +4728,7 @@ static int amdgpu_device_suspend_display_audio(struct amdgpu_device *adev) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void amdgpu_device_recheck_guilty_jobs( | static void amdgpu_device_recheck_guilty_jobs( | ||||||
| 	struct amdgpu_device *adev, struct list_head *device_list_handle, | 	struct amdgpu_device *adev, struct list_head *device_list_handle, | ||||||
| 	struct amdgpu_reset_context *reset_context) | 	struct amdgpu_reset_context *reset_context) | ||||||
| { | { | ||||||
| @ -4937,6 +5031,8 @@ skip_hw_reset: | |||||||
| 			amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); | 			amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); | ||||||
| 		} else { | 		} else { | ||||||
| 			dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&tmp_adev->gpu_reset_counter)); | 			dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&tmp_adev->gpu_reset_counter)); | ||||||
|  | 			if (amdgpu_acpi_smart_shift_update(adev_to_drm(tmp_adev), AMDGPU_SS_DEV_D0)) | ||||||
|  | 				DRM_WARN("smart shift update failed\n"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -5125,7 +5221,8 @@ int amdgpu_device_baco_enter(struct drm_device *dev) | |||||||
| 	if (!amdgpu_device_supports_baco(adev_to_drm(adev))) | 	if (!amdgpu_device_supports_baco(adev_to_drm(adev))) | ||||||
| 		return -ENOTSUPP; | 		return -ENOTSUPP; | ||||||
| 
 | 
 | ||||||
| 	if (ras && ras->supported && adev->nbio.funcs->enable_doorbell_interrupt) | 	if (ras && adev->ras_enabled && | ||||||
|  | 	    adev->nbio.funcs->enable_doorbell_interrupt) | ||||||
| 		adev->nbio.funcs->enable_doorbell_interrupt(adev, false); | 		adev->nbio.funcs->enable_doorbell_interrupt(adev, false); | ||||||
| 
 | 
 | ||||||
| 	return amdgpu_dpm_baco_enter(adev); | 	return amdgpu_dpm_baco_enter(adev); | ||||||
| @ -5144,7 +5241,8 @@ int amdgpu_device_baco_exit(struct drm_device *dev) | |||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	if (ras && ras->supported && adev->nbio.funcs->enable_doorbell_interrupt) | 	if (ras && adev->ras_enabled && | ||||||
|  | 	    adev->nbio.funcs->enable_doorbell_interrupt) | ||||||
| 		adev->nbio.funcs->enable_doorbell_interrupt(adev, true); | 		adev->nbio.funcs->enable_doorbell_interrupt(adev, true); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -5290,9 +5388,9 @@ pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev) | |||||||
| 	set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); | 	set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); | ||||||
| 	set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags); | 	set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags); | ||||||
| 
 | 
 | ||||||
| 	adev->in_pci_err_recovery = true; | 	adev->no_hw_access = true; | ||||||
| 	r = amdgpu_device_pre_asic_reset(adev, &reset_context); | 	r = amdgpu_device_pre_asic_reset(adev, &reset_context); | ||||||
| 	adev->in_pci_err_recovery = false; | 	adev->no_hw_access = false; | ||||||
| 	if (r) | 	if (r) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| @ -5387,4 +5485,31 @@ bool amdgpu_device_load_pci_state(struct pci_dev *pdev) | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void amdgpu_device_flush_hdp(struct amdgpu_device *adev, | ||||||
|  | 		struct amdgpu_ring *ring) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_X86_64 | ||||||
|  | 	if (adev->flags & AMD_IS_APU) | ||||||
|  | 		return; | ||||||
|  | #endif | ||||||
|  | 	if (adev->gmc.xgmi.connected_to_cpu) | ||||||
|  | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	if (ring && ring->funcs->emit_hdp_flush) | ||||||
|  | 		amdgpu_ring_emit_hdp_flush(ring); | ||||||
|  | 	else | ||||||
|  | 		amdgpu_asic_flush_hdp(adev, ring); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev, | ||||||
|  | 		struct amdgpu_ring *ring) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_X86_64 | ||||||
|  | 	if (adev->flags & AMD_IS_APU) | ||||||
|  | 		return; | ||||||
|  | #endif | ||||||
|  | 	if (adev->gmc.xgmi.connected_to_cpu) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	amdgpu_asic_invalidate_hdp(adev, ring); | ||||||
|  | } | ||||||
|  | |||||||
| @ -325,7 +325,7 @@ int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, | int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, int number_instance, | ||||||
| 				    int *major, int *minor, int *revision) | 				    int *major, int *minor, int *revision) | ||||||
| { | { | ||||||
| 	struct binary_header *bhdr; | 	struct binary_header *bhdr; | ||||||
| @ -357,7 +357,7 @@ int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, | |||||||
| 		for (j = 0; j < num_ips; j++) { | 		for (j = 0; j < num_ips; j++) { | ||||||
| 			ip = (struct ip *)(adev->mman.discovery_bin + ip_offset); | 			ip = (struct ip *)(adev->mman.discovery_bin + ip_offset); | ||||||
| 
 | 
 | ||||||
| 			if (le16_to_cpu(ip->hw_id) == hw_id) { | 			if ((le16_to_cpu(ip->hw_id) == hw_id) && (ip->number_instance == number_instance)) { | ||||||
| 				if (major) | 				if (major) | ||||||
| 					*major = ip->major; | 					*major = ip->major; | ||||||
| 				if (minor) | 				if (minor) | ||||||
| @ -373,6 +373,14 @@ int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, | |||||||
| 	return -EINVAL; | 	return -EINVAL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | int amdgpu_discovery_get_vcn_version(struct amdgpu_device *adev, int vcn_instance, | ||||||
|  | 				     int *major, int *minor, int *revision) | ||||||
|  | { | ||||||
|  | 	return amdgpu_discovery_get_ip_version(adev, VCN_HWID, | ||||||
|  | 					       vcn_instance, major, minor, revision); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev) | void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	struct binary_header *bhdr; | 	struct binary_header *bhdr; | ||||||
|  | |||||||
| @ -30,7 +30,10 @@ | |||||||
| void amdgpu_discovery_fini(struct amdgpu_device *adev); | void amdgpu_discovery_fini(struct amdgpu_device *adev); | ||||||
| int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev); | int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev); | ||||||
| void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev); | void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev); | ||||||
| int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, | int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, int number_instance, | ||||||
|  |                                     int *major, int *minor, int *revision); | ||||||
|  | 
 | ||||||
|  | int amdgpu_discovery_get_vcn_version(struct amdgpu_device *adev, int vcn_instance, | ||||||
| 				     int *major, int *minor, int *revision); | 				     int *major, int *minor, int *revision); | ||||||
| int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev); | int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -203,9 +203,8 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, | |||||||
| 		goto unpin; | 		goto unpin; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	r = dma_resv_get_fences_rcu(new_abo->tbo.base.resv, &work->excl, | 	r = dma_resv_get_fences(new_abo->tbo.base.resv, &work->excl, | ||||||
| 					      &work->shared_count, | 				&work->shared_count, &work->shared); | ||||||
| 					      &work->shared); |  | ||||||
| 	if (unlikely(r != 0)) { | 	if (unlikely(r != 0)) { | ||||||
| 		DRM_ERROR("failed to get fences for buffer\n"); | 		DRM_ERROR("failed to get fences for buffer\n"); | ||||||
| 		goto unpin; | 		goto unpin; | ||||||
| @ -1075,12 +1074,9 @@ int amdgpu_display_gem_fb_verify_and_init( | |||||||
| 	/* Verify that the modifier is supported. */ | 	/* Verify that the modifier is supported. */ | ||||||
| 	if (!drm_any_plane_has_format(dev, mode_cmd->pixel_format, | 	if (!drm_any_plane_has_format(dev, mode_cmd->pixel_format, | ||||||
| 				      mode_cmd->modifier[0])) { | 				      mode_cmd->modifier[0])) { | ||||||
| 		struct drm_format_name_buf format_name; |  | ||||||
| 		drm_dbg_kms(dev, | 		drm_dbg_kms(dev, | ||||||
| 			    "unsupported pixel format %s / modifier 0x%llx\n", | 			    "unsupported pixel format %p4cc / modifier 0x%llx\n", | ||||||
| 			    drm_get_format_name(mode_cmd->pixel_format, | 			    &mode_cmd->pixel_format, mode_cmd->modifier[0]); | ||||||
| 						&format_name), |  | ||||||
| 			    mode_cmd->modifier[0]); |  | ||||||
| 
 | 
 | ||||||
| 		ret = -EINVAL; | 		ret = -EINVAL; | ||||||
| 		goto err; | 		goto err; | ||||||
|  | |||||||
| @ -42,52 +42,6 @@ | |||||||
| #include <linux/pci-p2pdma.h> | #include <linux/pci-p2pdma.h> | ||||||
| #include <linux/pm_runtime.h> | #include <linux/pm_runtime.h> | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * amdgpu_gem_prime_mmap - &drm_driver.gem_prime_mmap implementation |  | ||||||
|  * @obj: GEM BO |  | ||||||
|  * @vma: Virtual memory area |  | ||||||
|  * |  | ||||||
|  * Sets up a userspace mapping of the BO's memory in the given |  | ||||||
|  * virtual memory area. |  | ||||||
|  * |  | ||||||
|  * Returns: |  | ||||||
|  * 0 on success or a negative error code on failure. |  | ||||||
|  */ |  | ||||||
| int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, |  | ||||||
| 			  struct vm_area_struct *vma) |  | ||||||
| { |  | ||||||
| 	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); |  | ||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |  | ||||||
| 	unsigned asize = amdgpu_bo_size(bo); |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	if (!vma->vm_file) |  | ||||||
| 		return -ENODEV; |  | ||||||
| 
 |  | ||||||
| 	if (adev == NULL) |  | ||||||
| 		return -ENODEV; |  | ||||||
| 
 |  | ||||||
| 	/* Check for valid size. */ |  | ||||||
| 	if (asize < vma->vm_end - vma->vm_start) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm) || |  | ||||||
| 	    (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)) { |  | ||||||
| 		return -EPERM; |  | ||||||
| 	} |  | ||||||
| 	vma->vm_pgoff += amdgpu_bo_mmap_offset(bo) >> PAGE_SHIFT; |  | ||||||
| 
 |  | ||||||
| 	/* prime mmap does not need to check access, so allow here */ |  | ||||||
| 	ret = drm_vma_node_allow(&obj->vma_node, vma->vm_file->private_data); |  | ||||||
| 	if (ret) |  | ||||||
| 		return ret; |  | ||||||
| 
 |  | ||||||
| 	ret = ttm_bo_mmap(vma->vm_file, vma, &adev->mman.bdev); |  | ||||||
| 	drm_vma_node_revoke(&obj->vma_node, vma->vm_file->private_data); |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int | static int | ||||||
| __dma_resv_make_exclusive(struct dma_resv *obj) | __dma_resv_make_exclusive(struct dma_resv *obj) | ||||||
| { | { | ||||||
| @ -95,10 +49,10 @@ __dma_resv_make_exclusive(struct dma_resv *obj) | |||||||
| 	unsigned int count; | 	unsigned int count; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	if (!dma_resv_get_list(obj)) /* no shared fences to convert */ | 	if (!dma_resv_shared_list(obj)) /* no shared fences to convert */ | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	r = dma_resv_get_fences_rcu(obj, NULL, &count, &fences); | 	r = dma_resv_get_fences(obj, NULL, &count, &fences); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| @ -284,12 +238,12 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach, | |||||||
| 		if (r) | 		if (r) | ||||||
| 			return ERR_PTR(r); | 			return ERR_PTR(r); | ||||||
| 
 | 
 | ||||||
| 	} else if (!(amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type) & | 	} else if (!(amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type) & | ||||||
| 		     AMDGPU_GEM_DOMAIN_GTT)) { | 		     AMDGPU_GEM_DOMAIN_GTT)) { | ||||||
| 		return ERR_PTR(-EBUSY); | 		return ERR_PTR(-EBUSY); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	switch (bo->tbo.mem.mem_type) { | 	switch (bo->tbo.resource->mem_type) { | ||||||
| 	case TTM_PL_TT: | 	case TTM_PL_TT: | ||||||
| 		sgt = drm_prime_pages_to_sg(obj->dev, | 		sgt = drm_prime_pages_to_sg(obj->dev, | ||||||
| 					    bo->tbo.ttm->pages, | 					    bo->tbo.ttm->pages, | ||||||
| @ -303,8 +257,9 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach, | |||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case TTM_PL_VRAM: | 	case TTM_PL_VRAM: | ||||||
| 		r = amdgpu_vram_mgr_alloc_sgt(adev, &bo->tbo.mem, 0, | 		r = amdgpu_vram_mgr_alloc_sgt(adev, bo->tbo.resource, 0, | ||||||
| 				bo->tbo.base.size, attach->dev, dir, &sgt); | 					      bo->tbo.base.size, attach->dev, | ||||||
|  | 					      dir, &sgt); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			return ERR_PTR(r); | 			return ERR_PTR(r); | ||||||
| 		break; | 		break; | ||||||
| @ -494,7 +449,7 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach) | |||||||
| 	struct amdgpu_vm_bo_base *bo_base; | 	struct amdgpu_vm_bo_base *bo_base; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	if (bo->tbo.mem.mem_type == TTM_PL_SYSTEM) | 	if (bo->tbo.resource->mem_type == TTM_PL_SYSTEM) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	r = ttm_bo_validate(&bo->tbo, &placement, &ctx); | 	r = ttm_bo_validate(&bo->tbo, &placement, &ctx); | ||||||
| @ -505,7 +460,7 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach) | |||||||
| 
 | 
 | ||||||
| 	for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) { | 	for (bo_base = bo->vm_bo; bo_base; bo_base = bo_base->next) { | ||||||
| 		struct amdgpu_vm *vm = bo_base->vm; | 		struct amdgpu_vm *vm = bo_base->vm; | ||||||
| 		struct dma_resv *resv = vm->root.base.bo->tbo.base.resv; | 		struct dma_resv *resv = vm->root.bo->tbo.base.resv; | ||||||
| 
 | 
 | ||||||
| 		if (ticket) { | 		if (ticket) { | ||||||
| 			/* When we get an error here it means that somebody
 | 			/* When we get an error here it means that somebody
 | ||||||
|  | |||||||
| @ -31,8 +31,6 @@ struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev, | |||||||
| 					    struct dma_buf *dma_buf); | 					    struct dma_buf *dma_buf); | ||||||
| bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev, | bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev, | ||||||
| 				      struct amdgpu_bo *bo); | 				      struct amdgpu_bo *bo); | ||||||
| int amdgpu_gem_prime_mmap(struct drm_gem_object *obj, |  | ||||||
| 			  struct vm_area_struct *vma); |  | ||||||
| 
 | 
 | ||||||
| extern const struct dma_buf_ops amdgpu_dmabuf_ops; | extern const struct dma_buf_ops amdgpu_dmabuf_ops; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -23,6 +23,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <drm/amdgpu_drm.h> | #include <drm/amdgpu_drm.h> | ||||||
|  | #include <drm/drm_aperture.h> | ||||||
| #include <drm/drm_drv.h> | #include <drm/drm_drv.h> | ||||||
| #include <drm/drm_gem.h> | #include <drm/drm_gem.h> | ||||||
| #include <drm/drm_vblank.h> | #include <drm/drm_vblank.h> | ||||||
| @ -42,7 +43,7 @@ | |||||||
| #include "amdgpu_irq.h" | #include "amdgpu_irq.h" | ||||||
| #include "amdgpu_dma_buf.h" | #include "amdgpu_dma_buf.h" | ||||||
| #include "amdgpu_sched.h" | #include "amdgpu_sched.h" | ||||||
| 
 | #include "amdgpu_fdinfo.h" | ||||||
| #include "amdgpu_amdkfd.h" | #include "amdgpu_amdkfd.h" | ||||||
| 
 | 
 | ||||||
| #include "amdgpu_ras.h" | #include "amdgpu_ras.h" | ||||||
| @ -94,9 +95,10 @@ | |||||||
|  * - 3.39.0 - DMABUF implicit sync does a full pipeline sync |  * - 3.39.0 - DMABUF implicit sync does a full pipeline sync | ||||||
|  * - 3.40.0 - Add AMDGPU_IDS_FLAGS_TMZ |  * - 3.40.0 - Add AMDGPU_IDS_FLAGS_TMZ | ||||||
|  * - 3.41.0 - Add video codec query |  * - 3.41.0 - Add video codec query | ||||||
|  |  * - 3.42.0 - Add 16bpc fixed point display support | ||||||
|  */ |  */ | ||||||
| #define KMS_DRIVER_MAJOR	3 | #define KMS_DRIVER_MAJOR	3 | ||||||
| #define KMS_DRIVER_MINOR	41 | #define KMS_DRIVER_MINOR	42 | ||||||
| #define KMS_DRIVER_PATCHLEVEL	0 | #define KMS_DRIVER_PATCHLEVEL	0 | ||||||
| 
 | 
 | ||||||
| int amdgpu_vram_limit; | int amdgpu_vram_limit; | ||||||
| @ -171,6 +173,7 @@ int amdgpu_tmz = -1; /* auto */ | |||||||
| uint amdgpu_freesync_vid_mode; | uint amdgpu_freesync_vid_mode; | ||||||
| int amdgpu_reset_method = -1; /* auto */ | int amdgpu_reset_method = -1; /* auto */ | ||||||
| int amdgpu_num_kcq = -1; | int amdgpu_num_kcq = -1; | ||||||
|  | int amdgpu_smartshift_bias; | ||||||
| 
 | 
 | ||||||
| static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); | static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); | ||||||
| 
 | 
 | ||||||
| @ -287,9 +290,9 @@ module_param_named(msi, amdgpu_msi, int, 0444); | |||||||
|  *   for SDMA and Video. |  *   for SDMA and Video. | ||||||
|  * |  * | ||||||
|  * By default(with no lockup_timeout settings), the timeout for all non-compute(GFX, SDMA and Video) |  * By default(with no lockup_timeout settings), the timeout for all non-compute(GFX, SDMA and Video) | ||||||
|  * jobs is 10000. And there is no timeout enforced on compute jobs. |  * jobs is 10000. The timeout for compute is 60000. | ||||||
|  */ |  */ | ||||||
| MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default: for bare metal 10000 for non-compute jobs and infinity timeout for compute jobs; " | MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (default: for bare metal 10000 for non-compute jobs and 60000 for compute jobs; " | ||||||
| 		"for passthrough or sriov, 10000 for all jobs." | 		"for passthrough or sriov, 10000 for all jobs." | ||||||
| 		" 0: keep default value. negative: infinity timeout), " | 		" 0: keep default value. negative: infinity timeout), " | ||||||
| 		"format: for bare metal [Non-Compute] or [GFX,Compute,SDMA,Video]; " | 		"format: for bare metal [Non-Compute] or [GFX,Compute,SDMA,Video]; " | ||||||
| @ -640,7 +643,8 @@ module_param_named(mes, amdgpu_mes, int, 0444); | |||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * DOC: noretry (int) |  * DOC: noretry (int) | ||||||
|  * Disable retry faults in the GPU memory controller. |  * Disable XNACK retry in the SQ by default on GFXv9 hardware. On ASICs that | ||||||
|  |  * do not support per-process XNACK this also disables retry page faults. | ||||||
|  * (0 = retry enabled, 1 = retry disabled, -1 auto (default)) |  * (0 = retry enabled, 1 = retry disabled, -1 auto (default)) | ||||||
|  */ |  */ | ||||||
| MODULE_PARM_DESC(noretry, | MODULE_PARM_DESC(noretry, | ||||||
| @ -833,8 +837,23 @@ module_param_named(tmz, amdgpu_tmz, int, 0444); | |||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * DOC: freesync_video (uint) |  * DOC: freesync_video (uint) | ||||||
|  * Enabled the optimization to adjust front porch timing to achieve seamless mode change experience |  * Enable the optimization to adjust front porch timing to achieve seamless | ||||||
|  * when setting a freesync supported mode for which full modeset is not needed. |  * mode change experience when setting a freesync supported mode for which full | ||||||
|  |  * modeset is not needed. | ||||||
|  |  * | ||||||
|  |  * The Display Core will add a set of modes derived from the base FreeSync | ||||||
|  |  * video mode into the corresponding connector's mode list based on commonly | ||||||
|  |  * used refresh rates and VRR range of the connected display, when users enable | ||||||
|  |  * this feature. From the userspace perspective, they can see a seamless mode | ||||||
|  |  * change experience when the change between different refresh rates under the | ||||||
|  |  * same resolution. Additionally, userspace applications such as Video playback | ||||||
|  |  * can read this modeset list and change the refresh rate based on the video | ||||||
|  |  * frame rate. Finally, the userspace can also derive an appropriate mode for a | ||||||
|  |  * particular refresh rate based on the FreeSync Mode and add it to the | ||||||
|  |  * connector's mode list. | ||||||
|  |  * | ||||||
|  |  * Note: This is an experimental feature. | ||||||
|  |  * | ||||||
|  * The default value: 0 (off). |  * The default value: 0 (off). | ||||||
|  */ |  */ | ||||||
| MODULE_PARM_DESC( | MODULE_PARM_DESC( | ||||||
| @ -1185,6 +1204,7 @@ static const struct pci_device_id pciidlist[] = { | |||||||
| 	{0x1002, 0x7408, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT}, | 	{0x1002, 0x7408, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT}, | ||||||
| 	{0x1002, 0x740C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT}, | 	{0x1002, 0x740C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT}, | ||||||
| 	{0x1002, 0x740F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT}, | 	{0x1002, 0x740F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT}, | ||||||
|  | 	{0x1002, 0x7410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT}, | ||||||
| 
 | 
 | ||||||
| 	{0, 0, 0} | 	{0, 0, 0} | ||||||
| }; | }; | ||||||
| @ -1258,7 +1278,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, | |||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	/* Get rid of things like offb */ | 	/* Get rid of things like offb */ | ||||||
| 	ret = drm_fb_helper_remove_conflicting_pci_framebuffers(pdev, "amdgpudrmfb"); | 	ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "amdgpudrmfb"); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return ret; | 		return ret; | ||||||
| 
 | 
 | ||||||
| @ -1310,14 +1330,16 @@ amdgpu_pci_remove(struct pci_dev *pdev) | |||||||
| { | { | ||||||
| 	struct drm_device *dev = pci_get_drvdata(pdev); | 	struct drm_device *dev = pci_get_drvdata(pdev); | ||||||
| 
 | 
 | ||||||
| #ifdef MODULE |  | ||||||
| 	if (THIS_MODULE->state != MODULE_STATE_GOING) |  | ||||||
| #endif |  | ||||||
| 		DRM_ERROR("Hotplug removal is not supported\n"); |  | ||||||
| 	drm_dev_unplug(dev); | 	drm_dev_unplug(dev); | ||||||
| 	amdgpu_driver_unload_kms(dev); | 	amdgpu_driver_unload_kms(dev); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Flush any in flight DMA operations from device. | ||||||
|  | 	 * Clear the Bus Master Enable bit and then wait on the PCIe Device | ||||||
|  | 	 * StatusTransactions Pending bit. | ||||||
|  | 	 */ | ||||||
| 	pci_disable_device(pdev); | 	pci_disable_device(pdev); | ||||||
| 	pci_set_drvdata(pdev, NULL); | 	pci_wait_for_pending_transaction(pdev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| @ -1552,6 +1574,10 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) | |||||||
| 	if (!adev->runpm) | 	if (!adev->runpm) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
|  | 	/* Avoids registers access if device is physically gone */ | ||||||
|  | 	if (!pci_device_is_present(adev->pdev)) | ||||||
|  | 		adev->no_hw_access = true; | ||||||
|  | 
 | ||||||
| 	if (amdgpu_device_supports_px(drm_dev)) { | 	if (amdgpu_device_supports_px(drm_dev)) { | ||||||
| 		drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | 		drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; | ||||||
| 
 | 
 | ||||||
| @ -1597,16 +1623,14 @@ static int amdgpu_pmops_runtime_idle(struct device *dev) | |||||||
| 	if (amdgpu_device_has_dc_support(adev)) { | 	if (amdgpu_device_has_dc_support(adev)) { | ||||||
| 		struct drm_crtc *crtc; | 		struct drm_crtc *crtc; | ||||||
| 
 | 
 | ||||||
| 		drm_modeset_lock_all(drm_dev); |  | ||||||
| 
 |  | ||||||
| 		drm_for_each_crtc(crtc, drm_dev) { | 		drm_for_each_crtc(crtc, drm_dev) { | ||||||
| 			if (crtc->state->active) { | 			drm_modeset_lock(&crtc->mutex, NULL); | ||||||
|  | 			if (crtc->state->active) | ||||||
| 				ret = -EBUSY; | 				ret = -EBUSY; | ||||||
|  | 			drm_modeset_unlock(&crtc->mutex); | ||||||
|  | 			if (ret < 0) | ||||||
| 				break; | 				break; | ||||||
| 		} | 		} | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		drm_modeset_unlock_all(drm_dev); |  | ||||||
| 
 | 
 | ||||||
| 	} else { | 	} else { | ||||||
| 		struct drm_connector *list_connector; | 		struct drm_connector *list_connector; | ||||||
| @ -1688,12 +1712,15 @@ static const struct file_operations amdgpu_driver_kms_fops = { | |||||||
| 	.flush = amdgpu_flush, | 	.flush = amdgpu_flush, | ||||||
| 	.release = drm_release, | 	.release = drm_release, | ||||||
| 	.unlocked_ioctl = amdgpu_drm_ioctl, | 	.unlocked_ioctl = amdgpu_drm_ioctl, | ||||||
| 	.mmap = amdgpu_mmap, | 	.mmap = drm_gem_mmap, | ||||||
| 	.poll = drm_poll, | 	.poll = drm_poll, | ||||||
| 	.read = drm_read, | 	.read = drm_read, | ||||||
| #ifdef CONFIG_COMPAT | #ifdef CONFIG_COMPAT | ||||||
| 	.compat_ioctl = amdgpu_kms_compat_ioctl, | 	.compat_ioctl = amdgpu_kms_compat_ioctl, | ||||||
| #endif | #endif | ||||||
|  | #ifdef CONFIG_PROC_FS | ||||||
|  | 	.show_fdinfo = amdgpu_show_fdinfo | ||||||
|  | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv) | int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv) | ||||||
| @ -1747,11 +1774,12 @@ static const struct drm_driver amdgpu_kms_driver = { | |||||||
| 	.dumb_create = amdgpu_mode_dumb_create, | 	.dumb_create = amdgpu_mode_dumb_create, | ||||||
| 	.dumb_map_offset = amdgpu_mode_dumb_mmap, | 	.dumb_map_offset = amdgpu_mode_dumb_mmap, | ||||||
| 	.fops = &amdgpu_driver_kms_fops, | 	.fops = &amdgpu_driver_kms_fops, | ||||||
|  | 	.release = &amdgpu_driver_release_kms, | ||||||
| 
 | 
 | ||||||
| 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd, | 	.prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||||||
| 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle, | 	.prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||||||
| 	.gem_prime_import = amdgpu_gem_prime_import, | 	.gem_prime_import = amdgpu_gem_prime_import, | ||||||
| 	.gem_prime_mmap = amdgpu_gem_prime_mmap, | 	.gem_prime_mmap = drm_gem_prime_mmap, | ||||||
| 
 | 
 | ||||||
| 	.name = DRIVER_NAME, | 	.name = DRIVER_NAME, | ||||||
| 	.desc = DRIVER_DESC, | 	.desc = DRIVER_DESC, | ||||||
| @ -1768,6 +1796,18 @@ static struct pci_error_handlers amdgpu_pci_err_handler = { | |||||||
| 	.resume		= amdgpu_pci_resume, | 	.resume		= amdgpu_pci_resume, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | extern const struct attribute_group amdgpu_vram_mgr_attr_group; | ||||||
|  | extern const struct attribute_group amdgpu_gtt_mgr_attr_group; | ||||||
|  | extern const struct attribute_group amdgpu_vbios_version_attr_group; | ||||||
|  | 
 | ||||||
|  | static const struct attribute_group *amdgpu_sysfs_groups[] = { | ||||||
|  | 	&amdgpu_vram_mgr_attr_group, | ||||||
|  | 	&amdgpu_gtt_mgr_attr_group, | ||||||
|  | 	&amdgpu_vbios_version_attr_group, | ||||||
|  | 	NULL, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| static struct pci_driver amdgpu_kms_pci_driver = { | static struct pci_driver amdgpu_kms_pci_driver = { | ||||||
| 	.name = DRIVER_NAME, | 	.name = DRIVER_NAME, | ||||||
| 	.id_table = pciidlist, | 	.id_table = pciidlist, | ||||||
| @ -1776,6 +1816,7 @@ static struct pci_driver amdgpu_kms_pci_driver = { | |||||||
| 	.shutdown = amdgpu_pci_shutdown, | 	.shutdown = amdgpu_pci_shutdown, | ||||||
| 	.driver.pm = &amdgpu_pm_ops, | 	.driver.pm = &amdgpu_pm_ops, | ||||||
| 	.err_handler = &amdgpu_pci_err_handler, | 	.err_handler = &amdgpu_pci_err_handler, | ||||||
|  | 	.dev_groups = amdgpu_sysfs_groups, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static int __init amdgpu_init(void) | static int __init amdgpu_init(void) | ||||||
| @ -1797,6 +1838,7 @@ static int __init amdgpu_init(void) | |||||||
| 
 | 
 | ||||||
| 	DRM_INFO("amdgpu kernel modesetting enabled.\n"); | 	DRM_INFO("amdgpu kernel modesetting enabled.\n"); | ||||||
| 	amdgpu_register_atpx_handler(); | 	amdgpu_register_atpx_handler(); | ||||||
|  | 	amdgpu_acpi_detect(); | ||||||
| 
 | 
 | ||||||
| 	/* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */ | 	/* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */ | ||||||
| 	amdgpu_amdkfd_init(); | 	amdgpu_amdkfd_init(); | ||||||
|  | |||||||
							
								
								
									
										104
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,104 @@ | |||||||
|  | // SPDX-License-Identifier: MIT
 | ||||||
|  | /* Copyright 2021 Advanced Micro Devices, Inc.
 | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  |  * copy of this software and associated documentation files (the "Software"), | ||||||
|  |  * to deal in the Software without restriction, including without limitation | ||||||
|  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  |  * and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  |  * Software is furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||||
|  |  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||||
|  |  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||||
|  |  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  |  * OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  * | ||||||
|  |  * Authors: David Nieto | ||||||
|  |  *          Roy Sun | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/debugfs.h> | ||||||
|  | #include <linux/list.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <linux/uaccess.h> | ||||||
|  | #include <linux/reboot.h> | ||||||
|  | #include <linux/syscalls.h> | ||||||
|  | 
 | ||||||
|  | #include <drm/amdgpu_drm.h> | ||||||
|  | #include <drm/drm_debugfs.h> | ||||||
|  | 
 | ||||||
|  | #include "amdgpu.h" | ||||||
|  | #include "amdgpu_vm.h" | ||||||
|  | #include "amdgpu_gem.h" | ||||||
|  | #include "amdgpu_ctx.h" | ||||||
|  | #include "amdgpu_fdinfo.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static const char *amdgpu_ip_name[AMDGPU_HW_IP_NUM] = { | ||||||
|  | 	[AMDGPU_HW_IP_GFX]	=	"gfx", | ||||||
|  | 	[AMDGPU_HW_IP_COMPUTE]	=	"compute", | ||||||
|  | 	[AMDGPU_HW_IP_DMA]	=	"dma", | ||||||
|  | 	[AMDGPU_HW_IP_UVD]	=	"dec", | ||||||
|  | 	[AMDGPU_HW_IP_VCE]	=	"enc", | ||||||
|  | 	[AMDGPU_HW_IP_UVD_ENC]	=	"enc_1", | ||||||
|  | 	[AMDGPU_HW_IP_VCN_DEC]	=	"dec", | ||||||
|  | 	[AMDGPU_HW_IP_VCN_ENC]	=	"enc", | ||||||
|  | 	[AMDGPU_HW_IP_VCN_JPEG]	=	"jpeg", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void amdgpu_show_fdinfo(struct seq_file *m, struct file *f) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_fpriv *fpriv; | ||||||
|  | 	uint32_t bus, dev, fn, i, domain; | ||||||
|  | 	uint64_t vram_mem = 0, gtt_mem = 0, cpu_mem = 0; | ||||||
|  | 	struct drm_file *file = f->private_data; | ||||||
|  | 	struct amdgpu_device *adev = drm_to_adev(file->minor->dev); | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ret = amdgpu_file_to_fpriv(f, &fpriv); | ||||||
|  | 	if (ret) | ||||||
|  | 		return; | ||||||
|  | 	bus = adev->pdev->bus->number; | ||||||
|  | 	domain = pci_domain_nr(adev->pdev->bus); | ||||||
|  | 	dev = PCI_SLOT(adev->pdev->devfn); | ||||||
|  | 	fn = PCI_FUNC(adev->pdev->devfn); | ||||||
|  | 
 | ||||||
|  | 	ret = amdgpu_bo_reserve(fpriv->vm.root.bo, false); | ||||||
|  | 	if (ret) { | ||||||
|  | 		DRM_ERROR("Fail to reserve bo\n"); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	amdgpu_vm_get_memory(&fpriv->vm, &vram_mem, >t_mem, &cpu_mem); | ||||||
|  | 	amdgpu_bo_unreserve(fpriv->vm.root.bo); | ||||||
|  | 	seq_printf(m, "pdev:\t%04x:%02x:%02x.%d\npasid:\t%u\n", domain, bus, | ||||||
|  | 			dev, fn, fpriv->vm.pasid); | ||||||
|  | 	seq_printf(m, "vram mem:\t%llu kB\n", vram_mem/1024UL); | ||||||
|  | 	seq_printf(m, "gtt mem:\t%llu kB\n", gtt_mem/1024UL); | ||||||
|  | 	seq_printf(m, "cpu mem:\t%llu kB\n", cpu_mem/1024UL); | ||||||
|  | 	for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { | ||||||
|  | 		uint32_t count = amdgpu_ctx_num_entities[i]; | ||||||
|  | 		int idx = 0; | ||||||
|  | 		uint64_t total = 0, min = 0; | ||||||
|  | 		uint32_t perc, frac; | ||||||
|  | 
 | ||||||
|  | 		for (idx = 0; idx < count; idx++) { | ||||||
|  | 			total = amdgpu_ctx_mgr_fence_usage(&fpriv->ctx_mgr, | ||||||
|  | 				i, idx, &min); | ||||||
|  | 			if ((total == 0) || (min == 0)) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | 			perc = div64_u64(10000 * total, min); | ||||||
|  | 			frac = perc % 100; | ||||||
|  | 
 | ||||||
|  | 			seq_printf(m, "%s%d:\t%d.%d%%\n", | ||||||
|  | 					amdgpu_ip_name[i], | ||||||
|  | 					idx, perc/100, frac); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | /* SPDX-License-Identifier: MIT
 | ||||||
|  |  * Copyright 2021 Advanced Micro Devices, Inc. | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  |  * copy of this software and associated documentation files (the "Software"), | ||||||
|  |  * to deal in the Software without restriction, including without limitation | ||||||
|  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  |  * and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  |  * Software is furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||||
|  |  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||||
|  |  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||||
|  |  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  |  * OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  * | ||||||
|  |  * Authors: David Nieto | ||||||
|  |  *          Roy Sun | ||||||
|  |  */ | ||||||
|  | #ifndef __AMDGPU_SMI_H__ | ||||||
|  | #define __AMDGPU_SMI_H__ | ||||||
|  | 
 | ||||||
|  | #include <linux/idr.h> | ||||||
|  | #include <linux/kfifo.h> | ||||||
|  | #include <linux/rbtree.h> | ||||||
|  | #include <drm/gpu_scheduler.h> | ||||||
|  | #include <drm/drm_file.h> | ||||||
|  | #include <drm/ttm/ttm_bo_driver.h> | ||||||
|  | #include <linux/sched/mm.h> | ||||||
|  | 
 | ||||||
|  | #include "amdgpu_sync.h" | ||||||
|  | #include "amdgpu_ring.h" | ||||||
|  | #include "amdgpu_ids.h" | ||||||
|  | 
 | ||||||
|  | uint32_t amdgpu_get_ip_count(struct amdgpu_device *adev, int id); | ||||||
|  | void amdgpu_show_fdinfo(struct seq_file *m, struct file *f); | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| @ -36,6 +36,7 @@ | |||||||
| #include <linux/firmware.h> | #include <linux/firmware.h> | ||||||
| #include <linux/pm_runtime.h> | #include <linux/pm_runtime.h> | ||||||
| 
 | 
 | ||||||
|  | #include <drm/drm_drv.h> | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| #include "amdgpu_trace.h" | #include "amdgpu_trace.h" | ||||||
| 
 | 
 | ||||||
| @ -434,6 +435,7 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring, | |||||||
|  * |  * | ||||||
|  * @ring: ring to init the fence driver on |  * @ring: ring to init the fence driver on | ||||||
|  * @num_hw_submission: number of entries on the hardware queue |  * @num_hw_submission: number of entries on the hardware queue | ||||||
|  |  * @sched_score: optional score atomic shared with other schedulers | ||||||
|  * |  * | ||||||
|  * Init the fence driver for the requested ring (all asics). |  * Init the fence driver for the requested ring (all asics). | ||||||
|  * Helper function for amdgpu_fence_driver_init(). |  * Helper function for amdgpu_fence_driver_init(). | ||||||
| @ -523,10 +525,9 @@ int amdgpu_fence_driver_init(struct amdgpu_device *adev) | |||||||
|  * |  * | ||||||
|  * Tear down the fence driver for all possible rings (all asics). |  * Tear down the fence driver for all possible rings (all asics). | ||||||
|  */ |  */ | ||||||
| void amdgpu_fence_driver_fini(struct amdgpu_device *adev) | void amdgpu_fence_driver_fini_hw(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	unsigned i, j; | 	int i, r; | ||||||
| 	int r; |  | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) { | 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) { | ||||||
| 		struct amdgpu_ring *ring = adev->rings[i]; | 		struct amdgpu_ring *ring = adev->rings[i]; | ||||||
| @ -535,16 +536,33 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev) | |||||||
| 			continue; | 			continue; | ||||||
| 		if (!ring->no_scheduler) | 		if (!ring->no_scheduler) | ||||||
| 			drm_sched_fini(&ring->sched); | 			drm_sched_fini(&ring->sched); | ||||||
|  | 		/* You can't wait for HW to signal if it's gone */ | ||||||
|  | 		if (!drm_dev_is_unplugged(&adev->ddev)) | ||||||
| 			r = amdgpu_fence_wait_empty(ring); | 			r = amdgpu_fence_wait_empty(ring); | ||||||
| 		if (r) { | 		else | ||||||
|  | 			r = -ENODEV; | ||||||
| 		/* no need to trigger GPU reset as we are unloading */ | 		/* no need to trigger GPU reset as we are unloading */ | ||||||
|  | 		if (r) | ||||||
| 			amdgpu_fence_driver_force_completion(ring); | 			amdgpu_fence_driver_force_completion(ring); | ||||||
| 		} | 
 | ||||||
| 		if (ring->fence_drv.irq_src) | 		if (ring->fence_drv.irq_src) | ||||||
| 			amdgpu_irq_put(adev, ring->fence_drv.irq_src, | 			amdgpu_irq_put(adev, ring->fence_drv.irq_src, | ||||||
| 				       ring->fence_drv.irq_type); | 				       ring->fence_drv.irq_type); | ||||||
| 
 | 
 | ||||||
| 		del_timer_sync(&ring->fence_drv.fallback_timer); | 		del_timer_sync(&ring->fence_drv.fallback_timer); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void amdgpu_fence_driver_fini_sw(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	unsigned int i, j; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < AMDGPU_MAX_RINGS; i++) { | ||||||
|  | 		struct amdgpu_ring *ring = adev->rings[i]; | ||||||
|  | 
 | ||||||
|  | 		if (!ring || !ring->fence_drv.initialized) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j) | 		for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j) | ||||||
| 			dma_fence_put(ring->fence_drv.fences[j]); | 			dma_fence_put(ring->fence_drv.fences[j]); | ||||||
| 		kfree(ring->fence_drv.fences); | 		kfree(ring->fence_drv.fences); | ||||||
|  | |||||||
| @ -121,6 +121,9 @@ static const struct file_operations amdgpu_fw_attestation_debugfs_ops = { | |||||||
| 
 | 
 | ||||||
| static int amdgpu_is_fw_attestation_supported(struct amdgpu_device *adev) | static int amdgpu_is_fw_attestation_supported(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
|  | 	if (adev->flags & AMD_IS_APU) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
| 	if (adev->asic_type >= CHIP_SIENNA_CICHLID) | 	if (adev->asic_type >= CHIP_SIENNA_CICHLID) | ||||||
| 		return 1; | 		return 1; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_dummy_page_init - init dummy page used by the driver |  * amdgpu_gart_dummy_page_init - init dummy page used by the driver | ||||||
|  * |  * | ||||||
|  * @adev: amdgpu_device pointer |  * @adev: amdgpu_device pointer | ||||||
|  * |  * | ||||||
| @ -86,13 +86,13 @@ static int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_dummy_page_fini - free dummy page used by the driver |  * amdgpu_gart_dummy_page_fini - free dummy page used by the driver | ||||||
|  * |  * | ||||||
|  * @adev: amdgpu_device pointer |  * @adev: amdgpu_device pointer | ||||||
|  * |  * | ||||||
|  * Frees the dummy page used by the driver (all asics). |  * Frees the dummy page used by the driver (all asics). | ||||||
|  */ |  */ | ||||||
| static void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev) | void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	if (!adev->dummy_page_addr) | 	if (!adev->dummy_page_addr) | ||||||
| 		return; | 		return; | ||||||
| @ -250,7 +250,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	mb(); | 	mb(); | ||||||
| 	amdgpu_asic_flush_hdp(adev, NULL); | 	amdgpu_device_flush_hdp(adev, NULL); | ||||||
| 	for (i = 0; i < adev->num_vmhubs; i++) | 	for (i = 0; i < adev->num_vmhubs; i++) | ||||||
| 		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0); | 		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0); | ||||||
| 
 | 
 | ||||||
| @ -300,7 +300,6 @@ int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, | |||||||
|  * @adev: amdgpu_device pointer |  * @adev: amdgpu_device pointer | ||||||
|  * @offset: offset into the GPU's gart aperture |  * @offset: offset into the GPU's gart aperture | ||||||
|  * @pages: number of pages to bind |  * @pages: number of pages to bind | ||||||
|  * @pagelist: pages to bind |  | ||||||
|  * @dma_addr: DMA addresses of pages |  * @dma_addr: DMA addresses of pages | ||||||
|  * @flags: page table entry flags |  * @flags: page table entry flags | ||||||
|  * |  * | ||||||
| @ -309,11 +308,9 @@ int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, | |||||||
|  * Returns 0 for success, -EINVAL for failure. |  * Returns 0 for success, -EINVAL for failure. | ||||||
|  */ |  */ | ||||||
| int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, | int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, | ||||||
| 		     int pages, struct page **pagelist, dma_addr_t *dma_addr, | 		     int pages, dma_addr_t *dma_addr, | ||||||
| 		     uint64_t flags) | 		     uint64_t flags) | ||||||
| { | { | ||||||
| 	int r, i; |  | ||||||
| 
 |  | ||||||
| 	if (!adev->gart.ready) { | 	if (!adev->gart.ready) { | ||||||
| 		WARN(1, "trying to bind memory to uninitialized GART !\n"); | 		WARN(1, "trying to bind memory to uninitialized GART !\n"); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| @ -322,16 +319,26 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, | |||||||
| 	if (!adev->gart.ptr) | 	if (!adev->gart.ptr) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	r = amdgpu_gart_map(adev, offset, pages, dma_addr, flags, | 	return amdgpu_gart_map(adev, offset, pages, dma_addr, flags, | ||||||
| 			       adev->gart.ptr); | 			       adev->gart.ptr); | ||||||
| 	if (r) | } | ||||||
| 		return r; | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_gart_invalidate_tlb - invalidate gart TLB | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu device driver pointer | ||||||
|  |  * | ||||||
|  |  * Invalidate gart TLB which can be use as a way to flush gart changes | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | void amdgpu_gart_invalidate_tlb(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
| 
 | 
 | ||||||
| 	mb(); | 	mb(); | ||||||
| 	amdgpu_asic_flush_hdp(adev, NULL); | 	amdgpu_device_flush_hdp(adev, NULL); | ||||||
| 	for (i = 0; i < adev->num_vmhubs; i++) | 	for (i = 0; i < adev->num_vmhubs; i++) | ||||||
| 		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0); | 		amdgpu_gmc_flush_gpu_tlb(adev, 0, i, 0); | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -365,15 +372,3 @@ int amdgpu_gart_init(struct amdgpu_device *adev) | |||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * amdgpu_gart_fini - tear down the driver info for managing the gart |  | ||||||
|  * |  | ||||||
|  * @adev: amdgpu_device pointer |  | ||||||
|  * |  | ||||||
|  * Tear down the gart driver info and free the dummy page (all asics). |  | ||||||
|  */ |  | ||||||
| void amdgpu_gart_fini(struct amdgpu_device *adev) |  | ||||||
| { |  | ||||||
| 	amdgpu_gart_dummy_page_fini(adev); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -57,14 +57,13 @@ void amdgpu_gart_table_vram_free(struct amdgpu_device *adev); | |||||||
| int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev); | int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev); | ||||||
| void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev); | void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev); | ||||||
| int amdgpu_gart_init(struct amdgpu_device *adev); | int amdgpu_gart_init(struct amdgpu_device *adev); | ||||||
| void amdgpu_gart_fini(struct amdgpu_device *adev); | void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev); | ||||||
| int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, | int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, | ||||||
| 		       int pages); | 		       int pages); | ||||||
| int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, | int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, | ||||||
| 		    int pages, dma_addr_t *dma_addr, uint64_t flags, | 		    int pages, dma_addr_t *dma_addr, uint64_t flags, | ||||||
| 		    void *dst); | 		    void *dst); | ||||||
| int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, | int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, | ||||||
| 		     int pages, struct page **pagelist, | 		     int pages, dma_addr_t *dma_addr, uint64_t flags); | ||||||
| 		     dma_addr_t *dma_addr, uint64_t flags); | void amdgpu_gart_invalidate_tlb(struct amdgpu_device *adev); | ||||||
| 
 |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ | |||||||
| #include <linux/dma-buf.h> | #include <linux/dma-buf.h> | ||||||
| 
 | 
 | ||||||
| #include <drm/amdgpu_drm.h> | #include <drm/amdgpu_drm.h> | ||||||
|  | #include <drm/drm_drv.h> | ||||||
| #include <drm/drm_gem_ttm_helper.h> | #include <drm/drm_gem_ttm_helper.h> | ||||||
| 
 | 
 | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| @ -41,6 +42,46 @@ | |||||||
| 
 | 
 | ||||||
| static const struct drm_gem_object_funcs amdgpu_gem_object_funcs; | static const struct drm_gem_object_funcs amdgpu_gem_object_funcs; | ||||||
| 
 | 
 | ||||||
|  | static vm_fault_t amdgpu_gem_fault(struct vm_fault *vmf) | ||||||
|  | { | ||||||
|  | 	struct ttm_buffer_object *bo = vmf->vma->vm_private_data; | ||||||
|  | 	struct drm_device *ddev = bo->base.dev; | ||||||
|  | 	vm_fault_t ret; | ||||||
|  | 	int idx; | ||||||
|  | 
 | ||||||
|  | 	ret = ttm_bo_vm_reserve(bo, vmf); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	if (drm_dev_enter(ddev, &idx)) { | ||||||
|  | 		ret = amdgpu_bo_fault_reserve_notify(bo); | ||||||
|  | 		if (ret) { | ||||||
|  | 			drm_dev_exit(idx); | ||||||
|  | 			goto unlock; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		 ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot, | ||||||
|  | 						TTM_BO_VM_NUM_PREFAULT, 1); | ||||||
|  | 
 | ||||||
|  | 		 drm_dev_exit(idx); | ||||||
|  | 	} else { | ||||||
|  | 		ret = ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot); | ||||||
|  | 	} | ||||||
|  | 	if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | unlock: | ||||||
|  | 	dma_resv_unlock(bo->base.resv); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct vm_operations_struct amdgpu_gem_vm_ops = { | ||||||
|  | 	.fault = amdgpu_gem_fault, | ||||||
|  | 	.open = ttm_bo_vm_open, | ||||||
|  | 	.close = ttm_bo_vm_close, | ||||||
|  | 	.access = ttm_bo_vm_access | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static void amdgpu_gem_object_free(struct drm_gem_object *gobj) | static void amdgpu_gem_object_free(struct drm_gem_object *gobj) | ||||||
| { | { | ||||||
| 	struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj); | 	struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj); | ||||||
| @ -129,7 +170,7 @@ static int amdgpu_gem_object_open(struct drm_gem_object *obj, | |||||||
| 		return -EPERM; | 		return -EPERM; | ||||||
| 
 | 
 | ||||||
| 	if (abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID && | 	if (abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID && | ||||||
| 	    abo->tbo.base.resv != vm->root.base.bo->tbo.base.resv) | 	    abo->tbo.base.resv != vm->root.bo->tbo.base.resv) | ||||||
| 		return -EPERM; | 		return -EPERM; | ||||||
| 
 | 
 | ||||||
| 	r = amdgpu_bo_reserve(abo, false); | 	r = amdgpu_bo_reserve(abo, false); | ||||||
| @ -185,7 +226,7 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, | |||||||
| 	if (!amdgpu_vm_ready(vm)) | 	if (!amdgpu_vm_ready(vm)) | ||||||
| 		goto out_unlock; | 		goto out_unlock; | ||||||
| 
 | 
 | ||||||
| 	fence = dma_resv_get_excl(bo->tbo.base.resv); | 	fence = dma_resv_excl_fence(bo->tbo.base.resv); | ||||||
| 	if (fence) { | 	if (fence) { | ||||||
| 		amdgpu_bo_fence(bo, fence, true); | 		amdgpu_bo_fence(bo, fence, true); | ||||||
| 		fence = NULL; | 		fence = NULL; | ||||||
| @ -205,6 +246,18 @@ out_unlock: | |||||||
| 	ttm_eu_backoff_reservation(&ticket, &list); | 	ttm_eu_backoff_reservation(&ticket, &list); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int amdgpu_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); | ||||||
|  | 
 | ||||||
|  | 	if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) | ||||||
|  | 		return -EPERM; | ||||||
|  | 	if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) | ||||||
|  | 		return -EPERM; | ||||||
|  | 
 | ||||||
|  | 	return drm_gem_ttm_mmap(obj, vma); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static const struct drm_gem_object_funcs amdgpu_gem_object_funcs = { | static const struct drm_gem_object_funcs amdgpu_gem_object_funcs = { | ||||||
| 	.free = amdgpu_gem_object_free, | 	.free = amdgpu_gem_object_free, | ||||||
| 	.open = amdgpu_gem_object_open, | 	.open = amdgpu_gem_object_open, | ||||||
| @ -212,6 +265,8 @@ static const struct drm_gem_object_funcs amdgpu_gem_object_funcs = { | |||||||
| 	.export = amdgpu_gem_prime_export, | 	.export = amdgpu_gem_prime_export, | ||||||
| 	.vmap = drm_gem_ttm_vmap, | 	.vmap = drm_gem_ttm_vmap, | ||||||
| 	.vunmap = drm_gem_ttm_vunmap, | 	.vunmap = drm_gem_ttm_vunmap, | ||||||
|  | 	.mmap = amdgpu_gem_object_mmap, | ||||||
|  | 	.vm_ops = &amdgpu_gem_vm_ops, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -265,11 +320,11 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { | 	if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { | ||||||
| 		r = amdgpu_bo_reserve(vm->root.base.bo, false); | 		r = amdgpu_bo_reserve(vm->root.bo, false); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			return r; | 			return r; | ||||||
| 
 | 
 | ||||||
| 		resv = vm->root.base.bo->tbo.base.resv; | 		resv = vm->root.bo->tbo.base.resv; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	initial_domain = (u32)(0xffffffff & args->in.domains); | 	initial_domain = (u32)(0xffffffff & args->in.domains); | ||||||
| @ -298,9 +353,9 @@ retry: | |||||||
| 		if (!r) { | 		if (!r) { | ||||||
| 			struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj); | 			struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj); | ||||||
| 
 | 
 | ||||||
| 			abo->parent = amdgpu_bo_ref(vm->root.base.bo); | 			abo->parent = amdgpu_bo_ref(vm->root.bo); | ||||||
| 		} | 		} | ||||||
| 		amdgpu_bo_unreserve(vm->root.base.bo); | 		amdgpu_bo_unreserve(vm->root.bo); | ||||||
| 	} | 	} | ||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
| @ -471,8 +526,7 @@ int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data, | |||||||
| 		return -ENOENT; | 		return -ENOENT; | ||||||
| 	} | 	} | ||||||
| 	robj = gem_to_amdgpu_bo(gobj); | 	robj = gem_to_amdgpu_bo(gobj); | ||||||
| 	ret = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true, | 	ret = dma_resv_wait_timeout(robj->tbo.base.resv, true, true, timeout); | ||||||
| 						  timeout); |  | ||||||
| 
 | 
 | ||||||
| 	/* ret == 0 means not signaled,
 | 	/* ret == 0 means not signaled,
 | ||||||
| 	 * ret > 0 means signaled | 	 * ret > 0 means signaled | ||||||
| @ -558,7 +612,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, | |||||||
| 
 | 
 | ||||||
| 	if (operation == AMDGPU_VA_OP_MAP || | 	if (operation == AMDGPU_VA_OP_MAP || | ||||||
| 	    operation == AMDGPU_VA_OP_REPLACE) { | 	    operation == AMDGPU_VA_OP_REPLACE) { | ||||||
| 		r = amdgpu_vm_bo_update(adev, bo_va, false); | 		r = amdgpu_vm_bo_update(adev, bo_va, false, NULL); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			goto error; | 			goto error; | ||||||
| 	} | 	} | ||||||
| @ -766,7 +820,7 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, | |||||||
| 		void __user *out = u64_to_user_ptr(args->value); | 		void __user *out = u64_to_user_ptr(args->value); | ||||||
| 
 | 
 | ||||||
| 		info.bo_size = robj->tbo.base.size; | 		info.bo_size = robj->tbo.base.size; | ||||||
| 		info.alignment = robj->tbo.mem.page_alignment << PAGE_SHIFT; | 		info.alignment = robj->tbo.page_alignment << PAGE_SHIFT; | ||||||
| 		info.domains = robj->preferred_domains; | 		info.domains = robj->preferred_domains; | ||||||
| 		info.domain_flags = robj->flags; | 		info.domain_flags = robj->flags; | ||||||
| 		amdgpu_bo_unreserve(robj); | 		amdgpu_bo_unreserve(robj); | ||||||
| @ -787,7 +841,7 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, | |||||||
| 		} | 		} | ||||||
| 		for (base = robj->vm_bo; base; base = base->next) | 		for (base = robj->vm_bo; base; base = base->next) | ||||||
| 			if (amdgpu_xgmi_same_hive(amdgpu_ttm_adev(robj->tbo.bdev), | 			if (amdgpu_xgmi_same_hive(amdgpu_ttm_adev(robj->tbo.bdev), | ||||||
| 				amdgpu_ttm_adev(base->vm->root.base.bo->tbo.bdev))) { | 				amdgpu_ttm_adev(base->vm->root.bo->tbo.bdev))) { | ||||||
| 				r = -EINVAL; | 				r = -EINVAL; | ||||||
| 				amdgpu_bo_unreserve(robj); | 				amdgpu_bo_unreserve(robj); | ||||||
| 				goto out; | 				goto out; | ||||||
|  | |||||||
| @ -607,7 +607,6 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev) | |||||||
| 	struct ras_ih_if ih_info = { | 	struct ras_ih_if ih_info = { | ||||||
| 		.cb = amdgpu_gfx_process_ras_data_cb, | 		.cb = amdgpu_gfx_process_ras_data_cb, | ||||||
| 	}; | 	}; | ||||||
| 	struct ras_query_if info = { 0 }; |  | ||||||
| 
 | 
 | ||||||
| 	if (!adev->gfx.ras_if) { | 	if (!adev->gfx.ras_if) { | ||||||
| 		adev->gfx.ras_if = kmalloc(sizeof(struct ras_common_if), GFP_KERNEL); | 		adev->gfx.ras_if = kmalloc(sizeof(struct ras_common_if), GFP_KERNEL); | ||||||
| @ -625,12 +624,8 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev) | |||||||
| 		goto free; | 		goto free; | ||||||
| 
 | 
 | ||||||
| 	if (amdgpu_ras_is_supported(adev, adev->gfx.ras_if->block)) { | 	if (amdgpu_ras_is_supported(adev, adev->gfx.ras_if->block)) { | ||||||
| 		if (adev->gmc.xgmi.connected_to_cpu) { | 		if (!amdgpu_persistent_edc_harvesting_supported(adev)) | ||||||
| 			info.head = *adev->gfx.ras_if; |  | ||||||
| 			amdgpu_ras_query_error_status(adev, &info); |  | ||||||
| 		} else { |  | ||||||
| 			amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); | 			amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX); | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); | 		r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); | ||||||
| 		if (r) | 		if (r) | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ struct amdgpu_gfxhub_funcs { | |||||||
| 	void (*set_fault_enable_default)(struct amdgpu_device *adev, bool value); | 	void (*set_fault_enable_default)(struct amdgpu_device *adev, bool value); | ||||||
| 	void (*init)(struct amdgpu_device *adev); | 	void (*init)(struct amdgpu_device *adev); | ||||||
| 	int (*get_xgmi_info)(struct amdgpu_device *adev); | 	int (*get_xgmi_info)(struct amdgpu_device *adev); | ||||||
|  | 	void (*utcl2_harvest)(struct amdgpu_device *adev); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct amdgpu_gfxhub { | struct amdgpu_gfxhub { | ||||||
|  | |||||||
| @ -31,6 +31,8 @@ | |||||||
| #include "amdgpu_ras.h" | #include "amdgpu_ras.h" | ||||||
| #include "amdgpu_xgmi.h" | #include "amdgpu_xgmi.h" | ||||||
| 
 | 
 | ||||||
|  | #include <drm/drm_drv.h> | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_gmc_pdb0_alloc - allocate vram for pdb0 |  * amdgpu_gmc_pdb0_alloc - allocate vram for pdb0 | ||||||
|  * |  * | ||||||
| @ -99,7 +101,7 @@ void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level, | |||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | ||||||
| 
 | 
 | ||||||
| 	switch (bo->tbo.mem.mem_type) { | 	switch (bo->tbo.resource->mem_type) { | ||||||
| 	case TTM_PL_TT: | 	case TTM_PL_TT: | ||||||
| 		*addr = bo->tbo.ttm->dma_address[0]; | 		*addr = bo->tbo.ttm->dma_address[0]; | ||||||
| 		break; | 		break; | ||||||
| @ -110,7 +112,7 @@ void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level, | |||||||
| 		*addr = 0; | 		*addr = 0; | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 	*flags = amdgpu_ttm_tt_pde_flags(bo->tbo.ttm, &bo->tbo.mem); | 	*flags = amdgpu_ttm_tt_pde_flags(bo->tbo.ttm, bo->tbo.resource); | ||||||
| 	amdgpu_gmc_get_vm_pde(adev, level, addr, flags); | 	amdgpu_gmc_get_vm_pde(adev, level, addr, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -151,6 +153,10 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, | |||||||
| { | { | ||||||
| 	void __iomem *ptr = (void *)cpu_pt_addr; | 	void __iomem *ptr = (void *)cpu_pt_addr; | ||||||
| 	uint64_t value; | 	uint64_t value; | ||||||
|  | 	int idx; | ||||||
|  | 
 | ||||||
|  | 	if (!drm_dev_enter(&adev->ddev, &idx)) | ||||||
|  | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * The following is for PTE only. GART does not have PDEs. | 	 * The following is for PTE only. GART does not have PDEs. | ||||||
| @ -158,6 +164,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, | |||||||
| 	value = addr & 0x0000FFFFFFFFF000ULL; | 	value = addr & 0x0000FFFFFFFFF000ULL; | ||||||
| 	value |= flags; | 	value |= flags; | ||||||
| 	writeq(value, ptr + (gpu_page_idx * 8)); | 	writeq(value, ptr + (gpu_page_idx * 8)); | ||||||
|  | 
 | ||||||
|  | 	drm_dev_exit(idx); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -332,6 +341,17 @@ void amdgpu_gmc_agp_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc) | |||||||
| 			mc->agp_size >> 20, mc->agp_start, mc->agp_end); | 			mc->agp_size >> 20, mc->agp_start, mc->agp_end); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_gmc_fault_key - get hask key from vm fault address and pasid | ||||||
|  |  * | ||||||
|  |  * @addr: 48 bit physical address, page aligned (36 significant bits) | ||||||
|  |  * @pasid: 16 bit process address space identifier | ||||||
|  |  */ | ||||||
|  | static inline uint64_t amdgpu_gmc_fault_key(uint64_t addr, uint16_t pasid) | ||||||
|  | { | ||||||
|  | 	return addr << 4 | pasid; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_gmc_filter_faults - filter VM faults |  * amdgpu_gmc_filter_faults - filter VM faults | ||||||
|  * |  * | ||||||
| @ -348,8 +368,7 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr, | |||||||
| 			      uint16_t pasid, uint64_t timestamp) | 			      uint16_t pasid, uint64_t timestamp) | ||||||
| { | { | ||||||
| 	struct amdgpu_gmc *gmc = &adev->gmc; | 	struct amdgpu_gmc *gmc = &adev->gmc; | ||||||
| 
 | 	uint64_t stamp, key = amdgpu_gmc_fault_key(addr, pasid); | ||||||
| 	uint64_t stamp, key = addr << 4 | pasid; |  | ||||||
| 	struct amdgpu_gmc_fault *fault; | 	struct amdgpu_gmc_fault *fault; | ||||||
| 	uint32_t hash; | 	uint32_t hash; | ||||||
| 
 | 
 | ||||||
| @ -365,7 +384,7 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr, | |||||||
| 	while (fault->timestamp >= stamp) { | 	while (fault->timestamp >= stamp) { | ||||||
| 		uint64_t tmp; | 		uint64_t tmp; | ||||||
| 
 | 
 | ||||||
| 		if (fault->key == key) | 		if (atomic64_read(&fault->key) == key) | ||||||
| 			return true; | 			return true; | ||||||
| 
 | 
 | ||||||
| 		tmp = fault->timestamp; | 		tmp = fault->timestamp; | ||||||
| @ -378,7 +397,7 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr, | |||||||
| 
 | 
 | ||||||
| 	/* Add the fault to the ring */ | 	/* Add the fault to the ring */ | ||||||
| 	fault = &gmc->fault_ring[gmc->last_fault]; | 	fault = &gmc->fault_ring[gmc->last_fault]; | ||||||
| 	fault->key = key; | 	atomic64_set(&fault->key, key); | ||||||
| 	fault->timestamp = timestamp; | 	fault->timestamp = timestamp; | ||||||
| 
 | 
 | ||||||
| 	/* And update the hash */ | 	/* And update the hash */ | ||||||
| @ -387,6 +406,36 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr, | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_gmc_filter_faults_remove - remove address from VM faults filter | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu device structure | ||||||
|  |  * @addr: address of the VM fault | ||||||
|  |  * @pasid: PASID of the process causing the fault | ||||||
|  |  * | ||||||
|  |  * Remove the address from fault filter, then future vm fault on this address | ||||||
|  |  * will pass to retry fault handler to recover. | ||||||
|  |  */ | ||||||
|  | void amdgpu_gmc_filter_faults_remove(struct amdgpu_device *adev, uint64_t addr, | ||||||
|  | 				     uint16_t pasid) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_gmc *gmc = &adev->gmc; | ||||||
|  | 	uint64_t key = amdgpu_gmc_fault_key(addr, pasid); | ||||||
|  | 	struct amdgpu_gmc_fault *fault; | ||||||
|  | 	uint32_t hash; | ||||||
|  | 	uint64_t tmp; | ||||||
|  | 
 | ||||||
|  | 	hash = hash_64(key, AMDGPU_GMC_FAULT_HASH_ORDER); | ||||||
|  | 	fault = &gmc->fault_ring[gmc->fault_hash[hash].idx]; | ||||||
|  | 	do { | ||||||
|  | 		if (atomic64_cmpxchg(&fault->key, key, 0) == key) | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
|  | 		tmp = fault->timestamp; | ||||||
|  | 		fault = &gmc->fault_ring[fault->next]; | ||||||
|  | 	} while (fault->timestamp < tmp); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev) | int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	int r; | 	int r; | ||||||
| @ -415,6 +464,13 @@ int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev) | |||||||
| 			return r; | 			return r; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (adev->hdp.ras_funcs && | ||||||
|  | 	    adev->hdp.ras_funcs->ras_late_init) { | ||||||
|  | 		r = adev->hdp.ras_funcs->ras_late_init(adev); | ||||||
|  | 		if (r) | ||||||
|  | 			return r; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -426,11 +482,15 @@ void amdgpu_gmc_ras_fini(struct amdgpu_device *adev) | |||||||
| 
 | 
 | ||||||
| 	if (adev->mmhub.ras_funcs && | 	if (adev->mmhub.ras_funcs && | ||||||
| 	    adev->mmhub.ras_funcs->ras_fini) | 	    adev->mmhub.ras_funcs->ras_fini) | ||||||
| 		amdgpu_mmhub_ras_fini(adev); | 		adev->mmhub.ras_funcs->ras_fini(adev); | ||||||
| 
 | 
 | ||||||
| 	if (adev->gmc.xgmi.ras_funcs && | 	if (adev->gmc.xgmi.ras_funcs && | ||||||
| 	    adev->gmc.xgmi.ras_funcs->ras_fini) | 	    adev->gmc.xgmi.ras_funcs->ras_fini) | ||||||
| 		adev->gmc.xgmi.ras_funcs->ras_fini(adev); | 		adev->gmc.xgmi.ras_funcs->ras_fini(adev); | ||||||
|  | 
 | ||||||
|  | 	if (adev->hdp.ras_funcs && | ||||||
|  | 	    adev->hdp.ras_funcs->ras_fini) | ||||||
|  | 		adev->hdp.ras_funcs->ras_fini(adev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| @ -477,7 +537,7 @@ int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_tmz_set -- check and set if a device supports TMZ |  * amdgpu_gmc_tmz_set -- check and set if a device supports TMZ | ||||||
|  * @adev: amdgpu_device pointer |  * @adev: amdgpu_device pointer | ||||||
|  * |  * | ||||||
|  * Check and set if an the device @adev supports Trusted Memory |  * Check and set if an the device @adev supports Trusted Memory | ||||||
| @ -523,7 +583,7 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_noretry_set -- set per asic noretry defaults |  * amdgpu_gmc_noretry_set -- set per asic noretry defaults | ||||||
|  * @adev: amdgpu_device pointer |  * @adev: amdgpu_device pointer | ||||||
|  * |  * | ||||||
|  * Set a per asic default for the no-retry parameter. |  * Set a per asic default for the no-retry parameter. | ||||||
| @ -578,13 +638,18 @@ void amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, | |||||||
| 	for (i = 0; i < 16; i++) { | 	for (i = 0; i < 16; i++) { | ||||||
| 		reg = hub->vm_context0_cntl + hub->ctx_distance * i; | 		reg = hub->vm_context0_cntl + hub->ctx_distance * i; | ||||||
| 
 | 
 | ||||||
| 		tmp = RREG32(reg); | 		tmp = (hub_type == AMDGPU_GFXHUB_0) ? | ||||||
|  | 			RREG32_SOC15_IP(GC, reg) : | ||||||
|  | 			RREG32_SOC15_IP(MMHUB, reg); | ||||||
|  | 
 | ||||||
| 		if (enable) | 		if (enable) | ||||||
| 			tmp |= hub->vm_cntx_cntl_vm_fault; | 			tmp |= hub->vm_cntx_cntl_vm_fault; | ||||||
| 		else | 		else | ||||||
| 			tmp &= ~hub->vm_cntx_cntl_vm_fault; | 			tmp &= ~hub->vm_cntx_cntl_vm_fault; | ||||||
| 
 | 
 | ||||||
| 		WREG32(reg, tmp); | 		(hub_type == AMDGPU_GFXHUB_0) ? | ||||||
|  | 			WREG32_SOC15_IP(GC, reg, tmp) : | ||||||
|  | 			WREG32_SOC15_IP(MMHUB, reg, tmp); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -720,3 +785,22 @@ uint64_t amdgpu_gmc_vram_cpu_pa(struct amdgpu_device *adev, struct amdgpu_bo *bo | |||||||
| { | { | ||||||
| 	return amdgpu_bo_gpu_offset(bo) - adev->gmc.vram_start + adev->gmc.aper_base; | 	return amdgpu_bo_gpu_offset(bo) - adev->gmc.vram_start + adev->gmc.aper_base; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void amdgpu_gmc_get_reserved_allocation(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	/* Some ASICs need to reserve a region of video memory to avoid access
 | ||||||
|  | 	 * from driver */ | ||||||
|  | 	adev->mman.stolen_reserved_offset = 0; | ||||||
|  | 	adev->mman.stolen_reserved_size = 0; | ||||||
|  | 
 | ||||||
|  | 	switch (adev->asic_type) { | ||||||
|  | 	case CHIP_YELLOW_CARP: | ||||||
|  | 		if (amdgpu_discovery == 0) { | ||||||
|  | 			adev->mman.stolen_reserved_offset = 0x1ffb0000; | ||||||
|  | 			adev->mman.stolen_reserved_size = 64 * PAGE_SIZE; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
| @ -66,9 +66,9 @@ struct firmware; | |||||||
|  * GMC page fault information |  * GMC page fault information | ||||||
|  */ |  */ | ||||||
| struct amdgpu_gmc_fault { | struct amdgpu_gmc_fault { | ||||||
| 	uint64_t	timestamp; | 	uint64_t	timestamp:48; | ||||||
| 	uint64_t	next:AMDGPU_GMC_FAULT_RING_ORDER; | 	uint64_t	next:AMDGPU_GMC_FAULT_RING_ORDER; | ||||||
| 	uint64_t	key:52; | 	atomic64_t	key; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -318,6 +318,8 @@ void amdgpu_gmc_agp_location(struct amdgpu_device *adev, | |||||||
| 			     struct amdgpu_gmc *mc); | 			     struct amdgpu_gmc *mc); | ||||||
| bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr, | bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr, | ||||||
| 			      uint16_t pasid, uint64_t timestamp); | 			      uint16_t pasid, uint64_t timestamp); | ||||||
|  | void amdgpu_gmc_filter_faults_remove(struct amdgpu_device *adev, uint64_t addr, | ||||||
|  | 				     uint16_t pasid); | ||||||
| int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev); | int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev); | ||||||
| void amdgpu_gmc_ras_fini(struct amdgpu_device *adev); | void amdgpu_gmc_ras_fini(struct amdgpu_device *adev); | ||||||
| int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev); | int amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev); | ||||||
| @ -330,6 +332,7 @@ amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, | |||||||
| 			      bool enable); | 			      bool enable); | ||||||
| 
 | 
 | ||||||
| void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev); | void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev); | ||||||
|  | void amdgpu_gmc_get_reserved_allocation(struct amdgpu_device *adev); | ||||||
| 
 | 
 | ||||||
| void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev); | void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev); | ||||||
| uint64_t amdgpu_gmc_vram_mc2pa(struct amdgpu_device *adev, uint64_t mc_addr); | uint64_t amdgpu_gmc_vram_mc2pa(struct amdgpu_device *adev, uint64_t mc_addr); | ||||||
|  | |||||||
| @ -22,17 +22,26 @@ | |||||||
|  * Authors: Christian König |  * Authors: Christian König | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <drm/ttm/ttm_range_manager.h> | ||||||
|  | 
 | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| 
 | 
 | ||||||
| static inline struct amdgpu_gtt_mgr *to_gtt_mgr(struct ttm_resource_manager *man) | struct amdgpu_gtt_node { | ||||||
|  | 	struct ttm_buffer_object *tbo; | ||||||
|  | 	struct ttm_range_mgr_node base; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static inline struct amdgpu_gtt_mgr * | ||||||
|  | to_gtt_mgr(struct ttm_resource_manager *man) | ||||||
| { | { | ||||||
| 	return container_of(man, struct amdgpu_gtt_mgr, manager); | 	return container_of(man, struct amdgpu_gtt_mgr, manager); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct amdgpu_gtt_node { | static inline struct amdgpu_gtt_node * | ||||||
| 	struct drm_mm_node node; | to_amdgpu_gtt_node(struct ttm_resource *res) | ||||||
| 	struct ttm_buffer_object *tbo; | { | ||||||
| }; | 	return container_of(res, struct amdgpu_gtt_node, base.base); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * DOC: mem_info_gtt_total |  * DOC: mem_info_gtt_total | ||||||
| @ -43,12 +52,14 @@ struct amdgpu_gtt_node { | |||||||
|  * the GTT block, in bytes |  * the GTT block, in bytes | ||||||
|  */ |  */ | ||||||
| static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev, | static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev, | ||||||
| 		struct device_attribute *attr, char *buf) | 					      struct device_attribute *attr, | ||||||
|  | 					      char *buf) | ||||||
| { | { | ||||||
| 	struct drm_device *ddev = dev_get_drvdata(dev); | 	struct drm_device *ddev = dev_get_drvdata(dev); | ||||||
| 	struct amdgpu_device *adev = drm_to_adev(ddev); | 	struct amdgpu_device *adev = drm_to_adev(ddev); | ||||||
| 	struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | 	struct ttm_resource_manager *man; | ||||||
| 
 | 
 | ||||||
|  | 	man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | ||||||
| 	return sysfs_emit(buf, "%llu\n", man->size * PAGE_SIZE); | 	return sysfs_emit(buf, "%llu\n", man->size * PAGE_SIZE); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -61,12 +72,14 @@ static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev, | |||||||
|  * size of the GTT block, in bytes |  * size of the GTT block, in bytes | ||||||
|  */ |  */ | ||||||
| static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev, | static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev, | ||||||
| 		struct device_attribute *attr, char *buf) | 					     struct device_attribute *attr, | ||||||
|  | 					     char *buf) | ||||||
| { | { | ||||||
| 	struct drm_device *ddev = dev_get_drvdata(dev); | 	struct drm_device *ddev = dev_get_drvdata(dev); | ||||||
| 	struct amdgpu_device *adev = drm_to_adev(ddev); | 	struct amdgpu_device *adev = drm_to_adev(ddev); | ||||||
| 	struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | 	struct ttm_resource_manager *man; | ||||||
| 
 | 
 | ||||||
|  | 	man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); | ||||||
| 	return sysfs_emit(buf, "%llu\n", amdgpu_gtt_mgr_usage(man)); | 	return sysfs_emit(buf, "%llu\n", amdgpu_gtt_mgr_usage(man)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -75,90 +88,28 @@ static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, | |||||||
| static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, | static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO, | ||||||
| 	           amdgpu_mem_info_gtt_used_show, NULL); | 	           amdgpu_mem_info_gtt_used_show, NULL); | ||||||
| 
 | 
 | ||||||
| static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func; | static struct attribute *amdgpu_gtt_mgr_attributes[] = { | ||||||
| /**
 | 	&dev_attr_mem_info_gtt_total.attr, | ||||||
|  * amdgpu_gtt_mgr_init - init GTT manager and DRM MM | 	&dev_attr_mem_info_gtt_used.attr, | ||||||
|  * | 	NULL | ||||||
|  * @adev: amdgpu_device pointer | }; | ||||||
|  * @gtt_size: maximum size of GTT |  | ||||||
|  * |  | ||||||
|  * Allocate and initialize the GTT manager. |  | ||||||
|  */ |  | ||||||
| int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) |  | ||||||
| { |  | ||||||
| 	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; |  | ||||||
| 	struct ttm_resource_manager *man = &mgr->manager; |  | ||||||
| 	uint64_t start, size; |  | ||||||
| 	int ret; |  | ||||||
| 
 | 
 | ||||||
| 	man->use_tt = true; | const struct attribute_group amdgpu_gtt_mgr_attr_group = { | ||||||
| 	man->func = &amdgpu_gtt_mgr_func; | 	.attrs = amdgpu_gtt_mgr_attributes | ||||||
| 
 | }; | ||||||
| 	ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); |  | ||||||
| 
 |  | ||||||
| 	start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; |  | ||||||
| 	size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; |  | ||||||
| 	drm_mm_init(&mgr->mm, start, size); |  | ||||||
| 	spin_lock_init(&mgr->lock); |  | ||||||
| 	atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT); |  | ||||||
| 
 |  | ||||||
| 	ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_total); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_ERROR("Failed to create device file mem_info_gtt_total\n"); |  | ||||||
| 		return ret; |  | ||||||
| 	} |  | ||||||
| 	ret = device_create_file(adev->dev, &dev_attr_mem_info_gtt_used); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_ERROR("Failed to create device file mem_info_gtt_used\n"); |  | ||||||
| 		return ret; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager); |  | ||||||
| 	ttm_resource_manager_set_used(man, true); |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * amdgpu_gtt_mgr_fini - free and destroy GTT manager |  | ||||||
|  * |  | ||||||
|  * @adev: amdgpu_device pointer |  | ||||||
|  * |  | ||||||
|  * Destroy and free the GTT manager, returns -EBUSY if ranges are still |  | ||||||
|  * allocated inside it. |  | ||||||
|  */ |  | ||||||
| void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev) |  | ||||||
| { |  | ||||||
| 	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; |  | ||||||
| 	struct ttm_resource_manager *man = &mgr->manager; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	ttm_resource_manager_set_used(man, false); |  | ||||||
| 
 |  | ||||||
| 	ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man); |  | ||||||
| 	if (ret) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	spin_lock(&mgr->lock); |  | ||||||
| 	drm_mm_takedown(&mgr->mm); |  | ||||||
| 	spin_unlock(&mgr->lock); |  | ||||||
| 
 |  | ||||||
| 	device_remove_file(adev->dev, &dev_attr_mem_info_gtt_total); |  | ||||||
| 	device_remove_file(adev->dev, &dev_attr_mem_info_gtt_used); |  | ||||||
| 
 |  | ||||||
| 	ttm_resource_manager_cleanup(man); |  | ||||||
| 	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL); |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space |  * amdgpu_gtt_mgr_has_gart_addr - Check if mem has address space | ||||||
|  * |  * | ||||||
|  * @mem: the mem object to check |  * @res: the mem object to check | ||||||
|  * |  * | ||||||
|  * Check if a mem object has already address space allocated. |  * Check if a mem object has already address space allocated. | ||||||
|  */ |  */ | ||||||
| bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem) | bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res) | ||||||
| { | { | ||||||
| 	return mem->mm_node != NULL; | 	struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res); | ||||||
|  | 
 | ||||||
|  | 	return drm_mm_node_allocated(&node->base.mm_nodes[0]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -174,54 +125,57 @@ bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *mem) | |||||||
| static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, | static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, | ||||||
| 			      struct ttm_buffer_object *tbo, | 			      struct ttm_buffer_object *tbo, | ||||||
| 			      const struct ttm_place *place, | 			      const struct ttm_place *place, | ||||||
| 			      struct ttm_resource *mem) | 			      struct ttm_resource **res) | ||||||
| { | { | ||||||
| 	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | 	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | ||||||
|  | 	uint32_t num_pages = PFN_UP(tbo->base.size); | ||||||
| 	struct amdgpu_gtt_node *node; | 	struct amdgpu_gtt_node *node; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	spin_lock(&mgr->lock); | 	spin_lock(&mgr->lock); | ||||||
| 	if ((&tbo->mem == mem || tbo->mem.mem_type != TTM_PL_TT) && | 	if (tbo->resource && tbo->resource->mem_type != TTM_PL_TT && | ||||||
| 	    atomic64_read(&mgr->available) < mem->num_pages) { | 	    atomic64_read(&mgr->available) < num_pages) { | ||||||
| 		spin_unlock(&mgr->lock); | 		spin_unlock(&mgr->lock); | ||||||
| 		return -ENOSPC; | 		return -ENOSPC; | ||||||
| 	} | 	} | ||||||
| 	atomic64_sub(mem->num_pages, &mgr->available); | 	atomic64_sub(num_pages, &mgr->available); | ||||||
| 	spin_unlock(&mgr->lock); | 	spin_unlock(&mgr->lock); | ||||||
| 
 | 
 | ||||||
| 	if (!place->lpfn) { | 	node = kzalloc(struct_size(node, base.mm_nodes, 1), GFP_KERNEL); | ||||||
| 		mem->mm_node = NULL; |  | ||||||
| 		mem->start = AMDGPU_BO_INVALID_OFFSET; |  | ||||||
| 		return 0; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	node = kzalloc(sizeof(*node), GFP_KERNEL); |  | ||||||
| 	if (!node) { | 	if (!node) { | ||||||
| 		r = -ENOMEM; | 		r = -ENOMEM; | ||||||
| 		goto err_out; | 		goto err_out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	node->tbo = tbo; | 	node->tbo = tbo; | ||||||
|  | 	ttm_resource_init(tbo, place, &node->base.base); | ||||||
| 
 | 
 | ||||||
|  | 	if (place->lpfn) { | ||||||
| 		spin_lock(&mgr->lock); | 		spin_lock(&mgr->lock); | ||||||
| 	r = drm_mm_insert_node_in_range(&mgr->mm, &node->node, mem->num_pages, | 		r = drm_mm_insert_node_in_range(&mgr->mm, | ||||||
| 					mem->page_alignment, 0, place->fpfn, | 						&node->base.mm_nodes[0], | ||||||
| 					place->lpfn, DRM_MM_INSERT_BEST); | 						num_pages, tbo->page_alignment, | ||||||
|  | 						0, place->fpfn, place->lpfn, | ||||||
|  | 						DRM_MM_INSERT_BEST); | ||||||
| 		spin_unlock(&mgr->lock); | 		spin_unlock(&mgr->lock); | ||||||
| 
 |  | ||||||
| 		if (unlikely(r)) | 		if (unlikely(r)) | ||||||
| 			goto err_free; | 			goto err_free; | ||||||
| 
 | 
 | ||||||
| 	mem->mm_node = node; | 		node->base.base.start = node->base.mm_nodes[0].start; | ||||||
| 	mem->start = node->node.start; | 	} else { | ||||||
|  | 		node->base.mm_nodes[0].start = 0; | ||||||
|  | 		node->base.mm_nodes[0].size = node->base.base.num_pages; | ||||||
|  | 		node->base.base.start = AMDGPU_BO_INVALID_OFFSET; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	*res = &node->base.base; | ||||||
| 	return 0; | 	return 0; | ||||||
| 
 | 
 | ||||||
| err_free: | err_free: | ||||||
| 	kfree(node); | 	kfree(node); | ||||||
| 
 | 
 | ||||||
| err_out: | err_out: | ||||||
| 	atomic64_add(mem->num_pages, &mgr->available); | 	atomic64_add(num_pages, &mgr->available); | ||||||
| 
 | 
 | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| @ -235,19 +189,18 @@ err_out: | |||||||
|  * Free the allocated GTT again. |  * Free the allocated GTT again. | ||||||
|  */ |  */ | ||||||
| static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, | static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, | ||||||
| 			       struct ttm_resource *mem) | 			       struct ttm_resource *res) | ||||||
| { | { | ||||||
|  | 	struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res); | ||||||
| 	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | 	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | ||||||
| 	struct amdgpu_gtt_node *node = mem->mm_node; |  | ||||||
| 
 | 
 | ||||||
| 	if (node) { |  | ||||||
| 	spin_lock(&mgr->lock); | 	spin_lock(&mgr->lock); | ||||||
| 		drm_mm_remove_node(&node->node); | 	if (drm_mm_node_allocated(&node->base.mm_nodes[0])) | ||||||
|  | 		drm_mm_remove_node(&node->base.mm_nodes[0]); | ||||||
| 	spin_unlock(&mgr->lock); | 	spin_unlock(&mgr->lock); | ||||||
| 		kfree(node); | 	atomic64_add(res->num_pages, &mgr->available); | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	atomic64_add(mem->num_pages, &mgr->available); | 	kfree(node); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -265,22 +218,33 @@ uint64_t amdgpu_gtt_mgr_usage(struct ttm_resource_manager *man) | |||||||
| 	return (result > 0 ? result : 0) * PAGE_SIZE; | 	return (result > 0 ? result : 0) * PAGE_SIZE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_gtt_mgr_recover - re-init gart | ||||||
|  |  * | ||||||
|  |  * @man: TTM memory type manager | ||||||
|  |  * | ||||||
|  |  * Re-init the gart for each known BO in the GTT. | ||||||
|  |  */ | ||||||
| int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man) | int amdgpu_gtt_mgr_recover(struct ttm_resource_manager *man) | ||||||
| { | { | ||||||
| 	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | 	struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man); | ||||||
|  | 	struct amdgpu_device *adev; | ||||||
| 	struct amdgpu_gtt_node *node; | 	struct amdgpu_gtt_node *node; | ||||||
| 	struct drm_mm_node *mm_node; | 	struct drm_mm_node *mm_node; | ||||||
| 	int r = 0; | 	int r = 0; | ||||||
| 
 | 
 | ||||||
|  | 	adev = container_of(mgr, typeof(*adev), mman.gtt_mgr); | ||||||
| 	spin_lock(&mgr->lock); | 	spin_lock(&mgr->lock); | ||||||
| 	drm_mm_for_each_node(mm_node, &mgr->mm) { | 	drm_mm_for_each_node(mm_node, &mgr->mm) { | ||||||
| 		node = container_of(mm_node, struct amdgpu_gtt_node, node); | 		node = container_of(mm_node, typeof(*node), base.mm_nodes[0]); | ||||||
| 		r = amdgpu_ttm_recover_gart(node->tbo); | 		r = amdgpu_ttm_recover_gart(node->tbo); | ||||||
| 		if (r) | 		if (r) | ||||||
| 			break; | 			break; | ||||||
| 	} | 	} | ||||||
| 	spin_unlock(&mgr->lock); | 	spin_unlock(&mgr->lock); | ||||||
| 
 | 
 | ||||||
|  | 	amdgpu_gart_invalidate_tlb(adev); | ||||||
|  | 
 | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -311,3 +275,61 @@ static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = { | |||||||
| 	.free = amdgpu_gtt_mgr_del, | 	.free = amdgpu_gtt_mgr_del, | ||||||
| 	.debug = amdgpu_gtt_mgr_debug | 	.debug = amdgpu_gtt_mgr_debug | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_gtt_mgr_init - init GTT manager and DRM MM | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * @gtt_size: maximum size of GTT | ||||||
|  |  * | ||||||
|  |  * Allocate and initialize the GTT manager. | ||||||
|  |  */ | ||||||
|  | int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; | ||||||
|  | 	struct ttm_resource_manager *man = &mgr->manager; | ||||||
|  | 	uint64_t start, size; | ||||||
|  | 
 | ||||||
|  | 	man->use_tt = true; | ||||||
|  | 	man->func = &amdgpu_gtt_mgr_func; | ||||||
|  | 
 | ||||||
|  | 	ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); | ||||||
|  | 
 | ||||||
|  | 	start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; | ||||||
|  | 	size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; | ||||||
|  | 	drm_mm_init(&mgr->mm, start, size); | ||||||
|  | 	spin_lock_init(&mgr->lock); | ||||||
|  | 	atomic64_set(&mgr->available, gtt_size >> PAGE_SHIFT); | ||||||
|  | 
 | ||||||
|  | 	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, &mgr->manager); | ||||||
|  | 	ttm_resource_manager_set_used(man, true); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_gtt_mgr_fini - free and destroy GTT manager | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Destroy and free the GTT manager, returns -EBUSY if ranges are still | ||||||
|  |  * allocated inside it. | ||||||
|  |  */ | ||||||
|  | void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_gtt_mgr *mgr = &adev->mman.gtt_mgr; | ||||||
|  | 	struct ttm_resource_manager *man = &mgr->manager; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ttm_resource_manager_set_used(man, false); | ||||||
|  | 
 | ||||||
|  | 	ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man); | ||||||
|  | 	if (ret) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	spin_lock(&mgr->lock); | ||||||
|  | 	drm_mm_takedown(&mgr->mm); | ||||||
|  | 	spin_unlock(&mgr->lock); | ||||||
|  | 
 | ||||||
|  | 	ttm_resource_manager_cleanup(man); | ||||||
|  | 	ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_TT, NULL); | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										69
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_hdp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_hdp.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | /*
 | ||||||
|  |  * Copyright 2021 Advanced Micro Devices, Inc. | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  |  * copy of this software and associated documentation files (the "Software"), | ||||||
|  |  * to deal in the Software without restriction, including without limitation | ||||||
|  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  |  * and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  |  * Software is furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||||
|  |  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||||
|  |  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||||
|  |  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  |  * OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "amdgpu.h" | ||||||
|  | #include "amdgpu_ras.h" | ||||||
|  | 
 | ||||||
|  | int amdgpu_hdp_ras_late_init(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	int r; | ||||||
|  | 	struct ras_ih_if ih_info = { | ||||||
|  | 		.cb = NULL, | ||||||
|  | 	}; | ||||||
|  | 	struct ras_fs_if fs_info = { | ||||||
|  | 		.sysfs_name = "hdp_err_count", | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	if (!adev->hdp.ras_if) { | ||||||
|  | 		adev->hdp.ras_if = kmalloc(sizeof(struct ras_common_if), GFP_KERNEL); | ||||||
|  | 		if (!adev->hdp.ras_if) | ||||||
|  | 			return -ENOMEM; | ||||||
|  | 		adev->hdp.ras_if->block = AMDGPU_RAS_BLOCK__HDP; | ||||||
|  | 		adev->hdp.ras_if->type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; | ||||||
|  | 		adev->hdp.ras_if->sub_block_index = 0; | ||||||
|  | 		strcpy(adev->hdp.ras_if->name, "hdp"); | ||||||
|  | 	} | ||||||
|  | 	ih_info.head = fs_info.head = *adev->hdp.ras_if; | ||||||
|  | 	r = amdgpu_ras_late_init(adev, adev->hdp.ras_if, | ||||||
|  | 				 &fs_info, &ih_info); | ||||||
|  | 	if (r || !amdgpu_ras_is_supported(adev, adev->hdp.ras_if->block)) { | ||||||
|  | 		kfree(adev->hdp.ras_if); | ||||||
|  | 		adev->hdp.ras_if = NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void amdgpu_hdp_ras_fini(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__HDP) && | ||||||
|  | 	    adev->hdp.ras_if) { | ||||||
|  | 		struct ras_common_if *ras_if = adev->hdp.ras_if; | ||||||
|  | 		struct ras_ih_if ih_info = { | ||||||
|  | 			.cb = NULL, | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 		amdgpu_ras_late_fini(adev, ras_if, &ih_info); | ||||||
|  | 		kfree(ras_if); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -23,18 +23,29 @@ | |||||||
| #ifndef __AMDGPU_HDP_H__ | #ifndef __AMDGPU_HDP_H__ | ||||||
| #define __AMDGPU_HDP_H__ | #define __AMDGPU_HDP_H__ | ||||||
| 
 | 
 | ||||||
|  | struct amdgpu_hdp_ras_funcs { | ||||||
|  | 	int (*ras_late_init)(struct amdgpu_device *adev); | ||||||
|  | 	void (*ras_fini)(struct amdgpu_device *adev); | ||||||
|  | 	void (*query_ras_error_count)(struct amdgpu_device *adev, | ||||||
|  | 				      void *ras_error_status); | ||||||
|  | 	void (*reset_ras_error_count)(struct amdgpu_device *adev); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct amdgpu_hdp_funcs { | struct amdgpu_hdp_funcs { | ||||||
| 	void (*flush_hdp)(struct amdgpu_device *adev, struct amdgpu_ring *ring); | 	void (*flush_hdp)(struct amdgpu_device *adev, struct amdgpu_ring *ring); | ||||||
| 	void (*invalidate_hdp)(struct amdgpu_device *adev, | 	void (*invalidate_hdp)(struct amdgpu_device *adev, | ||||||
| 			       struct amdgpu_ring *ring); | 			       struct amdgpu_ring *ring); | ||||||
| 	void (*reset_ras_error_count)(struct amdgpu_device *adev); |  | ||||||
| 	void (*update_clock_gating)(struct amdgpu_device *adev, bool enable); | 	void (*update_clock_gating)(struct amdgpu_device *adev, bool enable); | ||||||
| 	void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags); | 	void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags); | ||||||
| 	void (*init_registers)(struct amdgpu_device *adev); | 	void (*init_registers)(struct amdgpu_device *adev); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct amdgpu_hdp { | struct amdgpu_hdp { | ||||||
|  | 	struct ras_common_if			*ras_if; | ||||||
| 	const struct amdgpu_hdp_funcs		*funcs; | 	const struct amdgpu_hdp_funcs		*funcs; | ||||||
|  | 	const struct amdgpu_hdp_ras_funcs	*ras_funcs; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | int amdgpu_hdp_ras_late_init(struct amdgpu_device *adev); | ||||||
|  | void amdgpu_hdp_ras_fini(struct amdgpu_device *adev); | ||||||
| #endif /* __AMDGPU_HDP_H__ */ | #endif /* __AMDGPU_HDP_H__ */ | ||||||
|  | |||||||
| @ -130,7 +130,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, | |||||||
| 	struct amdgpu_device *adev = ring->adev; | 	struct amdgpu_device *adev = ring->adev; | ||||||
| 	struct amdgpu_ib *ib = &ibs[0]; | 	struct amdgpu_ib *ib = &ibs[0]; | ||||||
| 	struct dma_fence *tmp = NULL; | 	struct dma_fence *tmp = NULL; | ||||||
| 	bool skip_preamble, need_ctx_switch; | 	bool need_ctx_switch; | ||||||
| 	unsigned patch_offset = ~0; | 	unsigned patch_offset = ~0; | ||||||
| 	struct amdgpu_vm *vm; | 	struct amdgpu_vm *vm; | ||||||
| 	uint64_t fence_ctx; | 	uint64_t fence_ctx; | ||||||
| @ -214,20 +214,11 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, | |||||||
| 	if (job && ring->funcs->init_cond_exec) | 	if (job && ring->funcs->init_cond_exec) | ||||||
| 		patch_offset = amdgpu_ring_init_cond_exec(ring); | 		patch_offset = amdgpu_ring_init_cond_exec(ring); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_X86_64 | 	amdgpu_device_flush_hdp(adev, ring); | ||||||
| 	if (!(adev->flags & AMD_IS_APU)) |  | ||||||
| #endif |  | ||||||
| 	{ |  | ||||||
| 		if (ring->funcs->emit_hdp_flush) |  | ||||||
| 			amdgpu_ring_emit_hdp_flush(ring); |  | ||||||
| 		else |  | ||||||
| 			amdgpu_asic_flush_hdp(adev, ring); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if (need_ctx_switch) | 	if (need_ctx_switch) | ||||||
| 		status |= AMDGPU_HAVE_CTX_SWITCH; | 		status |= AMDGPU_HAVE_CTX_SWITCH; | ||||||
| 
 | 
 | ||||||
| 	skip_preamble = ring->current_ctx == fence_ctx; |  | ||||||
| 	if (job && ring->funcs->emit_cntxcntl) { | 	if (job && ring->funcs->emit_cntxcntl) { | ||||||
| 		status |= job->preamble_status; | 		status |= job->preamble_status; | ||||||
| 		status |= job->preemption_status; | 		status |= job->preemption_status; | ||||||
| @ -245,14 +236,6 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, | |||||||
| 	for (i = 0; i < num_ibs; ++i) { | 	for (i = 0; i < num_ibs; ++i) { | ||||||
| 		ib = &ibs[i]; | 		ib = &ibs[i]; | ||||||
| 
 | 
 | ||||||
| 		/* drop preamble IBs if we don't have a context switch */ |  | ||||||
| 		if ((ib->flags & AMDGPU_IB_FLAG_PREAMBLE) && |  | ||||||
| 		    skip_preamble && |  | ||||||
| 		    !(status & AMDGPU_PREAMBLE_IB_PRESENT_FIRST) && |  | ||||||
| 		    !amdgpu_mcbp && |  | ||||||
| 		    !amdgpu_sriov_vf(adev)) /* for SRIOV preemption, Preamble CE ib must be inserted anyway */ |  | ||||||
| 			continue; |  | ||||||
| 
 |  | ||||||
| 		if (job && ring->funcs->emit_frame_cntl) { | 		if (job && ring->funcs->emit_frame_cntl) { | ||||||
| 			if (secure != !!(ib->flags & AMDGPU_IB_FLAGS_SECURE)) { | 			if (secure != !!(ib->flags & AMDGPU_IB_FLAGS_SECURE)) { | ||||||
| 				amdgpu_ring_emit_frame_cntl(ring, false, secure); | 				amdgpu_ring_emit_frame_cntl(ring, false, secure); | ||||||
| @ -268,10 +251,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs, | |||||||
| 	if (job && ring->funcs->emit_frame_cntl) | 	if (job && ring->funcs->emit_frame_cntl) | ||||||
| 		amdgpu_ring_emit_frame_cntl(ring, false, secure); | 		amdgpu_ring_emit_frame_cntl(ring, false, secure); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_X86_64 | 	amdgpu_device_invalidate_hdp(adev, ring); | ||||||
| 	if (!(adev->flags & AMD_IS_APU)) |  | ||||||
| #endif |  | ||||||
| 		amdgpu_asic_invalidate_hdp(adev, ring); |  | ||||||
| 
 | 
 | ||||||
| 	if (ib->flags & AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE) | 	if (ib->flags & AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE) | ||||||
| 		fence_flags |= AMDGPU_FENCE_FLAG_TC_WB_ONLY; | 		fence_flags |= AMDGPU_FENCE_FLAG_TC_WB_ONLY; | ||||||
| @ -328,7 +308,7 @@ int amdgpu_ib_pool_init(struct amdgpu_device *adev) | |||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < AMDGPU_IB_POOL_MAX; i++) { | 	for (i = 0; i < AMDGPU_IB_POOL_MAX; i++) { | ||||||
| 		if (i == AMDGPU_IB_POOL_DIRECT) | 		if (i == AMDGPU_IB_POOL_DIRECT) | ||||||
| 			size = PAGE_SIZE * 2; | 			size = PAGE_SIZE * 6; | ||||||
| 		else | 		else | ||||||
| 			size = AMDGPU_IB_POOL_SIZE; | 			size = AMDGPU_IB_POOL_SIZE; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv, | |||||||
| 	unsigned count; | 	unsigned count; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	r = dma_resv_get_fences_rcu(resv, NULL, &count, &fences); | 	r = dma_resv_get_fences(resv, NULL, &count, &fences); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		goto fallback; | 		goto fallback; | ||||||
| 
 | 
 | ||||||
| @ -156,8 +156,7 @@ fallback: | |||||||
| 	/* Not enough memory for the delayed delete, as last resort
 | 	/* Not enough memory for the delayed delete, as last resort
 | ||||||
| 	 * block for all the fences to complete. | 	 * block for all the fences to complete. | ||||||
| 	 */ | 	 */ | ||||||
| 	dma_resv_wait_timeout_rcu(resv, true, false, | 	dma_resv_wait_timeout(resv, true, false, MAX_SCHEDULE_TIMEOUT); | ||||||
| 					    MAX_SCHEDULE_TIMEOUT); |  | ||||||
| 	amdgpu_pasid_free(pasid); | 	amdgpu_pasid_free(pasid); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -183,7 +182,7 @@ bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_vm_grab_idle - grab idle VMID |  * amdgpu_vmid_grab_idle - grab idle VMID | ||||||
|  * |  * | ||||||
|  * @vm: vm to allocate id for |  * @vm: vm to allocate id for | ||||||
|  * @ring: ring we want to submit job to |  * @ring: ring we want to submit job to | ||||||
| @ -256,7 +255,7 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_vm *vm, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_vm_grab_reserved - try to assign reserved VMID |  * amdgpu_vmid_grab_reserved - try to assign reserved VMID | ||||||
|  * |  * | ||||||
|  * @vm: vm to allocate id for |  * @vm: vm to allocate id for | ||||||
|  * @ring: ring we want to submit job to |  * @ring: ring we want to submit job to | ||||||
| @ -325,7 +324,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_vm_grab_used - try to reuse a VMID |  * amdgpu_vmid_grab_used - try to reuse a VMID | ||||||
|  * |  * | ||||||
|  * @vm: vm to allocate id for |  * @vm: vm to allocate id for | ||||||
|  * @ring: ring we want to submit job to |  * @ring: ring we want to submit job to | ||||||
| @ -397,7 +396,7 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_vm_grab_id - allocate the next free VMID |  * amdgpu_vmid_grab - allocate the next free VMID | ||||||
|  * |  * | ||||||
|  * @vm: vm to allocate id for |  * @vm: vm to allocate id for | ||||||
|  * @ring: ring we want to submit job to |  * @ring: ring we want to submit job to | ||||||
|  | |||||||
| @ -115,10 +115,12 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih, | |||||||
|  */ |  */ | ||||||
| void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih) | void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih) | ||||||
| { | { | ||||||
| 	if (ih->use_bus_addr) { | 
 | ||||||
| 	if (!ih->ring) | 	if (!ih->ring) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	if (ih->use_bus_addr) { | ||||||
|  | 
 | ||||||
| 		/* add 8 bytes for the rptr/wptr shadows and
 | 		/* add 8 bytes for the rptr/wptr shadows and
 | ||||||
| 		 * add them to the end of the ring allocation. | 		 * add them to the end of the ring allocation. | ||||||
| 		 */ | 		 */ | ||||||
| @ -175,7 +177,9 @@ static bool amdgpu_ih_has_checkpoint_processed(struct amdgpu_device *adev, | |||||||
| 		cur_rptr += ih->ptr_mask + 1; | 		cur_rptr += ih->ptr_mask + 1; | ||||||
| 	*prev_rptr = cur_rptr; | 	*prev_rptr = cur_rptr; | ||||||
| 
 | 
 | ||||||
| 	return cur_rptr >= checkpoint_wptr; | 	/* check ring is empty to workaround missing wptr overflow flag */ | ||||||
|  | 	return cur_rptr >= checkpoint_wptr || | ||||||
|  | 	       (cur_rptr & ih->ptr_mask) == amdgpu_ih_get_wptr(adev, ih); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | |||||||
| @ -49,6 +49,7 @@ | |||||||
| #include <drm/drm_irq.h> | #include <drm/drm_irq.h> | ||||||
| #include <drm/drm_vblank.h> | #include <drm/drm_vblank.h> | ||||||
| #include <drm/amdgpu_drm.h> | #include <drm/amdgpu_drm.h> | ||||||
|  | #include <drm/drm_drv.h> | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| #include "amdgpu_ih.h" | #include "amdgpu_ih.h" | ||||||
| #include "atom.h" | #include "atom.h" | ||||||
| @ -348,6 +349,25 @@ int amdgpu_irq_init(struct amdgpu_device *adev) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | void amdgpu_irq_fini_hw(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	if (adev->irq.installed) { | ||||||
|  | 		drm_irq_uninstall(&adev->ddev); | ||||||
|  | 		adev->irq.installed = false; | ||||||
|  | 		if (adev->irq.msi_enabled) | ||||||
|  | 			pci_free_irq_vectors(adev->pdev); | ||||||
|  | 
 | ||||||
|  | 		if (!amdgpu_device_has_dc_support(adev)) | ||||||
|  | 			flush_work(&adev->hotplug_work); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	amdgpu_ih_ring_fini(adev, &adev->irq.ih_soft); | ||||||
|  | 	amdgpu_ih_ring_fini(adev, &adev->irq.ih); | ||||||
|  | 	amdgpu_ih_ring_fini(adev, &adev->irq.ih1); | ||||||
|  | 	amdgpu_ih_ring_fini(adev, &adev->irq.ih2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_irq_fini - shut down interrupt handling |  * amdgpu_irq_fini - shut down interrupt handling | ||||||
|  * |  * | ||||||
| @ -357,19 +377,10 @@ int amdgpu_irq_init(struct amdgpu_device *adev) | |||||||
|  * functionality, shuts down vblank, hotplug and reset interrupt handling, |  * functionality, shuts down vblank, hotplug and reset interrupt handling, | ||||||
|  * turns off interrupts from all sources (all ASICs). |  * turns off interrupts from all sources (all ASICs). | ||||||
|  */ |  */ | ||||||
| void amdgpu_irq_fini(struct amdgpu_device *adev) | void amdgpu_irq_fini_sw(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	unsigned i, j; | 	unsigned i, j; | ||||||
| 
 | 
 | ||||||
| 	if (adev->irq.installed) { |  | ||||||
| 		drm_irq_uninstall(adev_to_drm(adev)); |  | ||||||
| 		adev->irq.installed = false; |  | ||||||
| 		if (adev->irq.msi_enabled) |  | ||||||
| 			pci_free_irq_vectors(adev->pdev); |  | ||||||
| 		if (!amdgpu_device_has_dc_support(adev)) |  | ||||||
| 			flush_work(&adev->hotplug_work); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) { | 	for (i = 0; i < AMDGPU_IRQ_CLIENTID_MAX; ++i) { | ||||||
| 		if (!adev->irq.client[i].sources) | 		if (!adev->irq.client[i].sources) | ||||||
| 			continue; | 			continue; | ||||||
|  | |||||||
| @ -103,7 +103,8 @@ void amdgpu_irq_disable_all(struct amdgpu_device *adev); | |||||||
| irqreturn_t amdgpu_irq_handler(int irq, void *arg); | irqreturn_t amdgpu_irq_handler(int irq, void *arg); | ||||||
| 
 | 
 | ||||||
| int amdgpu_irq_init(struct amdgpu_device *adev); | int amdgpu_irq_init(struct amdgpu_device *adev); | ||||||
| void amdgpu_irq_fini(struct amdgpu_device *adev); | void amdgpu_irq_fini_sw(struct amdgpu_device *adev); | ||||||
|  | void amdgpu_irq_fini_hw(struct amdgpu_device *adev); | ||||||
| int amdgpu_irq_add_id(struct amdgpu_device *adev, | int amdgpu_irq_add_id(struct amdgpu_device *adev, | ||||||
| 		      unsigned client_id, unsigned src_id, | 		      unsigned client_id, unsigned src_id, | ||||||
| 		      struct amdgpu_irq_src *source); | 		      struct amdgpu_irq_src *source); | ||||||
|  | |||||||
| @ -25,6 +25,8 @@ | |||||||
| #include <linux/wait.h> | #include <linux/wait.h> | ||||||
| #include <linux/sched.h> | #include <linux/sched.h> | ||||||
| 
 | 
 | ||||||
|  | #include <drm/drm_drv.h> | ||||||
|  | 
 | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| #include "amdgpu_trace.h" | #include "amdgpu_trace.h" | ||||||
| 
 | 
 | ||||||
| @ -34,6 +36,15 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) | |||||||
| 	struct amdgpu_job *job = to_amdgpu_job(s_job); | 	struct amdgpu_job *job = to_amdgpu_job(s_job); | ||||||
| 	struct amdgpu_task_info ti; | 	struct amdgpu_task_info ti; | ||||||
| 	struct amdgpu_device *adev = ring->adev; | 	struct amdgpu_device *adev = ring->adev; | ||||||
|  | 	int idx; | ||||||
|  | 
 | ||||||
|  | 	if (!drm_dev_enter(&adev->ddev, &idx)) { | ||||||
|  | 		DRM_INFO("%s - device unplugged skipping recovery on scheduler:%s", | ||||||
|  | 			 __func__, s_job->sched->name); | ||||||
|  | 
 | ||||||
|  | 		/* Effectively the job is aborted as the device is gone */ | ||||||
|  | 		return DRM_GPU_SCHED_STAT_ENODEV; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	memset(&ti, 0, sizeof(struct amdgpu_task_info)); | 	memset(&ti, 0, sizeof(struct amdgpu_task_info)); | ||||||
| 
 | 
 | ||||||
| @ -41,7 +52,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) | |||||||
| 	    amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) { | 	    amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) { | ||||||
| 		DRM_ERROR("ring %s timeout, but soft recovered\n", | 		DRM_ERROR("ring %s timeout, but soft recovered\n", | ||||||
| 			  s_job->sched->name); | 			  s_job->sched->name); | ||||||
| 		return DRM_GPU_SCHED_STAT_NOMINAL; | 		goto exit; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	amdgpu_vm_get_task_info(ring->adev, job->pasid, &ti); | 	amdgpu_vm_get_task_info(ring->adev, job->pasid, &ti); | ||||||
| @ -53,13 +64,15 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) | |||||||
| 
 | 
 | ||||||
| 	if (amdgpu_device_should_recover_gpu(ring->adev)) { | 	if (amdgpu_device_should_recover_gpu(ring->adev)) { | ||||||
| 		amdgpu_device_gpu_recover(ring->adev, job); | 		amdgpu_device_gpu_recover(ring->adev, job); | ||||||
| 		return DRM_GPU_SCHED_STAT_NOMINAL; |  | ||||||
| 	} else { | 	} else { | ||||||
| 		drm_sched_suspend_timeout(&ring->sched); | 		drm_sched_suspend_timeout(&ring->sched); | ||||||
| 		if (amdgpu_sriov_vf(adev)) | 		if (amdgpu_sriov_vf(adev)) | ||||||
| 			adev->virt.tdr_debug = true; | 			adev->virt.tdr_debug = true; | ||||||
| 		return DRM_GPU_SCHED_STAT_NOMINAL; |  | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | exit: | ||||||
|  | 	drm_dev_exit(idx); | ||||||
|  | 	return DRM_GPU_SCHED_STAT_NOMINAL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, | int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs, | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ | |||||||
| 
 | 
 | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| #include <drm/amdgpu_drm.h> | #include <drm/amdgpu_drm.h> | ||||||
|  | #include <drm/drm_drv.h> | ||||||
| #include "amdgpu_uvd.h" | #include "amdgpu_uvd.h" | ||||||
| #include "amdgpu_vce.h" | #include "amdgpu_vce.h" | ||||||
| #include "atom.h" | #include "atom.h" | ||||||
| @ -91,8 +92,11 @@ void amdgpu_driver_unload_kms(struct drm_device *dev) | |||||||
| 		pm_runtime_forbid(dev->dev); | 		pm_runtime_forbid(dev->dev); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DRV_UNLOAD)) | ||||||
|  | 		DRM_WARN("smart shift update failed\n"); | ||||||
|  | 
 | ||||||
| 	amdgpu_acpi_fini(adev); | 	amdgpu_acpi_fini(adev); | ||||||
| 	amdgpu_device_fini(adev); | 	amdgpu_device_fini_hw(adev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void amdgpu_register_gpu_instance(struct amdgpu_device *adev) | void amdgpu_register_gpu_instance(struct amdgpu_device *adev) | ||||||
| @ -120,6 +124,22 @@ void amdgpu_register_gpu_instance(struct amdgpu_device *adev) | |||||||
| 	mutex_unlock(&mgpu_info.mutex); | 	mutex_unlock(&mgpu_info.mutex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void amdgpu_get_audio_func(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	struct pci_dev *p = NULL; | ||||||
|  | 
 | ||||||
|  | 	p = pci_get_domain_bus_and_slot(pci_domain_nr(adev->pdev->bus), | ||||||
|  | 			adev->pdev->bus->number, 1); | ||||||
|  | 	if (p) { | ||||||
|  | 		pm_runtime_get_sync(&p->dev); | ||||||
|  | 
 | ||||||
|  | 		pm_runtime_mark_last_busy(&p->dev); | ||||||
|  | 		pm_runtime_put_autosuspend(&p->dev); | ||||||
|  | 
 | ||||||
|  | 		pci_dev_put(p); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_driver_load_kms - Main load function for KMS. |  * amdgpu_driver_load_kms - Main load function for KMS. | ||||||
|  * |  * | ||||||
| @ -209,11 +229,40 @@ int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags) | |||||||
| 						DPM_FLAG_MAY_SKIP_RESUME); | 						DPM_FLAG_MAY_SKIP_RESUME); | ||||||
| 		pm_runtime_use_autosuspend(dev->dev); | 		pm_runtime_use_autosuspend(dev->dev); | ||||||
| 		pm_runtime_set_autosuspend_delay(dev->dev, 5000); | 		pm_runtime_set_autosuspend_delay(dev->dev, 5000); | ||||||
|  | 
 | ||||||
| 		pm_runtime_allow(dev->dev); | 		pm_runtime_allow(dev->dev); | ||||||
|  | 
 | ||||||
| 		pm_runtime_mark_last_busy(dev->dev); | 		pm_runtime_mark_last_busy(dev->dev); | ||||||
| 		pm_runtime_put_autosuspend(dev->dev); | 		pm_runtime_put_autosuspend(dev->dev); | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * For runpm implemented via BACO, PMFW will handle the | ||||||
|  | 		 * timing for BACO in and out: | ||||||
|  | 		 *   - put ASIC into BACO state only when both video and | ||||||
|  | 		 *     audio functions are in D3 state. | ||||||
|  | 		 *   - pull ASIC out of BACO state when either video or | ||||||
|  | 		 *     audio function is in D0 state. | ||||||
|  | 		 * Also, at startup, PMFW assumes both functions are in | ||||||
|  | 		 * D0 state. | ||||||
|  | 		 * | ||||||
|  | 		 * So if snd driver was loaded prior to amdgpu driver | ||||||
|  | 		 * and audio function was put into D3 state, there will | ||||||
|  | 		 * be no PMFW-aware D-state transition(D0->D3) on runpm | ||||||
|  | 		 * suspend. Thus the BACO will be not correctly kicked in. | ||||||
|  | 		 * | ||||||
|  | 		 * Via amdgpu_get_audio_func(), the audio dev is put | ||||||
|  | 		 * into D0 state. Then there will be a PMFW-aware D-state | ||||||
|  | 		 * transition(D0->D3) on runpm suspend. | ||||||
|  | 		 */ | ||||||
|  | 		if (amdgpu_device_supports_baco(dev) && | ||||||
|  | 		    !(adev->flags & AMD_IS_APU) && | ||||||
|  | 		    (adev->asic_type >= CHIP_NAVI10)) | ||||||
|  | 			amdgpu_get_audio_func(adev); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DRV_LOAD)) | ||||||
|  | 		DRM_WARN("smart shift update failed\n"); | ||||||
|  | 
 | ||||||
| out: | out: | ||||||
| 	if (r) { | 	if (r) { | ||||||
| 		/* balance pm_runtime_get_sync in amdgpu_driver_unload_kms */ | 		/* balance pm_runtime_get_sync in amdgpu_driver_unload_kms */ | ||||||
| @ -861,6 +910,21 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||||||
| 					    min((size_t)size, (size_t)(bios_size - bios_offset))) | 					    min((size_t)size, (size_t)(bios_size - bios_offset))) | ||||||
| 					? -EFAULT : 0; | 					? -EFAULT : 0; | ||||||
| 		} | 		} | ||||||
|  | 		case AMDGPU_INFO_VBIOS_INFO: { | ||||||
|  | 			struct drm_amdgpu_info_vbios vbios_info = {}; | ||||||
|  | 			struct atom_context *atom_context; | ||||||
|  | 
 | ||||||
|  | 			atom_context = adev->mode_info.atom_context; | ||||||
|  | 			memcpy(vbios_info.name, atom_context->name, sizeof(atom_context->name)); | ||||||
|  | 			memcpy(vbios_info.vbios_pn, atom_context->vbios_pn, sizeof(atom_context->vbios_pn)); | ||||||
|  | 			vbios_info.version = atom_context->version; | ||||||
|  | 			memcpy(vbios_info.vbios_ver_str, atom_context->vbios_ver_str, | ||||||
|  | 						sizeof(atom_context->vbios_ver_str)); | ||||||
|  | 			memcpy(vbios_info.date, atom_context->date, sizeof(atom_context->date)); | ||||||
|  | 
 | ||||||
|  | 			return copy_to_user(out, &vbios_info, | ||||||
|  | 						min((size_t)size, sizeof(vbios_info))) ? -EFAULT : 0; | ||||||
|  | 		} | ||||||
| 		default: | 		default: | ||||||
| 			DRM_DEBUG_KMS("Invalid request %d\n", | 			DRM_DEBUG_KMS("Invalid request %d\n", | ||||||
| 					info->vbios_info.type); | 					info->vbios_info.type); | ||||||
| @ -986,7 +1050,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) | |||||||
| 
 | 
 | ||||||
| 		if (!ras) | 		if (!ras) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		ras_mask = (uint64_t)ras->supported << 32 | ras->features; | 		ras_mask = (uint64_t)adev->ras_enabled << 32 | ras->features; | ||||||
| 
 | 
 | ||||||
| 		return copy_to_user(out, &ras_mask, | 		return copy_to_user(out, &ras_mask, | ||||||
| 				min_t(u64, size, sizeof(ras_mask))) ? | 				min_t(u64, size, sizeof(ras_mask))) ? | ||||||
| @ -1114,7 +1178,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) | |||||||
| 		dev_warn(adev->dev, "No more PASIDs available!"); | 		dev_warn(adev->dev, "No more PASIDs available!"); | ||||||
| 		pasid = 0; | 		pasid = 0; | ||||||
| 	} | 	} | ||||||
| 	r = amdgpu_vm_init(adev, &fpriv->vm, AMDGPU_VM_CONTEXT_GFX, pasid); | 
 | ||||||
|  | 	r = amdgpu_vm_init(adev, &fpriv->vm, pasid); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		goto error_pasid; | 		goto error_pasid; | ||||||
| 
 | 
 | ||||||
| @ -1197,7 +1262,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pasid = fpriv->vm.pasid; | 	pasid = fpriv->vm.pasid; | ||||||
| 	pd = amdgpu_bo_ref(fpriv->vm.root.base.bo); | 	pd = amdgpu_bo_ref(fpriv->vm.root.bo); | ||||||
| 
 | 
 | ||||||
| 	amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr); | 	amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr); | ||||||
| 	amdgpu_vm_fini(adev, &fpriv->vm); | 	amdgpu_vm_fini(adev, &fpriv->vm); | ||||||
| @ -1219,6 +1284,15 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, | |||||||
| 	pm_runtime_put_autosuspend(dev->dev); | 	pm_runtime_put_autosuspend(dev->dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | void amdgpu_driver_release_kms(struct drm_device *dev) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_device *adev = drm_to_adev(dev); | ||||||
|  | 
 | ||||||
|  | 	amdgpu_device_fini_sw(adev); | ||||||
|  | 	pci_set_drvdata(adev->pdev, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * VBlank related functions. |  * VBlank related functions. | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ struct amdgpu_mmhub_ras_funcs { | |||||||
| 				      void *ras_error_status); | 				      void *ras_error_status); | ||||||
| 	void (*query_ras_error_status)(struct amdgpu_device *adev); | 	void (*query_ras_error_status)(struct amdgpu_device *adev); | ||||||
| 	void (*reset_ras_error_count)(struct amdgpu_device *adev); | 	void (*reset_ras_error_count)(struct amdgpu_device *adev); | ||||||
|  | 	void (*reset_ras_error_status)(struct amdgpu_device *adev); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct amdgpu_mmhub_funcs { | struct amdgpu_mmhub_funcs { | ||||||
|  | |||||||
| @ -75,7 +75,7 @@ static bool amdgpu_mn_invalidate_gfx(struct mmu_interval_notifier *mni, | |||||||
| 
 | 
 | ||||||
| 	mmu_interval_set_seq(mni, cur_seq); | 	mmu_interval_set_seq(mni, cur_seq); | ||||||
| 
 | 
 | ||||||
| 	r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false, | 	r = dma_resv_wait_timeout(bo->tbo.base.resv, true, false, | ||||||
| 				  MAX_SCHEDULE_TIMEOUT); | 				  MAX_SCHEDULE_TIMEOUT); | ||||||
| 	mutex_unlock(&adev->notifier_lock); | 	mutex_unlock(&adev->notifier_lock); | ||||||
| 	if (r <= 0) | 	if (r <= 0) | ||||||
| @ -155,3 +155,89 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo) | |||||||
| 	mmu_interval_notifier_remove(&bo->notifier); | 	mmu_interval_notifier_remove(&bo->notifier); | ||||||
| 	bo->notifier.mm = NULL; | 	bo->notifier.mm = NULL; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, | ||||||
|  | 			       struct mm_struct *mm, struct page **pages, | ||||||
|  | 			       uint64_t start, uint64_t npages, | ||||||
|  | 			       struct hmm_range **phmm_range, bool readonly, | ||||||
|  | 			       bool mmap_locked) | ||||||
|  | { | ||||||
|  | 	struct hmm_range *hmm_range; | ||||||
|  | 	unsigned long timeout; | ||||||
|  | 	unsigned long i; | ||||||
|  | 	unsigned long *pfns; | ||||||
|  | 	int r = 0; | ||||||
|  | 
 | ||||||
|  | 	hmm_range = kzalloc(sizeof(*hmm_range), GFP_KERNEL); | ||||||
|  | 	if (unlikely(!hmm_range)) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL); | ||||||
|  | 	if (unlikely(!pfns)) { | ||||||
|  | 		r = -ENOMEM; | ||||||
|  | 		goto out_free_range; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	hmm_range->notifier = notifier; | ||||||
|  | 	hmm_range->default_flags = HMM_PFN_REQ_FAULT; | ||||||
|  | 	if (!readonly) | ||||||
|  | 		hmm_range->default_flags |= HMM_PFN_REQ_WRITE; | ||||||
|  | 	hmm_range->hmm_pfns = pfns; | ||||||
|  | 	hmm_range->start = start; | ||||||
|  | 	hmm_range->end = start + npages * PAGE_SIZE; | ||||||
|  | 
 | ||||||
|  | 	/* Assuming 512MB takes maxmium 1 second to fault page address */ | ||||||
|  | 	timeout = max(npages >> 17, 1ULL) * HMM_RANGE_DEFAULT_TIMEOUT; | ||||||
|  | 	timeout = jiffies + msecs_to_jiffies(timeout); | ||||||
|  | 
 | ||||||
|  | retry: | ||||||
|  | 	hmm_range->notifier_seq = mmu_interval_read_begin(notifier); | ||||||
|  | 
 | ||||||
|  | 	if (likely(!mmap_locked)) | ||||||
|  | 		mmap_read_lock(mm); | ||||||
|  | 
 | ||||||
|  | 	r = hmm_range_fault(hmm_range); | ||||||
|  | 
 | ||||||
|  | 	if (likely(!mmap_locked)) | ||||||
|  | 		mmap_read_unlock(mm); | ||||||
|  | 	if (unlikely(r)) { | ||||||
|  | 		/*
 | ||||||
|  | 		 * FIXME: This timeout should encompass the retry from | ||||||
|  | 		 * mmu_interval_read_retry() as well. | ||||||
|  | 		 */ | ||||||
|  | 		if (r == -EBUSY && !time_after(jiffies, timeout)) | ||||||
|  | 			goto retry; | ||||||
|  | 		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; pages && i < npages; i++) | ||||||
|  | 		pages[i] = hmm_pfn_to_page(pfns[i]); | ||||||
|  | 
 | ||||||
|  | 	*phmm_range = hmm_range; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | 
 | ||||||
|  | out_free_pfns: | ||||||
|  | 	kvfree(pfns); | ||||||
|  | out_free_range: | ||||||
|  | 	kfree(hmm_range); | ||||||
|  | 
 | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range) | ||||||
|  | { | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	r = mmu_interval_read_retry(hmm_range->notifier, | ||||||
|  | 				    hmm_range->notifier_seq); | ||||||
|  | 	kvfree(hmm_range->hmm_pfns); | ||||||
|  | 	kfree(hmm_range); | ||||||
|  | 
 | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | |||||||
| @ -30,6 +30,13 @@ | |||||||
| #include <linux/workqueue.h> | #include <linux/workqueue.h> | ||||||
| #include <linux/interval_tree.h> | #include <linux/interval_tree.h> | ||||||
| 
 | 
 | ||||||
|  | int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, | ||||||
|  | 			       struct mm_struct *mm, struct page **pages, | ||||||
|  | 			       uint64_t start, uint64_t npages, | ||||||
|  | 			       struct hmm_range **phmm_range, bool readonly, | ||||||
|  | 			       bool mmap_locked); | ||||||
|  | int amdgpu_hmm_range_get_pages_done(struct hmm_range *hmm_range); | ||||||
|  | 
 | ||||||
| #if defined(CONFIG_HMM_MIRROR) | #if defined(CONFIG_HMM_MIRROR) | ||||||
| int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr); | int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr); | ||||||
| void amdgpu_mn_unregister(struct amdgpu_bo *bo); | void amdgpu_mn_unregister(struct amdgpu_bo *bo); | ||||||
|  | |||||||
| @ -344,7 +344,7 @@ struct amdgpu_mode_info { | |||||||
| 	/* pointer to fbdev info structure */ | 	/* pointer to fbdev info structure */ | ||||||
| 	struct amdgpu_fbdev *rfbdev; | 	struct amdgpu_fbdev *rfbdev; | ||||||
| 	/* firmware flags */ | 	/* firmware flags */ | ||||||
| 	u16 firmware_flags; | 	u32 firmware_flags; | ||||||
| 	/* pointer to backlight encoder */ | 	/* pointer to backlight encoder */ | ||||||
| 	struct amdgpu_encoder *bl_encoder; | 	struct amdgpu_encoder *bl_encoder; | ||||||
| 	u8 bl_level; /* saved backlight level */ | 	u8 bl_level; /* saved backlight level */ | ||||||
|  | |||||||
| @ -52,55 +52,44 @@ | |||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * amdgpu_bo_subtract_pin_size - Remove BO from pin_size accounting |  | ||||||
|  * |  | ||||||
|  * @bo: &amdgpu_bo buffer object |  | ||||||
|  * |  | ||||||
|  * This function is called when a BO stops being pinned, and updates the |  | ||||||
|  * &amdgpu_device pin_size values accordingly. |  | ||||||
|  */ |  | ||||||
| static void amdgpu_bo_subtract_pin_size(struct amdgpu_bo *bo) |  | ||||||
| { |  | ||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |  | ||||||
| 
 |  | ||||||
| 	if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { |  | ||||||
| 		atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); |  | ||||||
| 		atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), |  | ||||||
| 			     &adev->visible_pin_size); |  | ||||||
| 	} else if (bo->tbo.mem.mem_type == TTM_PL_TT) { |  | ||||||
| 		atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo) | static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo) | ||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); |  | ||||||
| 	struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); | 	struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); | ||||||
| 	struct amdgpu_bo_user *ubo; |  | ||||||
| 
 |  | ||||||
| 	if (bo->tbo.pin_count > 0) |  | ||||||
| 		amdgpu_bo_subtract_pin_size(bo); |  | ||||||
| 
 | 
 | ||||||
| 	amdgpu_bo_kunmap(bo); | 	amdgpu_bo_kunmap(bo); | ||||||
| 
 | 
 | ||||||
| 	if (bo->tbo.base.import_attach) | 	if (bo->tbo.base.import_attach) | ||||||
| 		drm_prime_gem_destroy(&bo->tbo.base, bo->tbo.sg); | 		drm_prime_gem_destroy(&bo->tbo.base, bo->tbo.sg); | ||||||
| 	drm_gem_object_release(&bo->tbo.base); | 	drm_gem_object_release(&bo->tbo.base); | ||||||
| 	/* in case amdgpu_device_recover_vram got NULL of bo->parent */ |  | ||||||
| 	if (!list_empty(&bo->shadow_list)) { |  | ||||||
| 		mutex_lock(&adev->shadow_list_lock); |  | ||||||
| 		list_del_init(&bo->shadow_list); |  | ||||||
| 		mutex_unlock(&adev->shadow_list_lock); |  | ||||||
| 	} |  | ||||||
| 	amdgpu_bo_unref(&bo->parent); | 	amdgpu_bo_unref(&bo->parent); | ||||||
|  | 	kvfree(bo); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void amdgpu_bo_user_destroy(struct ttm_buffer_object *tbo) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); | ||||||
|  | 	struct amdgpu_bo_user *ubo; | ||||||
| 
 | 
 | ||||||
| 	if (bo->tbo.type == ttm_bo_type_device) { |  | ||||||
| 	ubo = to_amdgpu_bo_user(bo); | 	ubo = to_amdgpu_bo_user(bo); | ||||||
| 	kfree(ubo->metadata); | 	kfree(ubo->metadata); | ||||||
|  | 	amdgpu_bo_destroy(tbo); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 	kvfree(bo); | static void amdgpu_bo_vm_destroy(struct ttm_buffer_object *tbo) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); | ||||||
|  | 	struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); | ||||||
|  | 	struct amdgpu_bo_vm *vmbo; | ||||||
|  | 
 | ||||||
|  | 	vmbo = to_amdgpu_bo_vm(bo); | ||||||
|  | 	/* in case amdgpu_device_recover_vram got NULL of bo->parent */ | ||||||
|  | 	if (!list_empty(&vmbo->shadow_list)) { | ||||||
|  | 		mutex_lock(&adev->shadow_list_lock); | ||||||
|  | 		list_del_init(&vmbo->shadow_list); | ||||||
|  | 		mutex_unlock(&adev->shadow_list_lock); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	amdgpu_bo_destroy(tbo); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -115,8 +104,11 @@ static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo) | |||||||
|  */ |  */ | ||||||
| bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) | bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) | ||||||
| { | { | ||||||
| 	if (bo->destroy == &amdgpu_bo_destroy) | 	if (bo->destroy == &amdgpu_bo_destroy || | ||||||
|  | 	    bo->destroy == &amdgpu_bo_user_destroy || | ||||||
|  | 	    bo->destroy == &amdgpu_bo_vm_destroy) | ||||||
| 		return true; | 		return true; | ||||||
|  | 
 | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -157,7 +149,9 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) | |||||||
| 	if (domain & AMDGPU_GEM_DOMAIN_GTT) { | 	if (domain & AMDGPU_GEM_DOMAIN_GTT) { | ||||||
| 		places[c].fpfn = 0; | 		places[c].fpfn = 0; | ||||||
| 		places[c].lpfn = 0; | 		places[c].lpfn = 0; | ||||||
| 		places[c].mem_type = TTM_PL_TT; | 		places[c].mem_type = | ||||||
|  | 			abo->flags & AMDGPU_GEM_CREATE_PREEMPTIBLE ? | ||||||
|  | 			AMDGPU_PL_PREEMPT : TTM_PL_TT; | ||||||
| 		places[c].flags = 0; | 		places[c].flags = 0; | ||||||
| 		c++; | 		c++; | ||||||
| 	} | 	} | ||||||
| @ -386,14 +380,14 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev, | |||||||
| 	if (cpu_addr) | 	if (cpu_addr) | ||||||
| 		amdgpu_bo_kunmap(*bo_ptr); | 		amdgpu_bo_kunmap(*bo_ptr); | ||||||
| 
 | 
 | ||||||
| 	ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.mem); | 	ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.resource); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) { | 	for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) { | ||||||
| 		(*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT; | 		(*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT; | ||||||
| 		(*bo_ptr)->placements[i].lpfn = (offset + size) >> PAGE_SHIFT; | 		(*bo_ptr)->placements[i].lpfn = (offset + size) >> PAGE_SHIFT; | ||||||
| 	} | 	} | ||||||
| 	r = ttm_bo_mem_space(&(*bo_ptr)->tbo, &(*bo_ptr)->placement, | 	r = ttm_bo_mem_space(&(*bo_ptr)->tbo, &(*bo_ptr)->placement, | ||||||
| 			     &(*bo_ptr)->tbo.mem, &ctx); | 			     &(*bo_ptr)->tbo.resource, &ctx); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		goto error; | 		goto error; | ||||||
| 
 | 
 | ||||||
| @ -515,7 +509,18 @@ bool amdgpu_bo_support_uswc(u64 bo_flags) | |||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int amdgpu_bo_do_create(struct amdgpu_device *adev, | /**
 | ||||||
|  |  * amdgpu_bo_create - create an &amdgpu_bo buffer object | ||||||
|  |  * @adev: amdgpu device object | ||||||
|  |  * @bp: parameters to be used for the buffer object | ||||||
|  |  * @bo_ptr: pointer to the buffer object pointer | ||||||
|  |  * | ||||||
|  |  * Creates an &amdgpu_bo buffer object. | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * 0 for success or a negative error code on failure. | ||||||
|  |  */ | ||||||
|  | int amdgpu_bo_create(struct amdgpu_device *adev, | ||||||
| 			       struct amdgpu_bo_param *bp, | 			       struct amdgpu_bo_param *bp, | ||||||
| 			       struct amdgpu_bo **bo_ptr) | 			       struct amdgpu_bo **bo_ptr) | ||||||
| { | { | ||||||
| @ -556,7 +561,6 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, | |||||||
| 	if (bo == NULL) | 	if (bo == NULL) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size); | 	drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size); | ||||||
| 	INIT_LIST_HEAD(&bo->shadow_list); |  | ||||||
| 	bo->vm_bo = NULL; | 	bo->vm_bo = NULL; | ||||||
| 	bo->preferred_domains = bp->preferred_domain ? bp->preferred_domain : | 	bo->preferred_domains = bp->preferred_domain ? bp->preferred_domain : | ||||||
| 		bp->domain; | 		bp->domain; | ||||||
| @ -579,22 +583,25 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev, | |||||||
| 	if (bp->type == ttm_bo_type_kernel) | 	if (bp->type == ttm_bo_type_kernel) | ||||||
| 		bo->tbo.priority = 1; | 		bo->tbo.priority = 1; | ||||||
| 
 | 
 | ||||||
|  | 	if (!bp->destroy) | ||||||
|  | 		bp->destroy = &amdgpu_bo_destroy; | ||||||
|  | 
 | ||||||
| 	r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type, | 	r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type, | ||||||
| 				 &bo->placement, page_align, &ctx,  NULL, | 				 &bo->placement, page_align, &ctx,  NULL, | ||||||
| 				 bp->resv, &amdgpu_bo_destroy); | 				 bp->resv, bp->destroy); | ||||||
| 	if (unlikely(r != 0)) | 	if (unlikely(r != 0)) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| 	if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && | 	if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && | ||||||
| 	    bo->tbo.mem.mem_type == TTM_PL_VRAM && | 	    bo->tbo.resource->mem_type == TTM_PL_VRAM && | ||||||
| 	    bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT) | 	    bo->tbo.resource->start < adev->gmc.visible_vram_size >> PAGE_SHIFT) | ||||||
| 		amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, | 		amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, | ||||||
| 					     ctx.bytes_moved); | 					     ctx.bytes_moved); | ||||||
| 	else | 	else | ||||||
| 		amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0); | 		amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0); | ||||||
| 
 | 
 | ||||||
| 	if (bp->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED && | 	if (bp->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED && | ||||||
| 	    bo->tbo.mem.mem_type == TTM_PL_VRAM) { | 	    bo->tbo.resource->mem_type == TTM_PL_VRAM) { | ||||||
| 		struct dma_fence *fence; | 		struct dma_fence *fence; | ||||||
| 
 | 
 | ||||||
| 		r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence); | 		r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence); | ||||||
| @ -625,80 +632,6 @@ fail_unreserve: | |||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, |  | ||||||
| 				   unsigned long size, |  | ||||||
| 				   struct amdgpu_bo *bo) |  | ||||||
| { |  | ||||||
| 	struct amdgpu_bo_param bp; |  | ||||||
| 	int r; |  | ||||||
| 
 |  | ||||||
| 	if (bo->shadow) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	memset(&bp, 0, sizeof(bp)); |  | ||||||
| 	bp.size = size; |  | ||||||
| 	bp.domain = AMDGPU_GEM_DOMAIN_GTT; |  | ||||||
| 	bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC | |  | ||||||
| 		AMDGPU_GEM_CREATE_SHADOW; |  | ||||||
| 	bp.type = ttm_bo_type_kernel; |  | ||||||
| 	bp.resv = bo->tbo.base.resv; |  | ||||||
| 	bp.bo_ptr_size = sizeof(struct amdgpu_bo); |  | ||||||
| 
 |  | ||||||
| 	r = amdgpu_bo_do_create(adev, &bp, &bo->shadow); |  | ||||||
| 	if (!r) { |  | ||||||
| 		bo->shadow->parent = amdgpu_bo_ref(bo); |  | ||||||
| 		mutex_lock(&adev->shadow_list_lock); |  | ||||||
| 		list_add_tail(&bo->shadow->shadow_list, &adev->shadow_list); |  | ||||||
| 		mutex_unlock(&adev->shadow_list_lock); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return r; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * amdgpu_bo_create - create an &amdgpu_bo buffer object |  | ||||||
|  * @adev: amdgpu device object |  | ||||||
|  * @bp: parameters to be used for the buffer object |  | ||||||
|  * @bo_ptr: pointer to the buffer object pointer |  | ||||||
|  * |  | ||||||
|  * Creates an &amdgpu_bo buffer object; and if requested, also creates a |  | ||||||
|  * shadow object. |  | ||||||
|  * Shadow object is used to backup the original buffer object, and is always |  | ||||||
|  * in GTT. |  | ||||||
|  * |  | ||||||
|  * Returns: |  | ||||||
|  * 0 for success or a negative error code on failure. |  | ||||||
|  */ |  | ||||||
| int amdgpu_bo_create(struct amdgpu_device *adev, |  | ||||||
| 		     struct amdgpu_bo_param *bp, |  | ||||||
| 		     struct amdgpu_bo **bo_ptr) |  | ||||||
| { |  | ||||||
| 	u64 flags = bp->flags; |  | ||||||
| 	int r; |  | ||||||
| 
 |  | ||||||
| 	bp->flags = bp->flags & ~AMDGPU_GEM_CREATE_SHADOW; |  | ||||||
| 
 |  | ||||||
| 	r = amdgpu_bo_do_create(adev, bp, bo_ptr); |  | ||||||
| 	if (r) |  | ||||||
| 		return r; |  | ||||||
| 
 |  | ||||||
| 	if ((flags & AMDGPU_GEM_CREATE_SHADOW) && !(adev->flags & AMD_IS_APU)) { |  | ||||||
| 		if (!bp->resv) |  | ||||||
| 			WARN_ON(dma_resv_lock((*bo_ptr)->tbo.base.resv, |  | ||||||
| 							NULL)); |  | ||||||
| 
 |  | ||||||
| 		r = amdgpu_bo_create_shadow(adev, bp->size, *bo_ptr); |  | ||||||
| 
 |  | ||||||
| 		if (!bp->resv) |  | ||||||
| 			dma_resv_unlock((*bo_ptr)->tbo.base.resv); |  | ||||||
| 
 |  | ||||||
| 		if (r) |  | ||||||
| 			amdgpu_bo_unref(bo_ptr); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return r; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_bo_create_user - create an &amdgpu_bo_user buffer object |  * amdgpu_bo_create_user - create an &amdgpu_bo_user buffer object | ||||||
|  * @adev: amdgpu device object |  * @adev: amdgpu device object | ||||||
| @ -718,15 +651,49 @@ int amdgpu_bo_create_user(struct amdgpu_device *adev, | |||||||
| 	struct amdgpu_bo *bo_ptr; | 	struct amdgpu_bo *bo_ptr; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	bp->flags = bp->flags & ~AMDGPU_GEM_CREATE_SHADOW; |  | ||||||
| 	bp->bo_ptr_size = sizeof(struct amdgpu_bo_user); | 	bp->bo_ptr_size = sizeof(struct amdgpu_bo_user); | ||||||
| 	r = amdgpu_bo_do_create(adev, bp, &bo_ptr); | 	bp->destroy = &amdgpu_bo_user_destroy; | ||||||
|  | 	r = amdgpu_bo_create(adev, bp, &bo_ptr); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| 	*ubo_ptr = to_amdgpu_bo_user(bo_ptr); | 	*ubo_ptr = to_amdgpu_bo_user(bo_ptr); | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_bo_create_vm - create an &amdgpu_bo_vm buffer object | ||||||
|  |  * @adev: amdgpu device object | ||||||
|  |  * @bp: parameters to be used for the buffer object | ||||||
|  |  * @vmbo_ptr: pointer to the buffer object pointer | ||||||
|  |  * | ||||||
|  |  * Create a BO to be for GPUVM. | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * 0 for success or a negative error code on failure. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | int amdgpu_bo_create_vm(struct amdgpu_device *adev, | ||||||
|  | 			struct amdgpu_bo_param *bp, | ||||||
|  | 			struct amdgpu_bo_vm **vmbo_ptr) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_bo *bo_ptr; | ||||||
|  | 	int r; | ||||||
|  | 
 | ||||||
|  | 	/* bo_ptr_size will be determined by the caller and it depends on
 | ||||||
|  | 	 * num of amdgpu_vm_pt entries. | ||||||
|  | 	 */ | ||||||
|  | 	BUG_ON(bp->bo_ptr_size < sizeof(struct amdgpu_bo_vm)); | ||||||
|  | 	bp->destroy = &amdgpu_bo_vm_destroy; | ||||||
|  | 	r = amdgpu_bo_create(adev, bp, &bo_ptr); | ||||||
|  | 	if (r) | ||||||
|  | 		return r; | ||||||
|  | 
 | ||||||
|  | 	*vmbo_ptr = to_amdgpu_bo_vm(bo_ptr); | ||||||
|  | 	INIT_LIST_HEAD(&(*vmbo_ptr)->shadow_list); | ||||||
|  | 	return r; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_bo_validate - validate an &amdgpu_bo buffer object |  * amdgpu_bo_validate - validate an &amdgpu_bo buffer object | ||||||
|  * @bo: pointer to the buffer object |  * @bo: pointer to the buffer object | ||||||
| @ -761,6 +728,22 @@ retry: | |||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_bo_add_to_shadow_list - add a BO to the shadow list | ||||||
|  |  * | ||||||
|  |  * @bo: BO that will be inserted into the shadow list | ||||||
|  |  * | ||||||
|  |  * Insert a BO to the shadow list. | ||||||
|  |  */ | ||||||
|  | void amdgpu_bo_add_to_shadow_list(struct amdgpu_bo_vm *vmbo) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_device *adev = amdgpu_ttm_adev(vmbo->bo.tbo.bdev); | ||||||
|  | 
 | ||||||
|  | 	mutex_lock(&adev->shadow_list_lock); | ||||||
|  | 	list_add_tail(&vmbo->shadow_list, &adev->shadow_list); | ||||||
|  | 	mutex_unlock(&adev->shadow_list_lock); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_bo_restore_shadow - restore an &amdgpu_bo shadow |  * amdgpu_bo_restore_shadow - restore an &amdgpu_bo shadow | ||||||
|  * |  * | ||||||
| @ -815,12 +798,12 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) | |||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, false, false, | 	r = dma_resv_wait_timeout(bo->tbo.base.resv, false, false, | ||||||
| 				  MAX_SCHEDULE_TIMEOUT); | 				  MAX_SCHEDULE_TIMEOUT); | ||||||
| 	if (r < 0) | 	if (r < 0) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| 	r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.mem.num_pages, &bo->kmap); | 	r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap); | ||||||
| 	if (r) | 	if (r) | ||||||
| 		return r; | 		return r; | ||||||
| 
 | 
 | ||||||
| @ -943,8 +926,8 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, | |||||||
| 	domain = amdgpu_bo_get_preferred_pin_domain(adev, domain); | 	domain = amdgpu_bo_get_preferred_pin_domain(adev, domain); | ||||||
| 
 | 
 | ||||||
| 	if (bo->tbo.pin_count) { | 	if (bo->tbo.pin_count) { | ||||||
| 		uint32_t mem_type = bo->tbo.mem.mem_type; | 		uint32_t mem_type = bo->tbo.resource->mem_type; | ||||||
| 		uint32_t mem_flags = bo->tbo.mem.placement; | 		uint32_t mem_flags = bo->tbo.resource->placement; | ||||||
| 
 | 
 | ||||||
| 		if (!(domain & amdgpu_mem_type_to_domain(mem_type))) | 		if (!(domain & amdgpu_mem_type_to_domain(mem_type))) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| @ -994,7 +977,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, | |||||||
| 
 | 
 | ||||||
| 	ttm_bo_pin(&bo->tbo); | 	ttm_bo_pin(&bo->tbo); | ||||||
| 
 | 
 | ||||||
| 	domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); | 	domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type); | ||||||
| 	if (domain == AMDGPU_GEM_DOMAIN_VRAM) { | 	if (domain == AMDGPU_GEM_DOMAIN_VRAM) { | ||||||
| 		atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size); | 		atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size); | ||||||
| 		atomic64_add(amdgpu_vram_mgr_bo_visible_size(bo), | 		atomic64_add(amdgpu_vram_mgr_bo_visible_size(bo), | ||||||
| @ -1037,14 +1020,22 @@ int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain) | |||||||
|  */ |  */ | ||||||
| void amdgpu_bo_unpin(struct amdgpu_bo *bo) | void amdgpu_bo_unpin(struct amdgpu_bo *bo) | ||||||
| { | { | ||||||
|  | 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | ||||||
|  | 
 | ||||||
| 	ttm_bo_unpin(&bo->tbo); | 	ttm_bo_unpin(&bo->tbo); | ||||||
| 	if (bo->tbo.pin_count) | 	if (bo->tbo.pin_count) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	amdgpu_bo_subtract_pin_size(bo); |  | ||||||
| 
 |  | ||||||
| 	if (bo->tbo.base.import_attach) | 	if (bo->tbo.base.import_attach) | ||||||
| 		dma_buf_unpin(bo->tbo.base.import_attach); | 		dma_buf_unpin(bo->tbo.base.import_attach); | ||||||
|  | 
 | ||||||
|  | 	if (bo->tbo.resource->mem_type == TTM_PL_VRAM) { | ||||||
|  | 		atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); | ||||||
|  | 		atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), | ||||||
|  | 			     &adev->visible_pin_size); | ||||||
|  | 	} else if (bo->tbo.resource->mem_type == TTM_PL_TT) { | ||||||
|  | 		atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -1123,10 +1114,6 @@ int amdgpu_bo_init(struct amdgpu_device *adev) | |||||||
| void amdgpu_bo_fini(struct amdgpu_device *adev) | void amdgpu_bo_fini(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	amdgpu_ttm_fini(adev); | 	amdgpu_ttm_fini(adev); | ||||||
| 	if (!adev->gmc.xgmi.connected_to_cpu) { |  | ||||||
| 		arch_phys_wc_del(adev->gmc.vram_mtrr); |  | ||||||
| 		arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -1246,6 +1233,9 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, | |||||||
| 
 | 
 | ||||||
| 	BUG_ON(bo->tbo.type == ttm_bo_type_kernel); | 	BUG_ON(bo->tbo.type == ttm_bo_type_kernel); | ||||||
| 	ubo = to_amdgpu_bo_user(bo); | 	ubo = to_amdgpu_bo_user(bo); | ||||||
|  | 	if (metadata_size) | ||||||
|  | 		*metadata_size = ubo->metadata_size; | ||||||
|  | 
 | ||||||
| 	if (buffer) { | 	if (buffer) { | ||||||
| 		if (buffer_size < ubo->metadata_size) | 		if (buffer_size < ubo->metadata_size) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| @ -1254,8 +1244,6 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, | |||||||
| 			memcpy(buffer, ubo->metadata, ubo->metadata_size); | 			memcpy(buffer, ubo->metadata, ubo->metadata_size); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (metadata_size) |  | ||||||
| 		*metadata_size = ubo->metadata_size; |  | ||||||
| 	if (flags) | 	if (flags) | ||||||
| 		*flags = ubo->metadata_flags; | 		*flags = ubo->metadata_flags; | ||||||
| 
 | 
 | ||||||
| @ -1278,7 +1266,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, | |||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); | 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); | ||||||
| 	struct amdgpu_bo *abo; | 	struct amdgpu_bo *abo; | ||||||
| 	struct ttm_resource *old_mem = &bo->mem; | 	struct ttm_resource *old_mem = bo->resource; | ||||||
| 
 | 
 | ||||||
| 	if (!amdgpu_bo_is_amdgpu_bo(bo)) | 	if (!amdgpu_bo_is_amdgpu_bo(bo)) | ||||||
| 		return; | 		return; | ||||||
| @ -1289,7 +1277,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, | |||||||
| 	amdgpu_bo_kunmap(abo); | 	amdgpu_bo_kunmap(abo); | ||||||
| 
 | 
 | ||||||
| 	if (abo->tbo.base.dma_buf && !abo->tbo.base.import_attach && | 	if (abo->tbo.base.dma_buf && !abo->tbo.base.import_attach && | ||||||
| 	    bo->mem.mem_type != TTM_PL_SYSTEM) | 	    bo->resource->mem_type != TTM_PL_SYSTEM) | ||||||
| 		dma_buf_move_notify(abo->tbo.base.dma_buf); | 		dma_buf_move_notify(abo->tbo.base.dma_buf); | ||||||
| 
 | 
 | ||||||
| 	/* remember the eviction */ | 	/* remember the eviction */ | ||||||
| @ -1304,6 +1292,26 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, | |||||||
| 	trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); | 	trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void amdgpu_bo_get_memory(struct amdgpu_bo *bo, uint64_t *vram_mem, | ||||||
|  | 				uint64_t *gtt_mem, uint64_t *cpu_mem) | ||||||
|  | { | ||||||
|  | 	unsigned int domain; | ||||||
|  | 
 | ||||||
|  | 	domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type); | ||||||
|  | 	switch (domain) { | ||||||
|  | 	case AMDGPU_GEM_DOMAIN_VRAM: | ||||||
|  | 		*vram_mem += amdgpu_bo_size(bo); | ||||||
|  | 		break; | ||||||
|  | 	case AMDGPU_GEM_DOMAIN_GTT: | ||||||
|  | 		*gtt_mem += amdgpu_bo_size(bo); | ||||||
|  | 		break; | ||||||
|  | 	case AMDGPU_GEM_DOMAIN_CPU: | ||||||
|  | 	default: | ||||||
|  | 		*cpu_mem += amdgpu_bo_size(bo); | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * amdgpu_bo_release_notify - notification about a BO being released |  * amdgpu_bo_release_notify - notification about a BO being released | ||||||
|  * @bo: pointer to a buffer object |  * @bo: pointer to a buffer object | ||||||
| @ -1331,7 +1339,7 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) | |||||||
| 	if (bo->base.resv == &bo->base._resv) | 	if (bo->base.resv == &bo->base._resv) | ||||||
| 		amdgpu_amdkfd_remove_fence_on_pt_pd_bos(abo); | 		amdgpu_amdkfd_remove_fence_on_pt_pd_bos(abo); | ||||||
| 
 | 
 | ||||||
| 	if (bo->mem.mem_type != TTM_PL_VRAM || !bo->mem.mm_node || | 	if (bo->resource->mem_type != TTM_PL_VRAM || | ||||||
| 	    !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) | 	    !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| @ -1362,18 +1370,17 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) | |||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); | 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); | ||||||
| 	struct ttm_operation_ctx ctx = { false, false }; | 	struct ttm_operation_ctx ctx = { false, false }; | ||||||
| 	struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); | 	struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); | ||||||
| 	unsigned long offset, size; | 	unsigned long offset; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	/* Remember that this BO was accessed by the CPU */ | 	/* Remember that this BO was accessed by the CPU */ | ||||||
| 	abo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; | 	abo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; | ||||||
| 
 | 
 | ||||||
| 	if (bo->mem.mem_type != TTM_PL_VRAM) | 	if (bo->resource->mem_type != TTM_PL_VRAM) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	size = bo->mem.num_pages << PAGE_SHIFT; | 	offset = bo->resource->start << PAGE_SHIFT; | ||||||
| 	offset = bo->mem.start << PAGE_SHIFT; | 	if ((offset + bo->base.size) <= adev->gmc.visible_vram_size) | ||||||
| 	if ((offset + size) <= adev->gmc.visible_vram_size) |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	/* Can't move a pinned BO to visible VRAM */ | 	/* Can't move a pinned BO to visible VRAM */ | ||||||
| @ -1395,10 +1402,10 @@ vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) | |||||||
| 	else if (unlikely(r)) | 	else if (unlikely(r)) | ||||||
| 		return VM_FAULT_SIGBUS; | 		return VM_FAULT_SIGBUS; | ||||||
| 
 | 
 | ||||||
| 	offset = bo->mem.start << PAGE_SHIFT; | 	offset = bo->resource->start << PAGE_SHIFT; | ||||||
| 	/* this should never happen */ | 	/* this should never happen */ | ||||||
| 	if (bo->mem.mem_type == TTM_PL_VRAM && | 	if (bo->resource->mem_type == TTM_PL_VRAM && | ||||||
| 	    (offset + size) > adev->gmc.visible_vram_size) | 	    (offset + bo->base.size) > adev->gmc.visible_vram_size) | ||||||
| 		return VM_FAULT_SIGBUS; | 		return VM_FAULT_SIGBUS; | ||||||
| 
 | 
 | ||||||
| 	ttm_bo_move_to_lru_tail_unlocked(bo); | 	ttm_bo_move_to_lru_tail_unlocked(bo); | ||||||
| @ -1482,11 +1489,11 @@ int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr) | |||||||
|  */ |  */ | ||||||
| u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) | u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) | ||||||
| { | { | ||||||
| 	WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM); | 	WARN_ON_ONCE(bo->tbo.resource->mem_type == TTM_PL_SYSTEM); | ||||||
| 	WARN_ON_ONCE(!dma_resv_is_locked(bo->tbo.base.resv) && | 	WARN_ON_ONCE(!dma_resv_is_locked(bo->tbo.base.resv) && | ||||||
| 		     !bo->tbo.pin_count && bo->tbo.type != ttm_bo_type_kernel); | 		     !bo->tbo.pin_count && bo->tbo.type != ttm_bo_type_kernel); | ||||||
| 	WARN_ON_ONCE(bo->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET); | 	WARN_ON_ONCE(bo->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET); | ||||||
| 	WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_VRAM && | 	WARN_ON_ONCE(bo->tbo.resource->mem_type == TTM_PL_VRAM && | ||||||
| 		     !(bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)); | 		     !(bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)); | ||||||
| 
 | 
 | ||||||
| 	return amdgpu_bo_gpu_offset_no_check(bo); | 	return amdgpu_bo_gpu_offset_no_check(bo); | ||||||
| @ -1504,8 +1511,8 @@ u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo) | |||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | ||||||
| 	uint64_t offset; | 	uint64_t offset; | ||||||
| 
 | 
 | ||||||
| 	offset = (bo->tbo.mem.start << PAGE_SHIFT) + | 	offset = (bo->tbo.resource->start << PAGE_SHIFT) + | ||||||
| 		 amdgpu_ttm_domain_start(adev, bo->tbo.mem.mem_type); | 		 amdgpu_ttm_domain_start(adev, bo->tbo.resource->mem_type); | ||||||
| 
 | 
 | ||||||
| 	return amdgpu_gmc_sign_extend(offset); | 	return amdgpu_gmc_sign_extend(offset); | ||||||
| } | } | ||||||
| @ -1558,7 +1565,7 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m) | |||||||
| 	unsigned int pin_count; | 	unsigned int pin_count; | ||||||
| 	u64 size; | 	u64 size; | ||||||
| 
 | 
 | ||||||
| 	domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); | 	domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type); | ||||||
| 	switch (domain) { | 	switch (domain) { | ||||||
| 	case AMDGPU_GEM_DOMAIN_VRAM: | 	case AMDGPU_GEM_DOMAIN_VRAM: | ||||||
| 		placement = "VRAM"; | 		placement = "VRAM"; | ||||||
| @ -1592,7 +1599,6 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m) | |||||||
| 	amdgpu_bo_print_flag(m, bo, NO_CPU_ACCESS); | 	amdgpu_bo_print_flag(m, bo, NO_CPU_ACCESS); | ||||||
| 	amdgpu_bo_print_flag(m, bo, CPU_GTT_USWC); | 	amdgpu_bo_print_flag(m, bo, CPU_GTT_USWC); | ||||||
| 	amdgpu_bo_print_flag(m, bo, VRAM_CLEARED); | 	amdgpu_bo_print_flag(m, bo, VRAM_CLEARED); | ||||||
| 	amdgpu_bo_print_flag(m, bo, SHADOW); |  | ||||||
| 	amdgpu_bo_print_flag(m, bo, VRAM_CONTIGUOUS); | 	amdgpu_bo_print_flag(m, bo, VRAM_CONTIGUOUS); | ||||||
| 	amdgpu_bo_print_flag(m, bo, VM_ALWAYS_VALID); | 	amdgpu_bo_print_flag(m, bo, VM_ALWAYS_VALID); | ||||||
| 	amdgpu_bo_print_flag(m, bo, EXPLICIT_SYNC); | 	amdgpu_bo_print_flag(m, bo, EXPLICIT_SYNC); | ||||||
|  | |||||||
| @ -30,6 +30,8 @@ | |||||||
| 
 | 
 | ||||||
| #include <drm/amdgpu_drm.h> | #include <drm/amdgpu_drm.h> | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
|  | #include "amdgpu_res_cursor.h" | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_MMU_NOTIFIER | #ifdef CONFIG_MMU_NOTIFIER | ||||||
| #include <linux/mmu_notifier.h> | #include <linux/mmu_notifier.h> | ||||||
| #endif | #endif | ||||||
| @ -37,7 +39,12 @@ | |||||||
| #define AMDGPU_BO_INVALID_OFFSET	LONG_MAX | #define AMDGPU_BO_INVALID_OFFSET	LONG_MAX | ||||||
| #define AMDGPU_BO_MAX_PLACEMENTS	3 | #define AMDGPU_BO_MAX_PLACEMENTS	3 | ||||||
| 
 | 
 | ||||||
|  | /* BO flag to indicate a KFD userptr BO */ | ||||||
|  | #define AMDGPU_AMDKFD_CREATE_USERPTR_BO	(1ULL << 63) | ||||||
|  | #define AMDGPU_AMDKFD_CREATE_SVM_BO	(1ULL << 62) | ||||||
|  | 
 | ||||||
| #define to_amdgpu_bo_user(abo) container_of((abo), struct amdgpu_bo_user, bo) | #define to_amdgpu_bo_user(abo) container_of((abo), struct amdgpu_bo_user, bo) | ||||||
|  | #define to_amdgpu_bo_vm(abo) container_of((abo), struct amdgpu_bo_vm, bo) | ||||||
| 
 | 
 | ||||||
| struct amdgpu_bo_param { | struct amdgpu_bo_param { | ||||||
| 	unsigned long			size; | 	unsigned long			size; | ||||||
| @ -49,6 +56,7 @@ struct amdgpu_bo_param { | |||||||
| 	enum ttm_bo_type		type; | 	enum ttm_bo_type		type; | ||||||
| 	bool				no_wait_gpu; | 	bool				no_wait_gpu; | ||||||
| 	struct dma_resv			*resv; | 	struct dma_resv			*resv; | ||||||
|  | 	void				(*destroy)(struct ttm_buffer_object *bo); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* bo virtual addresses in a vm */ | /* bo virtual addresses in a vm */ | ||||||
| @ -97,16 +105,10 @@ struct amdgpu_bo { | |||||||
| 	struct amdgpu_vm_bo_base	*vm_bo; | 	struct amdgpu_vm_bo_base	*vm_bo; | ||||||
| 	/* Constant after initialization */ | 	/* Constant after initialization */ | ||||||
| 	struct amdgpu_bo		*parent; | 	struct amdgpu_bo		*parent; | ||||||
| 	struct amdgpu_bo		*shadow; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_MMU_NOTIFIER | #ifdef CONFIG_MMU_NOTIFIER | ||||||
| 	struct mmu_interval_notifier	notifier; | 	struct mmu_interval_notifier	notifier; | ||||||
| #endif | #endif | ||||||
| 
 |  | ||||||
| 	struct list_head		shadow_list; |  | ||||||
| 
 |  | ||||||
| 	struct kgd_mem                  *kfd_bo; | 	struct kgd_mem                  *kfd_bo; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -119,6 +121,13 @@ struct amdgpu_bo_user { | |||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct amdgpu_bo_vm { | ||||||
|  | 	struct amdgpu_bo		bo; | ||||||
|  | 	struct amdgpu_bo		*shadow; | ||||||
|  | 	struct list_head		shadow_list; | ||||||
|  | 	struct amdgpu_vm_bo_base        entries[]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static inline struct amdgpu_bo *ttm_to_amdgpu_bo(struct ttm_buffer_object *tbo) | static inline struct amdgpu_bo *ttm_to_amdgpu_bo(struct ttm_buffer_object *tbo) | ||||||
| { | { | ||||||
| 	return container_of(tbo, struct amdgpu_bo, tbo); | 	return container_of(tbo, struct amdgpu_bo, tbo); | ||||||
| @ -191,7 +200,7 @@ static inline unsigned amdgpu_bo_ngpu_pages(struct amdgpu_bo *bo) | |||||||
| 
 | 
 | ||||||
| static inline unsigned amdgpu_bo_gpu_page_alignment(struct amdgpu_bo *bo) | static inline unsigned amdgpu_bo_gpu_page_alignment(struct amdgpu_bo *bo) | ||||||
| { | { | ||||||
| 	return (bo->tbo.mem.page_alignment << PAGE_SHIFT) / AMDGPU_GPU_PAGE_SIZE; | 	return (bo->tbo.page_alignment << PAGE_SHIFT) / AMDGPU_GPU_PAGE_SIZE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
| @ -211,18 +220,19 @@ static inline u64 amdgpu_bo_mmap_offset(struct amdgpu_bo *bo) | |||||||
| static inline bool amdgpu_bo_in_cpu_visible_vram(struct amdgpu_bo *bo) | static inline bool amdgpu_bo_in_cpu_visible_vram(struct amdgpu_bo *bo) | ||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | 	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); | ||||||
| 	unsigned fpfn = adev->gmc.visible_vram_size >> PAGE_SHIFT; | 	struct amdgpu_res_cursor cursor; | ||||||
| 	struct drm_mm_node *node = bo->tbo.mem.mm_node; |  | ||||||
| 	unsigned long pages_left; |  | ||||||
| 
 | 
 | ||||||
| 	if (bo->tbo.mem.mem_type != TTM_PL_VRAM) | 	if (bo->tbo.resource->mem_type != TTM_PL_VRAM) | ||||||
| 		return false; | 		return false; | ||||||
| 
 | 
 | ||||||
| 	for (pages_left = bo->tbo.mem.num_pages; pages_left; | 	amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor); | ||||||
| 	     pages_left -= node->size, node++) | 	while (cursor.remaining) { | ||||||
| 		if (node->start < fpfn) | 		if (cursor.start < adev->gmc.visible_vram_size) | ||||||
| 			return true; | 			return true; | ||||||
| 
 | 
 | ||||||
|  | 		amdgpu_res_next(&cursor, cursor.size); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -245,6 +255,22 @@ static inline bool amdgpu_bo_encrypted(struct amdgpu_bo *bo) | |||||||
| 	return bo->flags & AMDGPU_GEM_CREATE_ENCRYPTED; | 	return bo->flags & AMDGPU_GEM_CREATE_ENCRYPTED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_bo_shadowed - check if the BO is shadowed | ||||||
|  |  * | ||||||
|  |  * @bo: BO to be tested. | ||||||
|  |  * | ||||||
|  |  * Returns: | ||||||
|  |  * NULL if not shadowed or else return a BO pointer. | ||||||
|  |  */ | ||||||
|  | static inline struct amdgpu_bo *amdgpu_bo_shadowed(struct amdgpu_bo *bo) | ||||||
|  | { | ||||||
|  | 	if (bo->tbo.type == ttm_bo_type_kernel) | ||||||
|  | 		return to_amdgpu_bo_vm(bo)->shadow; | ||||||
|  | 
 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo); | bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo); | ||||||
| void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain); | void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain); | ||||||
| 
 | 
 | ||||||
| @ -265,6 +291,9 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev, | |||||||
| int amdgpu_bo_create_user(struct amdgpu_device *adev, | int amdgpu_bo_create_user(struct amdgpu_device *adev, | ||||||
| 			  struct amdgpu_bo_param *bp, | 			  struct amdgpu_bo_param *bp, | ||||||
| 			  struct amdgpu_bo_user **ubo_ptr); | 			  struct amdgpu_bo_user **ubo_ptr); | ||||||
|  | int amdgpu_bo_create_vm(struct amdgpu_device *adev, | ||||||
|  | 			struct amdgpu_bo_param *bp, | ||||||
|  | 			struct amdgpu_bo_vm **ubo_ptr); | ||||||
| void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr, | void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr, | ||||||
| 			   void **cpu_addr); | 			   void **cpu_addr); | ||||||
| int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr); | int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr); | ||||||
| @ -300,6 +329,9 @@ int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr); | |||||||
| u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo); | u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo); | ||||||
| u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo); | u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo); | ||||||
| int amdgpu_bo_validate(struct amdgpu_bo *bo); | int amdgpu_bo_validate(struct amdgpu_bo *bo); | ||||||
|  | void amdgpu_bo_get_memory(struct amdgpu_bo *bo, uint64_t *vram_mem, | ||||||
|  | 				uint64_t *gtt_mem, uint64_t *cpu_mem); | ||||||
|  | void amdgpu_bo_add_to_shadow_list(struct amdgpu_bo_vm *vmbo); | ||||||
| int amdgpu_bo_restore_shadow(struct amdgpu_bo *shadow, | int amdgpu_bo_restore_shadow(struct amdgpu_bo *shadow, | ||||||
| 			     struct dma_fence **fence); | 			     struct dma_fence **fence); | ||||||
| uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, | uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, | ||||||
|  | |||||||
							
								
								
									
										195
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,195 @@ | |||||||
|  | // SPDX-License-Identifier: GPL-2.0 OR MIT
 | ||||||
|  | /*
 | ||||||
|  |  * Copyright 2016-2021 Advanced Micro Devices, Inc. | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  |  * copy of this software and associated documentation files (the "Software"), | ||||||
|  |  * to deal in the Software without restriction, including without limitation | ||||||
|  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  |  * and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  |  * Software is furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in | ||||||
|  |  * all copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||||
|  |  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||||
|  |  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||||
|  |  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  |  * OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  * | ||||||
|  |  * Authors: Christian König, Felix Kuehling | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "amdgpu.h" | ||||||
|  | 
 | ||||||
|  | static inline struct amdgpu_preempt_mgr * | ||||||
|  | to_preempt_mgr(struct ttm_resource_manager *man) | ||||||
|  | { | ||||||
|  | 	return container_of(man, struct amdgpu_preempt_mgr, manager); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * DOC: mem_info_preempt_used | ||||||
|  |  * | ||||||
|  |  * The amdgpu driver provides a sysfs API for reporting current total amount of | ||||||
|  |  * used preemptible memory. | ||||||
|  |  * The file mem_info_preempt_used is used for this, and returns the current | ||||||
|  |  * used size of the preemptible block, in bytes | ||||||
|  |  */ | ||||||
|  | static ssize_t mem_info_preempt_used_show(struct device *dev, | ||||||
|  | 					  struct device_attribute *attr, | ||||||
|  | 					  char *buf) | ||||||
|  | { | ||||||
|  | 	struct drm_device *ddev = dev_get_drvdata(dev); | ||||||
|  | 	struct amdgpu_device *adev = drm_to_adev(ddev); | ||||||
|  | 	struct ttm_resource_manager *man; | ||||||
|  | 
 | ||||||
|  | 	man = ttm_manager_type(&adev->mman.bdev, AMDGPU_PL_PREEMPT); | ||||||
|  | 	return sysfs_emit(buf, "%llu\n", amdgpu_preempt_mgr_usage(man)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DEVICE_ATTR_RO(mem_info_preempt_used); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_preempt_mgr_new - allocate a new node | ||||||
|  |  * | ||||||
|  |  * @man: TTM memory type manager | ||||||
|  |  * @tbo: TTM BO we need this range for | ||||||
|  |  * @place: placement flags and restrictions | ||||||
|  |  * @mem: the resulting mem object | ||||||
|  |  * | ||||||
|  |  * Dummy, just count the space used without allocating resources or any limit. | ||||||
|  |  */ | ||||||
|  | static int amdgpu_preempt_mgr_new(struct ttm_resource_manager *man, | ||||||
|  | 				  struct ttm_buffer_object *tbo, | ||||||
|  | 				  const struct ttm_place *place, | ||||||
|  | 				  struct ttm_resource **res) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); | ||||||
|  | 
 | ||||||
|  | 	*res = kzalloc(sizeof(**res), GFP_KERNEL); | ||||||
|  | 	if (!*res) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	ttm_resource_init(tbo, place, *res); | ||||||
|  | 	(*res)->start = AMDGPU_BO_INVALID_OFFSET; | ||||||
|  | 
 | ||||||
|  | 	atomic64_add((*res)->num_pages, &mgr->used); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_preempt_mgr_del - free ranges | ||||||
|  |  * | ||||||
|  |  * @man: TTM memory type manager | ||||||
|  |  * @mem: TTM memory object | ||||||
|  |  * | ||||||
|  |  * Free the allocated GTT again. | ||||||
|  |  */ | ||||||
|  | static void amdgpu_preempt_mgr_del(struct ttm_resource_manager *man, | ||||||
|  | 				   struct ttm_resource *res) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); | ||||||
|  | 
 | ||||||
|  | 	atomic64_sub(res->num_pages, &mgr->used); | ||||||
|  | 	kfree(res); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_preempt_mgr_usage - return usage of PREEMPT domain | ||||||
|  |  * | ||||||
|  |  * @man: TTM memory type manager | ||||||
|  |  * | ||||||
|  |  * Return how many bytes are used in the GTT domain | ||||||
|  |  */ | ||||||
|  | uint64_t amdgpu_preempt_mgr_usage(struct ttm_resource_manager *man) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); | ||||||
|  | 	s64 result = atomic64_read(&mgr->used); | ||||||
|  | 
 | ||||||
|  | 	return (result > 0 ? result : 0) * PAGE_SIZE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_preempt_mgr_debug - dump VRAM table | ||||||
|  |  * | ||||||
|  |  * @man: TTM memory type manager | ||||||
|  |  * @printer: DRM printer to use | ||||||
|  |  * | ||||||
|  |  * Dump the table content using printk. | ||||||
|  |  */ | ||||||
|  | static void amdgpu_preempt_mgr_debug(struct ttm_resource_manager *man, | ||||||
|  | 				     struct drm_printer *printer) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); | ||||||
|  | 
 | ||||||
|  | 	drm_printf(printer, "man size:%llu pages, preempt used:%lld pages\n", | ||||||
|  | 		   man->size, (u64)atomic64_read(&mgr->used)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct ttm_resource_manager_func amdgpu_preempt_mgr_func = { | ||||||
|  | 	.alloc = amdgpu_preempt_mgr_new, | ||||||
|  | 	.free = amdgpu_preempt_mgr_del, | ||||||
|  | 	.debug = amdgpu_preempt_mgr_debug | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_preempt_mgr_init - init PREEMPT manager and DRM MM | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Allocate and initialize the GTT manager. | ||||||
|  |  */ | ||||||
|  | int amdgpu_preempt_mgr_init(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_preempt_mgr *mgr = &adev->mman.preempt_mgr; | ||||||
|  | 	struct ttm_resource_manager *man = &mgr->manager; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	man->use_tt = true; | ||||||
|  | 	man->func = &amdgpu_preempt_mgr_func; | ||||||
|  | 
 | ||||||
|  | 	ttm_resource_manager_init(man, (1 << 30)); | ||||||
|  | 
 | ||||||
|  | 	atomic64_set(&mgr->used, 0); | ||||||
|  | 
 | ||||||
|  | 	ret = device_create_file(adev->dev, &dev_attr_mem_info_preempt_used); | ||||||
|  | 	if (ret) { | ||||||
|  | 		DRM_ERROR("Failed to create device file mem_info_preempt_used\n"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ttm_set_driver_manager(&adev->mman.bdev, AMDGPU_PL_PREEMPT, | ||||||
|  | 			       &mgr->manager); | ||||||
|  | 	ttm_resource_manager_set_used(man, true); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * amdgpu_preempt_mgr_fini - free and destroy GTT manager | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * | ||||||
|  |  * Destroy and free the GTT manager, returns -EBUSY if ranges are still | ||||||
|  |  * allocated inside it. | ||||||
|  |  */ | ||||||
|  | void amdgpu_preempt_mgr_fini(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_preempt_mgr *mgr = &adev->mman.preempt_mgr; | ||||||
|  | 	struct ttm_resource_manager *man = &mgr->manager; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	ttm_resource_manager_set_used(man, false); | ||||||
|  | 
 | ||||||
|  | 	ret = ttm_resource_manager_evict_all(&adev->mman.bdev, man); | ||||||
|  | 	if (ret) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used); | ||||||
|  | 
 | ||||||
|  | 	ttm_resource_manager_cleanup(man); | ||||||
|  | 	ttm_set_driver_manager(&adev->mman.bdev, AMDGPU_PL_PREEMPT, NULL); | ||||||
|  | } | ||||||
| @ -25,6 +25,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <linux/firmware.h> | #include <linux/firmware.h> | ||||||
| #include <linux/dma-mapping.h> | #include <linux/dma-mapping.h> | ||||||
|  | #include <drm/drm_drv.h> | ||||||
| 
 | 
 | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| #include "amdgpu_psp.h" | #include "amdgpu_psp.h" | ||||||
| @ -38,6 +39,9 @@ | |||||||
| 
 | 
 | ||||||
| #include "amdgpu_ras.h" | #include "amdgpu_ras.h" | ||||||
| #include "amdgpu_securedisplay.h" | #include "amdgpu_securedisplay.h" | ||||||
|  | #include "amdgpu_atomfirmware.h" | ||||||
|  | 
 | ||||||
|  | #include <drm/drm_drv.h> | ||||||
| 
 | 
 | ||||||
| static int psp_sysfs_init(struct amdgpu_device *adev); | static int psp_sysfs_init(struct amdgpu_device *adev); | ||||||
| static void psp_sysfs_fini(struct amdgpu_device *adev); | static void psp_sysfs_fini(struct amdgpu_device *adev); | ||||||
| @ -104,6 +108,7 @@ static int psp_early_init(void *handle) | |||||||
| 	case CHIP_NAVY_FLOUNDER: | 	case CHIP_NAVY_FLOUNDER: | ||||||
| 	case CHIP_VANGOGH: | 	case CHIP_VANGOGH: | ||||||
| 	case CHIP_DIMGREY_CAVEFISH: | 	case CHIP_DIMGREY_CAVEFISH: | ||||||
|  | 	case CHIP_BEIGE_GOBY: | ||||||
| 		psp_v11_0_set_psp_funcs(psp); | 		psp_v11_0_set_psp_funcs(psp); | ||||||
| 		psp->autoload_supported = true; | 		psp->autoload_supported = true; | ||||||
| 		break; | 		break; | ||||||
| @ -113,6 +118,10 @@ static int psp_early_init(void *handle) | |||||||
| 	case CHIP_ALDEBARAN: | 	case CHIP_ALDEBARAN: | ||||||
| 		psp_v13_0_set_psp_funcs(psp); | 		psp_v13_0_set_psp_funcs(psp); | ||||||
| 		break; | 		break; | ||||||
|  | 	case CHIP_YELLOW_CARP: | ||||||
|  | 		psp_v13_0_set_psp_funcs(psp); | ||||||
|  | 		psp->autoload_supported = true; | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| @ -162,11 +171,81 @@ Err_out: | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Helper funciton to query psp runtime database entry | ||||||
|  |  * | ||||||
|  |  * @adev: amdgpu_device pointer | ||||||
|  |  * @entry_type: the type of psp runtime database entry | ||||||
|  |  * @db_entry: runtime database entry pointer | ||||||
|  |  * | ||||||
|  |  * Return false if runtime database doesn't exit or entry is invalid | ||||||
|  |  * or true if the specific database entry is found, and copy to @db_entry | ||||||
|  |  */ | ||||||
|  | static bool psp_get_runtime_db_entry(struct amdgpu_device *adev, | ||||||
|  | 				     enum psp_runtime_entry_type entry_type, | ||||||
|  | 				     void *db_entry) | ||||||
|  | { | ||||||
|  | 	uint64_t db_header_pos, db_dir_pos; | ||||||
|  | 	struct psp_runtime_data_header db_header = {0}; | ||||||
|  | 	struct psp_runtime_data_directory db_dir = {0}; | ||||||
|  | 	bool ret = false; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	db_header_pos = adev->gmc.mc_vram_size - PSP_RUNTIME_DB_OFFSET; | ||||||
|  | 	db_dir_pos = db_header_pos + sizeof(struct psp_runtime_data_header); | ||||||
|  | 
 | ||||||
|  | 	/* read runtime db header from vram */ | ||||||
|  | 	amdgpu_device_vram_access(adev, db_header_pos, (uint32_t *)&db_header, | ||||||
|  | 			sizeof(struct psp_runtime_data_header), false); | ||||||
|  | 
 | ||||||
|  | 	if (db_header.cookie != PSP_RUNTIME_DB_COOKIE_ID) { | ||||||
|  | 		/* runtime db doesn't exist, exit */ | ||||||
|  | 		dev_warn(adev->dev, "PSP runtime database doesn't exist\n"); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* read runtime database entry from vram */ | ||||||
|  | 	amdgpu_device_vram_access(adev, db_dir_pos, (uint32_t *)&db_dir, | ||||||
|  | 			sizeof(struct psp_runtime_data_directory), false); | ||||||
|  | 
 | ||||||
|  | 	if (db_dir.entry_count >= PSP_RUNTIME_DB_DIAG_ENTRY_MAX_COUNT) { | ||||||
|  | 		/* invalid db entry count, exit */ | ||||||
|  | 		dev_warn(adev->dev, "Invalid PSP runtime database entry count\n"); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* look up for requested entry type */ | ||||||
|  | 	for (i = 0; i < db_dir.entry_count && !ret; i++) { | ||||||
|  | 		if (db_dir.entry_list[i].entry_type == entry_type) { | ||||||
|  | 			switch (entry_type) { | ||||||
|  | 			case PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG: | ||||||
|  | 				if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_boot_cfg_entry)) { | ||||||
|  | 					/* invalid db entry size */ | ||||||
|  | 					dev_warn(adev->dev, "Invalid PSP runtime database entry size\n"); | ||||||
|  | 					return false; | ||||||
|  | 				} | ||||||
|  | 				/* read runtime database entry */ | ||||||
|  | 				amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset, | ||||||
|  | 							  (uint32_t *)db_entry, sizeof(struct psp_runtime_boot_cfg_entry), false); | ||||||
|  | 				ret = true; | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				ret = false; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int psp_sw_init(void *handle) | static int psp_sw_init(void *handle) | ||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 	struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||||||
| 	struct psp_context *psp = &adev->psp; | 	struct psp_context *psp = &adev->psp; | ||||||
| 	int ret; | 	int ret; | ||||||
|  | 	struct psp_runtime_boot_cfg_entry boot_cfg_entry; | ||||||
|  | 	struct psp_memory_training_context *mem_training_ctx = &psp->mem_train_ctx; | ||||||
| 
 | 
 | ||||||
| 	if (!amdgpu_sriov_vf(adev)) { | 	if (!amdgpu_sriov_vf(adev)) { | ||||||
| 		ret = psp_init_microcode(psp); | 		ret = psp_init_microcode(psp); | ||||||
| @ -174,18 +253,48 @@ static int psp_sw_init(void *handle) | |||||||
| 			DRM_ERROR("Failed to load psp firmware!\n"); | 			DRM_ERROR("Failed to load psp firmware!\n"); | ||||||
| 			return ret; | 			return ret; | ||||||
| 		} | 		} | ||||||
|  | 	} else if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_ALDEBARAN) { | ||||||
|  | 		ret = psp_init_ta_microcode(psp, "aldebaran"); | ||||||
|  | 		if (ret) { | ||||||
|  | 			DRM_ERROR("Failed to initialize ta microcode!\n"); | ||||||
|  | 			return ret; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	memset(&boot_cfg_entry, 0, sizeof(boot_cfg_entry)); | ||||||
|  | 	if (psp_get_runtime_db_entry(adev, | ||||||
|  | 				PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG, | ||||||
|  | 				&boot_cfg_entry)) { | ||||||
|  | 		psp->boot_cfg_bitmask = boot_cfg_entry.boot_cfg_bitmask; | ||||||
|  | 		if ((psp->boot_cfg_bitmask) & | ||||||
|  | 		    BOOT_CFG_FEATURE_TWO_STAGE_DRAM_TRAINING) { | ||||||
|  | 			/* If psp runtime database exists, then
 | ||||||
|  | 			 * only enable two stage memory training | ||||||
|  | 			 * when TWO_STAGE_DRAM_TRAINING bit is set | ||||||
|  | 			 * in runtime database */ | ||||||
|  | 			mem_training_ctx->enable_mem_training = true; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
|  | 		/* If psp runtime database doesn't exist or
 | ||||||
|  | 		 * is invalid, force enable two stage memory | ||||||
|  | 		 * training */ | ||||||
|  | 		mem_training_ctx->enable_mem_training = true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (mem_training_ctx->enable_mem_training) { | ||||||
| 		ret = psp_memory_training_init(psp); | 		ret = psp_memory_training_init(psp); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			DRM_ERROR("Failed to initialize memory training!\n"); | 			DRM_ERROR("Failed to initialize memory training!\n"); | ||||||
| 			return ret; | 			return ret; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT); | 		ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			DRM_ERROR("Failed to process memory training!\n"); | 			DRM_ERROR("Failed to process memory training!\n"); | ||||||
| 			return ret; | 			return ret; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_SIENNA_CICHLID) { | 	if (adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_SIENNA_CICHLID) { | ||||||
| 		ret= psp_sysfs_init(adev); | 		ret= psp_sysfs_init(adev); | ||||||
| @ -229,7 +338,7 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index, | |||||||
| 	int i; | 	int i; | ||||||
| 	struct amdgpu_device *adev = psp->adev; | 	struct amdgpu_device *adev = psp->adev; | ||||||
| 
 | 
 | ||||||
| 	if (psp->adev->in_pci_err_recovery) | 	if (psp->adev->no_hw_access) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < adev->usec_timeout; i++) { | 	for (i = 0; i < adev->usec_timeout; i++) { | ||||||
| @ -253,12 +362,15 @@ psp_cmd_submit_buf(struct psp_context *psp, | |||||||
| 		   struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr) | 		   struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
| 	int index; | 	int index, idx; | ||||||
| 	int timeout = 20000; | 	int timeout = 20000; | ||||||
| 	bool ras_intr = false; | 	bool ras_intr = false; | ||||||
| 	bool skip_unsupport = false; | 	bool skip_unsupport = false; | ||||||
| 
 | 
 | ||||||
| 	if (psp->adev->in_pci_err_recovery) | 	if (psp->adev->no_hw_access) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	if (!drm_dev_enter(&psp->adev->ddev, &idx)) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&psp->mutex); | 	mutex_lock(&psp->mutex); | ||||||
| @ -271,11 +383,10 @@ psp_cmd_submit_buf(struct psp_context *psp, | |||||||
| 	ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index); | 	ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		atomic_dec(&psp->fence_value); | 		atomic_dec(&psp->fence_value); | ||||||
| 		mutex_unlock(&psp->mutex); | 		goto exit; | ||||||
| 		return ret; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	amdgpu_asic_invalidate_hdp(psp->adev, NULL); | 	amdgpu_device_invalidate_hdp(psp->adev, NULL); | ||||||
| 	while (*((unsigned int *)psp->fence_buf) != index) { | 	while (*((unsigned int *)psp->fence_buf) != index) { | ||||||
| 		if (--timeout == 0) | 		if (--timeout == 0) | ||||||
| 			break; | 			break; | ||||||
| @ -288,7 +399,7 @@ psp_cmd_submit_buf(struct psp_context *psp, | |||||||
| 		if (ras_intr) | 		if (ras_intr) | ||||||
| 			break; | 			break; | ||||||
| 		usleep_range(10, 100); | 		usleep_range(10, 100); | ||||||
| 		amdgpu_asic_invalidate_hdp(psp->adev, NULL); | 		amdgpu_device_invalidate_hdp(psp->adev, NULL); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* We allow TEE_ERROR_NOT_SUPPORTED for VMR command and PSP_ERR_UNKNOWN_COMMAND in SRIOV */ | 	/* We allow TEE_ERROR_NOT_SUPPORTED for VMR command and PSP_ERR_UNKNOWN_COMMAND in SRIOV */ | ||||||
| @ -312,8 +423,8 @@ psp_cmd_submit_buf(struct psp_context *psp, | |||||||
| 			 psp->cmd_buf_mem->cmd_id, | 			 psp->cmd_buf_mem->cmd_id, | ||||||
| 			 psp->cmd_buf_mem->resp.status); | 			 psp->cmd_buf_mem->resp.status); | ||||||
| 		if (!timeout) { | 		if (!timeout) { | ||||||
| 			mutex_unlock(&psp->mutex); | 			ret = -EINVAL; | ||||||
| 			return -EINVAL; | 			goto exit; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -321,8 +432,10 @@ psp_cmd_submit_buf(struct psp_context *psp, | |||||||
| 		ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo; | 		ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo; | ||||||
| 		ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi; | 		ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi; | ||||||
| 	} | 	} | ||||||
| 	mutex_unlock(&psp->mutex); |  | ||||||
| 
 | 
 | ||||||
|  | exit: | ||||||
|  | 	mutex_unlock(&psp->mutex); | ||||||
|  | 	drm_dev_exit(idx); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -366,8 +479,7 @@ static int psp_load_toc(struct psp_context *psp, | |||||||
| 	if (!cmd) | 	if (!cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	/* Copy toc to psp firmware private buffer */ | 	/* Copy toc to psp firmware private buffer */ | ||||||
| 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | 	psp_copy_fw(psp, psp->toc_start_addr, psp->toc_bin_size); | ||||||
| 	memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size); |  | ||||||
| 
 | 
 | ||||||
| 	psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size); | 	psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc_bin_size); | ||||||
| 
 | 
 | ||||||
| @ -417,31 +529,12 @@ static int psp_tmr_init(struct psp_context *psp) | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int psp_clear_vf_fw(struct psp_context *psp) |  | ||||||
| { |  | ||||||
| 	int ret; |  | ||||||
| 	struct psp_gfx_cmd_resp *cmd; |  | ||||||
| 
 |  | ||||||
| 	if (!amdgpu_sriov_vf(psp->adev) || psp->adev->asic_type != CHIP_NAVI12) |  | ||||||
| 		return 0; |  | ||||||
| 
 |  | ||||||
| 	cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL); |  | ||||||
| 	if (!cmd) |  | ||||||
| 		return -ENOMEM; |  | ||||||
| 
 |  | ||||||
| 	cmd->cmd_id = GFX_CMD_ID_CLEAR_VF_FW; |  | ||||||
| 
 |  | ||||||
| 	ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); |  | ||||||
| 	kfree(cmd); |  | ||||||
| 
 |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool psp_skip_tmr(struct psp_context *psp) | static bool psp_skip_tmr(struct psp_context *psp) | ||||||
| { | { | ||||||
| 	switch (psp->adev->asic_type) { | 	switch (psp->adev->asic_type) { | ||||||
| 	case CHIP_NAVI12: | 	case CHIP_NAVI12: | ||||||
| 	case CHIP_SIENNA_CICHLID: | 	case CHIP_SIENNA_CICHLID: | ||||||
|  | 	case CHIP_ALDEBARAN: | ||||||
| 		return true; | 		return true; | ||||||
| 	default: | 	default: | ||||||
| 		return false; | 		return false; | ||||||
| @ -552,20 +645,43 @@ int psp_get_fw_attestation_records_addr(struct psp_context *psp, | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int psp_boot_config_set(struct amdgpu_device *adev) | static int psp_boot_config_get(struct amdgpu_device *adev, uint32_t *boot_cfg) | ||||||
|  | { | ||||||
|  | 	struct psp_context *psp = &adev->psp; | ||||||
|  | 	struct psp_gfx_cmd_resp *cmd = psp->cmd; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (amdgpu_sriov_vf(adev)) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); | ||||||
|  | 
 | ||||||
|  | 	cmd->cmd_id = GFX_CMD_ID_BOOT_CFG; | ||||||
|  | 	cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_GET; | ||||||
|  | 
 | ||||||
|  | 	ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); | ||||||
|  | 	if (!ret) { | ||||||
|  | 		*boot_cfg = | ||||||
|  | 			(cmd->resp.uresp.boot_cfg.boot_cfg & BOOT_CONFIG_GECC) ? 1 : 0; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int psp_boot_config_set(struct amdgpu_device *adev, uint32_t boot_cfg) | ||||||
| { | { | ||||||
| 	struct psp_context *psp = &adev->psp; | 	struct psp_context *psp = &adev->psp; | ||||||
| 	struct psp_gfx_cmd_resp *cmd = psp->cmd; | 	struct psp_gfx_cmd_resp *cmd = psp->cmd; | ||||||
| 
 | 
 | ||||||
| 	if (adev->asic_type != CHIP_SIENNA_CICHLID || amdgpu_sriov_vf(adev)) | 	if (amdgpu_sriov_vf(adev)) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); | 	memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp)); | ||||||
| 
 | 
 | ||||||
| 	cmd->cmd_id = GFX_CMD_ID_BOOT_CFG; | 	cmd->cmd_id = GFX_CMD_ID_BOOT_CFG; | ||||||
| 	cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_SET; | 	cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_SET; | ||||||
| 	cmd->cmd.boot_cfg.boot_config = BOOT_CONFIG_GECC; | 	cmd->cmd.boot_cfg.boot_config = boot_cfg; | ||||||
| 	cmd->cmd.boot_cfg.boot_config_valid = BOOT_CONFIG_GECC; | 	cmd->cmd.boot_cfg.boot_config_valid = boot_cfg; | ||||||
| 
 | 
 | ||||||
| 	return psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); | 	return psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); | ||||||
| } | } | ||||||
| @ -621,8 +737,7 @@ static int psp_asd_load(struct psp_context *psp) | |||||||
| 	if (!cmd) | 	if (!cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | 	psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size); | ||||||
| 	memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size); |  | ||||||
| 
 | 
 | ||||||
| 	psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr, | 	psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr, | ||||||
| 				  psp->asd_ucode_size); | 				  psp->asd_ucode_size); | ||||||
| @ -696,6 +811,8 @@ int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg, | |||||||
| 
 | 
 | ||||||
| 	psp_prep_reg_prog_cmd_buf(cmd, reg, value); | 	psp_prep_reg_prog_cmd_buf(cmd, reg, value); | ||||||
| 	ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); | 	ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); | ||||||
|  | 	if (ret) | ||||||
|  | 		DRM_ERROR("PSP failed to program reg id %d", reg); | ||||||
| 
 | 
 | ||||||
| 	kfree(cmd); | 	kfree(cmd); | ||||||
| 	return ret; | 	return ret; | ||||||
| @ -777,8 +894,7 @@ static int psp_xgmi_load(struct psp_context *psp) | |||||||
| 	if (!cmd) | 	if (!cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | 	psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size); | ||||||
| 	memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size); |  | ||||||
| 
 | 
 | ||||||
| 	psp_prep_ta_load_cmd_buf(cmd, | 	psp_prep_ta_load_cmd_buf(cmd, | ||||||
| 				 psp->fw_pri_mc_addr, | 				 psp->fw_pri_mc_addr, | ||||||
| @ -1034,8 +1150,14 @@ static int psp_ras_load(struct psp_context *psp) | |||||||
| 	if (!cmd) | 	if (!cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | 	psp_copy_fw(psp, psp->ta_ras_start_addr, psp->ta_ras_ucode_size); | ||||||
| 	memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size); | 
 | ||||||
|  | 	ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; | ||||||
|  | 
 | ||||||
|  | 	if (psp->adev->gmc.xgmi.connected_to_cpu) | ||||||
|  | 		ras_cmd->ras_in_message.init_flags.poison_mode_en = 1; | ||||||
|  | 	else | ||||||
|  | 		ras_cmd->ras_in_message.init_flags.dgpu_mode = 1; | ||||||
| 
 | 
 | ||||||
| 	psp_prep_ta_load_cmd_buf(cmd, | 	psp_prep_ta_load_cmd_buf(cmd, | ||||||
| 				 psp->fw_pri_mc_addr, | 				 psp->fw_pri_mc_addr, | ||||||
| @ -1046,8 +1168,6 @@ static int psp_ras_load(struct psp_context *psp) | |||||||
| 	ret = psp_cmd_submit_buf(psp, NULL, cmd, | 	ret = psp_cmd_submit_buf(psp, NULL, cmd, | ||||||
| 			psp->fence_buf_mc_addr); | 			psp->fence_buf_mc_addr); | ||||||
| 
 | 
 | ||||||
| 	ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf; |  | ||||||
| 
 |  | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		psp->ras.session_id = cmd->resp.session_id; | 		psp->ras.session_id = cmd->resp.session_id; | ||||||
| 
 | 
 | ||||||
| @ -1128,6 +1248,31 @@ int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id) | |||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int psp_ras_status_to_errno(struct amdgpu_device *adev, | ||||||
|  | 					 enum ta_ras_status ras_status) | ||||||
|  | { | ||||||
|  | 	int ret = -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	switch (ras_status) { | ||||||
|  | 	case TA_RAS_STATUS__SUCCESS: | ||||||
|  | 		ret = 0; | ||||||
|  | 		break; | ||||||
|  | 	case TA_RAS_STATUS__RESET_NEEDED: | ||||||
|  | 		ret = -EAGAIN; | ||||||
|  | 		break; | ||||||
|  | 	case TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE: | ||||||
|  | 		dev_warn(adev->dev, "RAS WARN: ras function unavailable\n"); | ||||||
|  | 		break; | ||||||
|  | 	case TA_RAS_STATUS__ERROR_ASD_READ_WRITE: | ||||||
|  | 		dev_warn(adev->dev, "RAS WARN: asd read or write failed\n"); | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		dev_err(adev->dev, "RAS ERROR: ras function failed ret 0x%X\n", ret); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int psp_ras_enable_features(struct psp_context *psp, | int psp_ras_enable_features(struct psp_context *psp, | ||||||
| 		union ta_ras_cmd_input *info, bool enable) | 		union ta_ras_cmd_input *info, bool enable) | ||||||
| { | { | ||||||
| @ -1151,7 +1296,7 @@ int psp_ras_enable_features(struct psp_context *psp, | |||||||
| 	if (ret) | 	if (ret) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	return ras_cmd->ras_status; | 	return psp_ras_status_to_errno(psp->adev, ras_cmd->ras_status); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int psp_ras_terminate(struct psp_context *psp) | static int psp_ras_terminate(struct psp_context *psp) | ||||||
| @ -1184,19 +1329,62 @@ static int psp_ras_terminate(struct psp_context *psp) | |||||||
| static int psp_ras_initialize(struct psp_context *psp) | static int psp_ras_initialize(struct psp_context *psp) | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
|  | 	uint32_t boot_cfg = 0xFF; | ||||||
|  | 	struct amdgpu_device *adev = psp->adev; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * TODO: bypass the initialize in sriov for now | 	 * TODO: bypass the initialize in sriov for now | ||||||
| 	 */ | 	 */ | ||||||
| 	if (amdgpu_sriov_vf(psp->adev)) | 	if (amdgpu_sriov_vf(adev)) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	if (!psp->adev->psp.ta_ras_ucode_size || | 	if (!adev->psp.ta_ras_ucode_size || | ||||||
| 	    !psp->adev->psp.ta_ras_start_addr) { | 	    !adev->psp.ta_ras_start_addr) { | ||||||
| 		dev_info(psp->adev->dev, "RAS: optional ras ta ucode is not available\n"); | 		dev_info(adev->dev, "RAS: optional ras ta ucode is not available\n"); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (amdgpu_atomfirmware_dynamic_boot_config_supported(adev)) { | ||||||
|  | 		/* query GECC enablement status from boot config
 | ||||||
|  | 		 * boot_cfg: 1: GECC is enabled or 0: GECC is disabled | ||||||
|  | 		 */ | ||||||
|  | 		ret = psp_boot_config_get(adev, &boot_cfg); | ||||||
|  | 		if (ret) | ||||||
|  | 			dev_warn(adev->dev, "PSP get boot config failed\n"); | ||||||
|  | 
 | ||||||
|  | 		if (!amdgpu_ras_is_supported(psp->adev, AMDGPU_RAS_BLOCK__UMC)) { | ||||||
|  | 			if (!boot_cfg) { | ||||||
|  | 				dev_info(adev->dev, "GECC is disabled\n"); | ||||||
|  | 			} else { | ||||||
|  | 				/* disable GECC in next boot cycle if ras is
 | ||||||
|  | 				 * disabled by module parameter amdgpu_ras_enable | ||||||
|  | 				 * and/or amdgpu_ras_mask, or boot_config_get call | ||||||
|  | 				 * is failed | ||||||
|  | 				 */ | ||||||
|  | 				ret = psp_boot_config_set(adev, 0); | ||||||
|  | 				if (ret) | ||||||
|  | 					dev_warn(adev->dev, "PSP set boot config failed\n"); | ||||||
|  | 				else | ||||||
|  | 					dev_warn(adev->dev, "GECC will be disabled in next boot cycle " | ||||||
|  | 						 "if set amdgpu_ras_enable and/or amdgpu_ras_mask to 0x0\n"); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			if (1 == boot_cfg) { | ||||||
|  | 				dev_info(adev->dev, "GECC is enabled\n"); | ||||||
|  | 			} else { | ||||||
|  | 				/* enable GECC in next boot cycle if it is disabled
 | ||||||
|  | 				 * in boot config, or force enable GECC if failed to | ||||||
|  | 				 * get boot configuration | ||||||
|  | 				 */ | ||||||
|  | 				ret = psp_boot_config_set(adev, BOOT_CONFIG_GECC); | ||||||
|  | 				if (ret) | ||||||
|  | 					dev_warn(adev->dev, "PSP set boot config failed\n"); | ||||||
|  | 				else | ||||||
|  | 					dev_warn(adev->dev, "GECC will be enabled in next boot cycle\n"); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (!psp->ras.ras_initialized) { | 	if (!psp->ras.ras_initialized) { | ||||||
| 		ret = psp_ras_init_shared_buf(psp); | 		ret = psp_ras_init_shared_buf(psp); | ||||||
| 		if (ret) | 		if (ret) | ||||||
| @ -1234,7 +1422,7 @@ int psp_ras_trigger_error(struct psp_context *psp, | |||||||
| 	if (amdgpu_ras_intr_triggered()) | 	if (amdgpu_ras_intr_triggered()) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	return ras_cmd->ras_status; | 	return psp_ras_status_to_errno(psp->adev, ras_cmd->ras_status); | ||||||
| } | } | ||||||
| // ras end
 | // ras end
 | ||||||
| 
 | 
 | ||||||
| @ -1271,8 +1459,7 @@ static int psp_hdcp_load(struct psp_context *psp) | |||||||
| 	if (!cmd) | 	if (!cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | 	psp_copy_fw(psp, psp->ta_hdcp_start_addr, | ||||||
| 	memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr, |  | ||||||
| 		    psp->ta_hdcp_ucode_size); | 		    psp->ta_hdcp_ucode_size); | ||||||
| 
 | 
 | ||||||
| 	psp_prep_ta_load_cmd_buf(cmd, | 	psp_prep_ta_load_cmd_buf(cmd, | ||||||
| @ -1423,8 +1610,7 @@ static int psp_dtm_load(struct psp_context *psp) | |||||||
| 	if (!cmd) | 	if (!cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | 	psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size); | ||||||
| 	memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size); |  | ||||||
| 
 | 
 | ||||||
| 	psp_prep_ta_load_cmd_buf(cmd, | 	psp_prep_ta_load_cmd_buf(cmd, | ||||||
| 				 psp->fw_pri_mc_addr, | 				 psp->fw_pri_mc_addr, | ||||||
| @ -1569,8 +1755,7 @@ static int psp_rap_load(struct psp_context *psp) | |||||||
| 	if (!cmd) | 	if (!cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | 	psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size); | ||||||
| 	memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size); |  | ||||||
| 
 | 
 | ||||||
| 	psp_prep_ta_load_cmd_buf(cmd, | 	psp_prep_ta_load_cmd_buf(cmd, | ||||||
| 				 psp->fw_pri_mc_addr, | 				 psp->fw_pri_mc_addr, | ||||||
| @ -1920,17 +2105,6 @@ static int psp_hw_start(struct psp_context *psp) | |||||||
| 		return ret; | 		return ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = psp_clear_vf_fw(psp); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_ERROR("PSP clear vf fw!\n"); |  | ||||||
| 		return ret; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = psp_boot_config_set(adev); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_WARN("PSP set boot config@\n"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	ret = psp_tmr_init(psp); | 	ret = psp_tmr_init(psp); | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		DRM_ERROR("PSP tmr init failed!\n"); | 		DRM_ERROR("PSP tmr init failed!\n"); | ||||||
| @ -2166,12 +2340,9 @@ static int psp_load_smu_fw(struct psp_context *psp) | |||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	if ((amdgpu_in_reset(adev) && | 	if ((amdgpu_in_reset(adev) && | ||||||
| 	     ras && ras->supported && | 	     ras && adev->ras_enabled && | ||||||
| 	     (adev->asic_type == CHIP_ARCTURUS || | 	     (adev->asic_type == CHIP_ARCTURUS || | ||||||
| 	      adev->asic_type == CHIP_VEGA20)) || | 	      adev->asic_type == CHIP_VEGA20))) { | ||||||
| 	     (adev->in_runpm && |  | ||||||
| 	      adev->asic_type >= CHIP_NAVI10 && |  | ||||||
| 	      adev->asic_type <= CHIP_NAVI12)) { |  | ||||||
| 		ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD); | 		ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			DRM_WARN("Failed to set MP1 state prepare for reload\n"); | 			DRM_WARN("Failed to set MP1 state prepare for reload\n"); | ||||||
| @ -2311,11 +2482,20 @@ static int psp_load_fw(struct amdgpu_device *adev) | |||||||
| 	if (!psp->cmd) | 	if (!psp->cmd) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | 	if (amdgpu_sriov_vf(adev)) { | ||||||
|  | 		ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, | ||||||
|  | 						AMDGPU_GEM_DOMAIN_VRAM, | ||||||
|  | 						&psp->fw_pri_bo, | ||||||
|  | 						&psp->fw_pri_mc_addr, | ||||||
|  | 						&psp->fw_pri_buf); | ||||||
|  | 	} else { | ||||||
| 		ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, | 		ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, | ||||||
| 						AMDGPU_GEM_DOMAIN_GTT, | 						AMDGPU_GEM_DOMAIN_GTT, | ||||||
| 						&psp->fw_pri_bo, | 						&psp->fw_pri_bo, | ||||||
| 						&psp->fw_pri_mc_addr, | 						&psp->fw_pri_mc_addr, | ||||||
| 						&psp->fw_pri_buf); | 						&psp->fw_pri_buf); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto failed; | 		goto failed; | ||||||
| 
 | 
 | ||||||
| @ -2434,7 +2614,6 @@ static int psp_hw_fini(void *handle) | |||||||
| { | { | ||||||
| 	struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 	struct amdgpu_device *adev = (struct amdgpu_device *)handle; | ||||||
| 	struct psp_context *psp = &adev->psp; | 	struct psp_context *psp = &adev->psp; | ||||||
| 	int ret; |  | ||||||
| 
 | 
 | ||||||
| 	if (psp->adev->psp.ta_fw) { | 	if (psp->adev->psp.ta_fw) { | ||||||
| 		psp_ras_terminate(psp); | 		psp_ras_terminate(psp); | ||||||
| @ -2445,11 +2624,6 @@ static int psp_hw_fini(void *handle) | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	psp_asd_unload(psp); | 	psp_asd_unload(psp); | ||||||
| 	ret = psp_clear_vf_fw(psp); |  | ||||||
| 	if (ret) { |  | ||||||
| 		DRM_ERROR("PSP clear vf fw!\n"); |  | ||||||
| 		return ret; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	psp_tmr_terminate(psp); | 	psp_tmr_terminate(psp); | ||||||
| 	psp_ring_destroy(psp, PSP_RING_TYPE__KM); | 	psp_ring_destroy(psp, PSP_RING_TYPE__KM); | ||||||
| @ -2539,11 +2713,13 @@ static int psp_resume(void *handle) | |||||||
| 
 | 
 | ||||||
| 	DRM_INFO("PSP is resuming...\n"); | 	DRM_INFO("PSP is resuming...\n"); | ||||||
| 
 | 
 | ||||||
|  | 	if (psp->mem_train_ctx.enable_mem_training) { | ||||||
| 		ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME); | 		ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			DRM_ERROR("Failed to process memory training!\n"); | 			DRM_ERROR("Failed to process memory training!\n"); | ||||||
| 			return ret; | 			return ret; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&adev->firmware.mutex); | 	mutex_lock(&adev->firmware.mutex); | ||||||
| 
 | 
 | ||||||
| @ -2694,7 +2870,7 @@ int psp_ring_cmd_submit(struct psp_context *psp, | |||||||
| 	write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); | 	write_frame->fence_addr_hi = upper_32_bits(fence_mc_addr); | ||||||
| 	write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); | 	write_frame->fence_addr_lo = lower_32_bits(fence_mc_addr); | ||||||
| 	write_frame->fence_value = index; | 	write_frame->fence_value = index; | ||||||
| 	amdgpu_asic_flush_hdp(adev, NULL); | 	amdgpu_device_flush_hdp(adev, NULL); | ||||||
| 
 | 
 | ||||||
| 	/* Update the write Pointer in DWORDs */ | 	/* Update the write Pointer in DWORDs */ | ||||||
| 	psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; | 	psp_write_ptr_reg = (psp_write_ptr_reg + rb_frame_size_dw) % ring_size_dw; | ||||||
| @ -2726,7 +2902,7 @@ int psp_init_asd_microcode(struct psp_context *psp, | |||||||
| 
 | 
 | ||||||
| 	asd_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data; | 	asd_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.asd_fw->data; | ||||||
| 	adev->psp.asd_fw_version = le32_to_cpu(asd_hdr->header.ucode_version); | 	adev->psp.asd_fw_version = le32_to_cpu(asd_hdr->header.ucode_version); | ||||||
| 	adev->psp.asd_feature_version = le32_to_cpu(asd_hdr->ucode_feature_version); | 	adev->psp.asd_feature_version = le32_to_cpu(asd_hdr->sos.fw_version); | ||||||
| 	adev->psp.asd_ucode_size = le32_to_cpu(asd_hdr->header.ucode_size_bytes); | 	adev->psp.asd_ucode_size = le32_to_cpu(asd_hdr->header.ucode_size_bytes); | ||||||
| 	adev->psp.asd_start_addr = (uint8_t *)asd_hdr + | 	adev->psp.asd_start_addr = (uint8_t *)asd_hdr + | ||||||
| 				le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes); | 				le32_to_cpu(asd_hdr->header.ucode_array_offset_bytes); | ||||||
| @ -2762,7 +2938,7 @@ int psp_init_toc_microcode(struct psp_context *psp, | |||||||
| 
 | 
 | ||||||
| 	toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data; | 	toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data; | ||||||
| 	adev->psp.toc_fw_version = le32_to_cpu(toc_hdr->header.ucode_version); | 	adev->psp.toc_fw_version = le32_to_cpu(toc_hdr->header.ucode_version); | ||||||
| 	adev->psp.toc_feature_version = le32_to_cpu(toc_hdr->ucode_feature_version); | 	adev->psp.toc_feature_version = le32_to_cpu(toc_hdr->sos.fw_version); | ||||||
| 	adev->psp.toc_bin_size = le32_to_cpu(toc_hdr->header.ucode_size_bytes); | 	adev->psp.toc_bin_size = le32_to_cpu(toc_hdr->header.ucode_size_bytes); | ||||||
| 	adev->psp.toc_start_addr = (uint8_t *)toc_hdr + | 	adev->psp.toc_start_addr = (uint8_t *)toc_hdr + | ||||||
| 				le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes); | 				le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes); | ||||||
| @ -2774,6 +2950,50 @@ out: | |||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int psp_init_sos_base_fw(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	const struct psp_firmware_header_v1_0 *sos_hdr; | ||||||
|  | 	const struct psp_firmware_header_v1_3 *sos_hdr_v1_3; | ||||||
|  | 	uint8_t *ucode_array_start_addr; | ||||||
|  | 
 | ||||||
|  | 	sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; | ||||||
|  | 	ucode_array_start_addr = (uint8_t *)sos_hdr + | ||||||
|  | 		le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes); | ||||||
|  | 
 | ||||||
|  | 	if (adev->gmc.xgmi.connected_to_cpu || (adev->asic_type != CHIP_ALDEBARAN)) { | ||||||
|  | 		adev->psp.sos_fw_version = le32_to_cpu(sos_hdr->header.ucode_version); | ||||||
|  | 		adev->psp.sos_feature_version = le32_to_cpu(sos_hdr->sos.fw_version); | ||||||
|  | 
 | ||||||
|  | 		adev->psp.sys_bin_size = le32_to_cpu(sos_hdr->sos.offset_bytes); | ||||||
|  | 		adev->psp.sys_start_addr = ucode_array_start_addr; | ||||||
|  | 
 | ||||||
|  | 		adev->psp.sos_bin_size = le32_to_cpu(sos_hdr->sos.size_bytes); | ||||||
|  | 		adev->psp.sos_start_addr = ucode_array_start_addr + | ||||||
|  | 				le32_to_cpu(sos_hdr->sos.offset_bytes); | ||||||
|  | 	} else { | ||||||
|  | 		/* Load alternate PSP SOS FW */ | ||||||
|  | 		sos_hdr_v1_3 = (const struct psp_firmware_header_v1_3 *)adev->psp.sos_fw->data; | ||||||
|  | 
 | ||||||
|  | 		adev->psp.sos_fw_version = le32_to_cpu(sos_hdr_v1_3->sos_aux.fw_version); | ||||||
|  | 		adev->psp.sos_feature_version = le32_to_cpu(sos_hdr_v1_3->sos_aux.fw_version); | ||||||
|  | 
 | ||||||
|  | 		adev->psp.sys_bin_size = le32_to_cpu(sos_hdr_v1_3->sys_drv_aux.size_bytes); | ||||||
|  | 		adev->psp.sys_start_addr = ucode_array_start_addr + | ||||||
|  | 			le32_to_cpu(sos_hdr_v1_3->sys_drv_aux.offset_bytes); | ||||||
|  | 
 | ||||||
|  | 		adev->psp.sos_bin_size = le32_to_cpu(sos_hdr_v1_3->sos_aux.size_bytes); | ||||||
|  | 		adev->psp.sos_start_addr = ucode_array_start_addr + | ||||||
|  | 			le32_to_cpu(sos_hdr_v1_3->sos_aux.offset_bytes); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((adev->psp.sys_bin_size == 0) || (adev->psp.sos_bin_size == 0)) { | ||||||
|  | 		dev_warn(adev->dev, "PSP SOS FW not available"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int psp_init_sos_microcode(struct psp_context *psp, | int psp_init_sos_microcode(struct psp_context *psp, | ||||||
| 			   const char *chip_name) | 			   const char *chip_name) | ||||||
| { | { | ||||||
| @ -2784,6 +3004,7 @@ int psp_init_sos_microcode(struct psp_context *psp, | |||||||
| 	const struct psp_firmware_header_v1_2 *sos_hdr_v1_2; | 	const struct psp_firmware_header_v1_2 *sos_hdr_v1_2; | ||||||
| 	const struct psp_firmware_header_v1_3 *sos_hdr_v1_3; | 	const struct psp_firmware_header_v1_3 *sos_hdr_v1_3; | ||||||
| 	int err = 0; | 	int err = 0; | ||||||
|  | 	uint8_t *ucode_array_start_addr; | ||||||
| 
 | 
 | ||||||
| 	if (!chip_name) { | 	if (!chip_name) { | ||||||
| 		dev_err(adev->dev, "invalid chip name for sos microcode\n"); | 		dev_err(adev->dev, "invalid chip name for sos microcode\n"); | ||||||
| @ -2800,47 +3021,45 @@ int psp_init_sos_microcode(struct psp_context *psp, | |||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; | 	sos_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.sos_fw->data; | ||||||
|  | 	ucode_array_start_addr = (uint8_t *)sos_hdr + | ||||||
|  | 		le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes); | ||||||
| 	amdgpu_ucode_print_psp_hdr(&sos_hdr->header); | 	amdgpu_ucode_print_psp_hdr(&sos_hdr->header); | ||||||
| 
 | 
 | ||||||
| 	switch (sos_hdr->header.header_version_major) { | 	switch (sos_hdr->header.header_version_major) { | ||||||
| 	case 1: | 	case 1: | ||||||
| 		adev->psp.sos_fw_version = le32_to_cpu(sos_hdr->header.ucode_version); | 		err = psp_init_sos_base_fw(adev); | ||||||
| 		adev->psp.sos_feature_version = le32_to_cpu(sos_hdr->ucode_feature_version); | 		if (err) | ||||||
| 		adev->psp.sos_bin_size = le32_to_cpu(sos_hdr->sos_size_bytes); | 			goto out; | ||||||
| 		adev->psp.sys_bin_size = le32_to_cpu(sos_hdr->sos_offset_bytes); | 
 | ||||||
| 		adev->psp.sys_start_addr = (uint8_t *)sos_hdr + |  | ||||||
| 				le32_to_cpu(sos_hdr->header.ucode_array_offset_bytes); |  | ||||||
| 		adev->psp.sos_start_addr = (uint8_t *)adev->psp.sys_start_addr + |  | ||||||
| 				le32_to_cpu(sos_hdr->sos_offset_bytes); |  | ||||||
| 		if (sos_hdr->header.header_version_minor == 1) { | 		if (sos_hdr->header.header_version_minor == 1) { | ||||||
| 			sos_hdr_v1_1 = (const struct psp_firmware_header_v1_1 *)adev->psp.sos_fw->data; | 			sos_hdr_v1_1 = (const struct psp_firmware_header_v1_1 *)adev->psp.sos_fw->data; | ||||||
| 			adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_1->toc_size_bytes); | 			adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_1->toc.size_bytes); | ||||||
| 			adev->psp.toc_start_addr = (uint8_t *)adev->psp.sys_start_addr + | 			adev->psp.toc_start_addr = (uint8_t *)adev->psp.sys_start_addr + | ||||||
| 					le32_to_cpu(sos_hdr_v1_1->toc_offset_bytes); | 					le32_to_cpu(sos_hdr_v1_1->toc.offset_bytes); | ||||||
| 			adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_1->kdb_size_bytes); | 			adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_1->kdb.size_bytes); | ||||||
| 			adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + | 			adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + | ||||||
| 					le32_to_cpu(sos_hdr_v1_1->kdb_offset_bytes); | 					le32_to_cpu(sos_hdr_v1_1->kdb.offset_bytes); | ||||||
| 		} | 		} | ||||||
| 		if (sos_hdr->header.header_version_minor == 2) { | 		if (sos_hdr->header.header_version_minor == 2) { | ||||||
| 			sos_hdr_v1_2 = (const struct psp_firmware_header_v1_2 *)adev->psp.sos_fw->data; | 			sos_hdr_v1_2 = (const struct psp_firmware_header_v1_2 *)adev->psp.sos_fw->data; | ||||||
| 			adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_2->kdb_size_bytes); | 			adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_2->kdb.size_bytes); | ||||||
| 			adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + | 			adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + | ||||||
| 						    le32_to_cpu(sos_hdr_v1_2->kdb_offset_bytes); | 						    le32_to_cpu(sos_hdr_v1_2->kdb.offset_bytes); | ||||||
| 		} | 		} | ||||||
| 		if (sos_hdr->header.header_version_minor == 3) { | 		if (sos_hdr->header.header_version_minor == 3) { | ||||||
| 			sos_hdr_v1_3 = (const struct psp_firmware_header_v1_3 *)adev->psp.sos_fw->data; | 			sos_hdr_v1_3 = (const struct psp_firmware_header_v1_3 *)adev->psp.sos_fw->data; | ||||||
| 			adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_3->v1_1.toc_size_bytes); | 			adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_3->v1_1.toc.size_bytes); | ||||||
| 			adev->psp.toc_start_addr = (uint8_t *)adev->psp.sys_start_addr + | 			adev->psp.toc_start_addr = ucode_array_start_addr + | ||||||
| 				le32_to_cpu(sos_hdr_v1_3->v1_1.toc_offset_bytes); | 				le32_to_cpu(sos_hdr_v1_3->v1_1.toc.offset_bytes); | ||||||
| 			adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_3->v1_1.kdb_size_bytes); | 			adev->psp.kdb_bin_size = le32_to_cpu(sos_hdr_v1_3->v1_1.kdb.size_bytes); | ||||||
| 			adev->psp.kdb_start_addr = (uint8_t *)adev->psp.sys_start_addr + | 			adev->psp.kdb_start_addr = ucode_array_start_addr + | ||||||
| 				le32_to_cpu(sos_hdr_v1_3->v1_1.kdb_offset_bytes); | 				le32_to_cpu(sos_hdr_v1_3->v1_1.kdb.offset_bytes); | ||||||
| 			adev->psp.spl_bin_size = le32_to_cpu(sos_hdr_v1_3->spl_size_bytes); | 			adev->psp.spl_bin_size = le32_to_cpu(sos_hdr_v1_3->spl.size_bytes); | ||||||
| 			adev->psp.spl_start_addr = (uint8_t *)adev->psp.sys_start_addr + | 			adev->psp.spl_start_addr = ucode_array_start_addr + | ||||||
| 				le32_to_cpu(sos_hdr_v1_3->spl_offset_bytes); | 				le32_to_cpu(sos_hdr_v1_3->spl.offset_bytes); | ||||||
| 			adev->psp.rl_bin_size = le32_to_cpu(sos_hdr_v1_3->rl_size_bytes); | 			adev->psp.rl_bin_size = le32_to_cpu(sos_hdr_v1_3->rl.size_bytes); | ||||||
| 			adev->psp.rl_start_addr = (uint8_t *)adev->psp.sys_start_addr + | 			adev->psp.rl_start_addr = ucode_array_start_addr + | ||||||
| 				le32_to_cpu(sos_hdr_v1_3->rl_offset_bytes); | 				le32_to_cpu(sos_hdr_v1_3->rl.offset_bytes); | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	default: | 	default: | ||||||
| @ -3018,7 +3237,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, | |||||||
| 	struct amdgpu_device *adev = drm_to_adev(ddev); | 	struct amdgpu_device *adev = drm_to_adev(ddev); | ||||||
| 	void *cpu_addr; | 	void *cpu_addr; | ||||||
| 	dma_addr_t dma_addr; | 	dma_addr_t dma_addr; | ||||||
| 	int ret; | 	int ret, idx; | ||||||
| 	char fw_name[100]; | 	char fw_name[100]; | ||||||
| 	const struct firmware *usbc_pd_fw; | 	const struct firmware *usbc_pd_fw; | ||||||
| 
 | 
 | ||||||
| @ -3027,6 +3246,9 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, | |||||||
| 		return -EBUSY; | 		return -EBUSY; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (!drm_dev_enter(ddev, &idx)) | ||||||
|  | 		return -ENODEV; | ||||||
|  | 
 | ||||||
| 	snprintf(fw_name, sizeof(fw_name), "amdgpu/%s", buf); | 	snprintf(fw_name, sizeof(fw_name), "amdgpu/%s", buf); | ||||||
| 	ret = request_firmware(&usbc_pd_fw, fw_name, adev->dev); | 	ret = request_firmware(&usbc_pd_fw, fw_name, adev->dev); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| @ -3058,16 +3280,29 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev, | |||||||
| rel_buf: | rel_buf: | ||||||
| 	dma_free_coherent(adev->dev, usbc_pd_fw->size, cpu_addr, dma_addr); | 	dma_free_coherent(adev->dev, usbc_pd_fw->size, cpu_addr, dma_addr); | ||||||
| 	release_firmware(usbc_pd_fw); | 	release_firmware(usbc_pd_fw); | ||||||
| 
 |  | ||||||
| fail: | fail: | ||||||
| 	if (ret) { | 	if (ret) { | ||||||
| 		DRM_ERROR("Failed to load USBC PD FW, err = %d", ret); | 		DRM_ERROR("Failed to load USBC PD FW, err = %d", ret); | ||||||
| 		return ret; | 		count = ret; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	drm_dev_exit(idx); | ||||||
| 	return count; | 	return count; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size) | ||||||
|  | { | ||||||
|  | 	int idx; | ||||||
|  | 
 | ||||||
|  | 	if (!drm_dev_enter(&psp->adev->ddev, &idx)) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	memset(psp->fw_pri_buf, 0, PSP_1_MEG); | ||||||
|  | 	memcpy(psp->fw_pri_buf, start_addr, bin_size); | ||||||
|  | 
 | ||||||
|  | 	drm_dev_exit(idx); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR, | static DEVICE_ATTR(usbc_pd_fw, S_IRUGO | S_IWUSR, | ||||||
| 		   psp_usbc_pd_fw_sysfs_read, | 		   psp_usbc_pd_fw_sysfs_read, | ||||||
| 		   psp_usbc_pd_fw_sysfs_write); | 		   psp_usbc_pd_fw_sysfs_write); | ||||||
|  | |||||||
| @ -225,6 +225,61 @@ struct psp_memory_training_context { | |||||||
| 
 | 
 | ||||||
| 	enum psp_memory_training_init_flag init; | 	enum psp_memory_training_init_flag init; | ||||||
| 	u32 training_cnt; | 	u32 training_cnt; | ||||||
|  | 	bool enable_mem_training; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** PSP runtime DB **/ | ||||||
|  | #define PSP_RUNTIME_DB_SIZE_IN_BYTES		0x10000 | ||||||
|  | #define PSP_RUNTIME_DB_OFFSET			0x100000 | ||||||
|  | #define PSP_RUNTIME_DB_COOKIE_ID		0x0ed5 | ||||||
|  | #define PSP_RUNTIME_DB_VER_1			0x0100 | ||||||
|  | #define PSP_RUNTIME_DB_DIAG_ENTRY_MAX_COUNT	0x40 | ||||||
|  | 
 | ||||||
|  | enum psp_runtime_entry_type { | ||||||
|  | 	PSP_RUNTIME_ENTRY_TYPE_INVALID		= 0x0, | ||||||
|  | 	PSP_RUNTIME_ENTRY_TYPE_TEST		= 0x1, | ||||||
|  | 	PSP_RUNTIME_ENTRY_TYPE_MGPU_COMMON	= 0x2,  /* Common mGPU runtime data */ | ||||||
|  | 	PSP_RUNTIME_ENTRY_TYPE_MGPU_WAFL	= 0x3,  /* WAFL runtime data */ | ||||||
|  | 	PSP_RUNTIME_ENTRY_TYPE_MGPU_XGMI	= 0x4,  /* XGMI runtime data */ | ||||||
|  | 	PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG	= 0x5,  /* Boot Config runtime data */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* PSP runtime DB header */ | ||||||
|  | struct psp_runtime_data_header { | ||||||
|  | 	/* determine the existence of runtime db */ | ||||||
|  | 	uint16_t cookie; | ||||||
|  | 	/* version of runtime db */ | ||||||
|  | 	uint16_t version; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* PSP runtime DB entry */ | ||||||
|  | struct psp_runtime_entry { | ||||||
|  | 	/* type of runtime db entry */ | ||||||
|  | 	uint32_t entry_type; | ||||||
|  | 	/* offset of entry in bytes */ | ||||||
|  | 	uint16_t offset; | ||||||
|  | 	/* size of entry in bytes */ | ||||||
|  | 	uint16_t size; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* PSP runtime DB directory */ | ||||||
|  | struct psp_runtime_data_directory { | ||||||
|  | 	/* number of valid entries */ | ||||||
|  | 	uint16_t			entry_count; | ||||||
|  | 	/* db entries*/ | ||||||
|  | 	struct psp_runtime_entry	entry_list[PSP_RUNTIME_DB_DIAG_ENTRY_MAX_COUNT]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* PSP runtime DB boot config feature bitmask */ | ||||||
|  | enum psp_runtime_boot_cfg_feature { | ||||||
|  | 	BOOT_CFG_FEATURE_GECC                       = 0x1, | ||||||
|  | 	BOOT_CFG_FEATURE_TWO_STAGE_DRAM_TRAINING    = 0x2, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* PSP runtime DB boot config entry */ | ||||||
|  | struct psp_runtime_boot_cfg_entry { | ||||||
|  | 	uint32_t boot_cfg_bitmask; | ||||||
|  | 	uint32_t reserved; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct psp_context | struct psp_context | ||||||
| @ -325,6 +380,8 @@ struct psp_context | |||||||
| 	struct psp_securedisplay_context	securedisplay_context; | 	struct psp_securedisplay_context	securedisplay_context; | ||||||
| 	struct mutex			mutex; | 	struct mutex			mutex; | ||||||
| 	struct psp_memory_training_context mem_train_ctx; | 	struct psp_memory_training_context mem_train_ctx; | ||||||
|  | 
 | ||||||
|  | 	uint32_t			boot_cfg_bitmask; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct amdgpu_psp_funcs { | struct amdgpu_psp_funcs { | ||||||
| @ -424,4 +481,6 @@ int psp_get_fw_attestation_records_addr(struct psp_context *psp, | |||||||
| 
 | 
 | ||||||
| int psp_load_fw_list(struct psp_context *psp, | int psp_load_fw_list(struct psp_context *psp, | ||||||
| 		     struct amdgpu_firmware_info **ucode_list, int ucode_count); | 		     struct amdgpu_firmware_info **ucode_list, int ucode_count); | ||||||
|  | void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -27,12 +27,14 @@ | |||||||
| #include <linux/uaccess.h> | #include <linux/uaccess.h> | ||||||
| #include <linux/reboot.h> | #include <linux/reboot.h> | ||||||
| #include <linux/syscalls.h> | #include <linux/syscalls.h> | ||||||
|  | #include <linux/pm_runtime.h> | ||||||
| 
 | 
 | ||||||
| #include "amdgpu.h" | #include "amdgpu.h" | ||||||
| #include "amdgpu_ras.h" | #include "amdgpu_ras.h" | ||||||
| #include "amdgpu_atomfirmware.h" | #include "amdgpu_atomfirmware.h" | ||||||
| #include "amdgpu_xgmi.h" | #include "amdgpu_xgmi.h" | ||||||
| #include "ivsrcid/nbio/irqsrcs_nbif_7_4.h" | #include "ivsrcid/nbio/irqsrcs_nbif_7_4.h" | ||||||
|  | #include "atom.h" | ||||||
| 
 | 
 | ||||||
| static const char *RAS_FS_NAME = "ras"; | static const char *RAS_FS_NAME = "ras"; | ||||||
| 
 | 
 | ||||||
| @ -320,11 +322,14 @@ static int amdgpu_ras_debugfs_ctrl_parse_data(struct file *f, | |||||||
|  * "disable" requires only the block. |  * "disable" requires only the block. | ||||||
|  * "enable" requires the block and error type. |  * "enable" requires the block and error type. | ||||||
|  * "inject" requires the block, error type, address, and value. |  * "inject" requires the block, error type, address, and value. | ||||||
|  |  * | ||||||
|  * The block is one of: umc, sdma, gfx, etc. |  * The block is one of: umc, sdma, gfx, etc. | ||||||
|  *	see ras_block_string[] for details |  *	see ras_block_string[] for details | ||||||
|  |  * | ||||||
|  * The error type is one of: ue, ce, where, |  * The error type is one of: ue, ce, where, | ||||||
|  *	ue is multi-uncorrectable |  *	ue is multi-uncorrectable | ||||||
|  *	ce is single-correctable |  *	ce is single-correctable | ||||||
|  |  * | ||||||
|  * The sub-block is a the sub-block index, pass 0 if there is no sub-block. |  * The sub-block is a the sub-block index, pass 0 if there is no sub-block. | ||||||
|  * The address and value are hexadecimal numbers, leading 0x is optional. |  * The address and value are hexadecimal numbers, leading 0x is optional. | ||||||
|  * |  * | ||||||
| @ -531,7 +536,7 @@ static struct ras_manager *amdgpu_ras_create_obj(struct amdgpu_device *adev, | |||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 	struct ras_manager *obj; | 	struct ras_manager *obj; | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
| 	if (head->block >= AMDGPU_RAS_BLOCK_COUNT) | 	if (head->block >= AMDGPU_RAS_BLOCK_COUNT) | ||||||
| @ -558,7 +563,7 @@ struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev, | |||||||
| 	struct ras_manager *obj; | 	struct ras_manager *obj; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
| 	if (head) { | 	if (head) { | ||||||
| @ -585,36 +590,11 @@ struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev, | |||||||
| } | } | ||||||
| /* obj end */ | /* obj end */ | ||||||
| 
 | 
 | ||||||
| static void amdgpu_ras_parse_status_code(struct amdgpu_device *adev, |  | ||||||
| 					 const char* invoke_type, |  | ||||||
| 					 const char* block_name, |  | ||||||
| 					 enum ta_ras_status ret) |  | ||||||
| { |  | ||||||
| 	switch (ret) { |  | ||||||
| 	case TA_RAS_STATUS__SUCCESS: |  | ||||||
| 		return; |  | ||||||
| 	case TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE: |  | ||||||
| 		dev_warn(adev->dev, |  | ||||||
| 			"RAS WARN: %s %s currently unavailable\n", |  | ||||||
| 			invoke_type, |  | ||||||
| 			block_name); |  | ||||||
| 		break; |  | ||||||
| 	default: |  | ||||||
| 		dev_err(adev->dev, |  | ||||||
| 			"RAS ERROR: %s %s error failed ret 0x%X\n", |  | ||||||
| 			invoke_type, |  | ||||||
| 			block_name, |  | ||||||
| 			ret); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* feature ctl begin */ | /* feature ctl begin */ | ||||||
| static int amdgpu_ras_is_feature_allowed(struct amdgpu_device *adev, | static int amdgpu_ras_is_feature_allowed(struct amdgpu_device *adev, | ||||||
| 					 struct ras_common_if *head) | 					 struct ras_common_if *head) | ||||||
| { | { | ||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	return adev->ras_hw_enabled & BIT(head->block); | ||||||
| 
 |  | ||||||
| 	return con->hw_supported & BIT(head->block); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int amdgpu_ras_is_feature_enabled(struct amdgpu_device *adev, | static int amdgpu_ras_is_feature_enabled(struct amdgpu_device *adev, | ||||||
| @ -658,10 +638,6 @@ static int __amdgpu_ras_feature_enable(struct amdgpu_device *adev, | |||||||
| 		con->features |= BIT(head->block); | 		con->features |= BIT(head->block); | ||||||
| 	} else { | 	} else { | ||||||
| 		if (obj && amdgpu_ras_is_feature_enabled(adev, head)) { | 		if (obj && amdgpu_ras_is_feature_enabled(adev, head)) { | ||||||
| 			/* skip clean gfx ras context feature for VEGA20 Gaming.
 |  | ||||||
| 			 * will clean later |  | ||||||
| 			 */ |  | ||||||
| 			if (!(!adev->ras_features && con->features & BIT(AMDGPU_RAS_BLOCK__GFX))) |  | ||||||
| 			con->features &= ~BIT(head->block); | 			con->features &= ~BIT(head->block); | ||||||
| 			put_obj(obj); | 			put_obj(obj); | ||||||
| 		} | 		} | ||||||
| @ -708,15 +684,10 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev, | |||||||
| 	if (!amdgpu_ras_intr_triggered()) { | 	if (!amdgpu_ras_intr_triggered()) { | ||||||
| 		ret = psp_ras_enable_features(&adev->psp, info, enable); | 		ret = psp_ras_enable_features(&adev->psp, info, enable); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			amdgpu_ras_parse_status_code(adev, | 			dev_err(adev->dev, "ras %s %s failed %d\n", | ||||||
| 				enable ? "enable":"disable", | 				enable ? "enable":"disable", | ||||||
| 				ras_block_str(head->block), | 				ras_block_str(head->block), | ||||||
| 						    (enum ta_ras_status)ret); | 				ret); | ||||||
| 			if (ret == TA_RAS_STATUS__RESET_NEEDED) |  | ||||||
| 				ret = -EAGAIN; |  | ||||||
| 			else |  | ||||||
| 				ret = -EINVAL; |  | ||||||
| 
 |  | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -770,6 +741,10 @@ int amdgpu_ras_feature_enable_on_boot(struct amdgpu_device *adev, | |||||||
| 				con->features |= BIT(head->block); | 				con->features |= BIT(head->block); | ||||||
| 
 | 
 | ||||||
| 			ret = amdgpu_ras_feature_enable(adev, head, 0); | 			ret = amdgpu_ras_feature_enable(adev, head, 0); | ||||||
|  | 
 | ||||||
|  | 			/* clean gfx block ras features flag */ | ||||||
|  | 			if (adev->ras_enabled && head->block == AMDGPU_RAS_BLOCK__GFX) | ||||||
|  | 				con->features &= ~BIT(head->block); | ||||||
| 		} | 		} | ||||||
| 	} else | 	} else | ||||||
| 		ret = amdgpu_ras_feature_enable(adev, head, enable); | 		ret = amdgpu_ras_feature_enable(adev, head, enable); | ||||||
| @ -890,6 +865,11 @@ int amdgpu_ras_query_error_status(struct amdgpu_device *adev, | |||||||
| 		    adev->gmc.xgmi.ras_funcs->query_ras_error_count) | 		    adev->gmc.xgmi.ras_funcs->query_ras_error_count) | ||||||
| 			adev->gmc.xgmi.ras_funcs->query_ras_error_count(adev, &err_data); | 			adev->gmc.xgmi.ras_funcs->query_ras_error_count(adev, &err_data); | ||||||
| 		break; | 		break; | ||||||
|  | 	case AMDGPU_RAS_BLOCK__HDP: | ||||||
|  | 		if (adev->hdp.ras_funcs && | ||||||
|  | 		    adev->hdp.ras_funcs->query_ras_error_count) | ||||||
|  | 			adev->hdp.ras_funcs->query_ras_error_count(adev, &err_data); | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| @ -901,18 +881,43 @@ int amdgpu_ras_query_error_status(struct amdgpu_device *adev, | |||||||
| 	info->ce_count = obj->err_data.ce_count; | 	info->ce_count = obj->err_data.ce_count; | ||||||
| 
 | 
 | ||||||
| 	if (err_data.ce_count) { | 	if (err_data.ce_count) { | ||||||
|  | 		if (adev->smuio.funcs && | ||||||
|  | 		    adev->smuio.funcs->get_socket_id && | ||||||
|  | 		    adev->smuio.funcs->get_die_id) { | ||||||
|  | 			dev_info(adev->dev, "socket: %d, die: %d " | ||||||
|  | 					"%ld correctable hardware errors " | ||||||
|  | 					"detected in %s block, no user " | ||||||
|  | 					"action is needed.\n", | ||||||
|  | 					adev->smuio.funcs->get_socket_id(adev), | ||||||
|  | 					adev->smuio.funcs->get_die_id(adev), | ||||||
|  | 					obj->err_data.ce_count, | ||||||
|  | 					ras_block_str(info->head.block)); | ||||||
|  | 		} else { | ||||||
| 			dev_info(adev->dev, "%ld correctable hardware errors " | 			dev_info(adev->dev, "%ld correctable hardware errors " | ||||||
| 					"detected in %s block, no user " | 					"detected in %s block, no user " | ||||||
| 					"action is needed.\n", | 					"action is needed.\n", | ||||||
| 					obj->err_data.ce_count, | 					obj->err_data.ce_count, | ||||||
| 					ras_block_str(info->head.block)); | 					ras_block_str(info->head.block)); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	if (err_data.ue_count) { | 	if (err_data.ue_count) { | ||||||
|  | 		if (adev->smuio.funcs && | ||||||
|  | 		    adev->smuio.funcs->get_socket_id && | ||||||
|  | 		    adev->smuio.funcs->get_die_id) { | ||||||
|  | 			dev_info(adev->dev, "socket: %d, die: %d " | ||||||
|  | 					"%ld uncorrectable hardware errors " | ||||||
|  | 					"detected in %s block\n", | ||||||
|  | 					adev->smuio.funcs->get_socket_id(adev), | ||||||
|  | 					adev->smuio.funcs->get_die_id(adev), | ||||||
|  | 					obj->err_data.ue_count, | ||||||
|  | 					ras_block_str(info->head.block)); | ||||||
|  | 		} else { | ||||||
| 			dev_info(adev->dev, "%ld uncorrectable hardware errors " | 			dev_info(adev->dev, "%ld uncorrectable hardware errors " | ||||||
| 					"detected in %s block\n", | 					"detected in %s block\n", | ||||||
| 					obj->err_data.ue_count, | 					obj->err_data.ue_count, | ||||||
| 					ras_block_str(info->head.block)); | 					ras_block_str(info->head.block)); | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -937,11 +942,20 @@ int amdgpu_ras_reset_error_status(struct amdgpu_device *adev, | |||||||
| 		if (adev->mmhub.ras_funcs && | 		if (adev->mmhub.ras_funcs && | ||||||
| 		    adev->mmhub.ras_funcs->reset_ras_error_count) | 		    adev->mmhub.ras_funcs->reset_ras_error_count) | ||||||
| 			adev->mmhub.ras_funcs->reset_ras_error_count(adev); | 			adev->mmhub.ras_funcs->reset_ras_error_count(adev); | ||||||
|  | 
 | ||||||
|  | 		if (adev->mmhub.ras_funcs && | ||||||
|  | 		    adev->mmhub.ras_funcs->reset_ras_error_status) | ||||||
|  | 			adev->mmhub.ras_funcs->reset_ras_error_status(adev); | ||||||
| 		break; | 		break; | ||||||
| 	case AMDGPU_RAS_BLOCK__SDMA: | 	case AMDGPU_RAS_BLOCK__SDMA: | ||||||
| 		if (adev->sdma.funcs->reset_ras_error_count) | 		if (adev->sdma.funcs->reset_ras_error_count) | ||||||
| 			adev->sdma.funcs->reset_ras_error_count(adev); | 			adev->sdma.funcs->reset_ras_error_count(adev); | ||||||
| 		break; | 		break; | ||||||
|  | 	case AMDGPU_RAS_BLOCK__HDP: | ||||||
|  | 		if (adev->hdp.ras_funcs && | ||||||
|  | 		    adev->hdp.ras_funcs->reset_ras_error_count) | ||||||
|  | 			adev->hdp.ras_funcs->reset_ras_error_count(adev); | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| @ -1022,38 +1036,44 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev, | |||||||
| 		ret = -EINVAL; | 		ret = -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	amdgpu_ras_parse_status_code(adev, | 	if (ret) | ||||||
| 				     "inject", | 		dev_err(adev->dev, "ras inject %s failed %d\n", | ||||||
| 				     ras_block_str(info->head.block), | 			ras_block_str(info->head.block), ret); | ||||||
| 				     (enum ta_ras_status)ret); |  | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* get the total error counts on all IPs */ | /* get the total error counts on all IPs */ | ||||||
| unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev, | void amdgpu_ras_query_error_count(struct amdgpu_device *adev, | ||||||
| 		bool is_ce) | 				  unsigned long *ce_count, | ||||||
|  | 				  unsigned long *ue_count) | ||||||
| { | { | ||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 	struct ras_manager *obj; | 	struct ras_manager *obj; | ||||||
| 	struct ras_err_data data = {0, 0}; | 	unsigned long ce, ue; | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return 0; | 		return; | ||||||
| 
 | 
 | ||||||
|  | 	ce = 0; | ||||||
|  | 	ue = 0; | ||||||
| 	list_for_each_entry(obj, &con->head, node) { | 	list_for_each_entry(obj, &con->head, node) { | ||||||
| 		struct ras_query_if info = { | 		struct ras_query_if info = { | ||||||
| 			.head = obj->head, | 			.head = obj->head, | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		if (amdgpu_ras_query_error_status(adev, &info)) | 		if (amdgpu_ras_query_error_status(adev, &info)) | ||||||
| 			return 0; | 			return; | ||||||
| 
 | 
 | ||||||
| 		data.ce_count += info.ce_count; | 		ce += info.ce_count; | ||||||
| 		data.ue_count += info.ue_count; | 		ue += info.ue_count; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return is_ce ? data.ce_count : data.ue_count; | 	if (ce_count) | ||||||
|  | 		*ce_count = ce; | ||||||
|  | 
 | ||||||
|  | 	if (ue_count) | ||||||
|  | 		*ue_count = ue; | ||||||
| } | } | ||||||
| /* query/inject/cure end */ | /* query/inject/cure end */ | ||||||
| 
 | 
 | ||||||
| @ -1265,8 +1285,8 @@ static int amdgpu_ras_sysfs_remove_all(struct amdgpu_device *adev) | |||||||
| static struct dentry *amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev) | static struct dentry *amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 	struct dentry *dir; |  | ||||||
| 	struct drm_minor  *minor = adev_to_drm(adev)->primary; | 	struct drm_minor  *minor = adev_to_drm(adev)->primary; | ||||||
|  | 	struct dentry     *dir; | ||||||
| 
 | 
 | ||||||
| 	dir = debugfs_create_dir(RAS_FS_NAME, minor->debugfs_root); | 	dir = debugfs_create_dir(RAS_FS_NAME, minor->debugfs_root); | ||||||
| 	debugfs_create_file("ras_ctrl", S_IWUGO | S_IRUGO, dir, adev, | 	debugfs_create_file("ras_ctrl", S_IWUGO | S_IRUGO, dir, adev, | ||||||
| @ -1275,6 +1295,8 @@ static struct dentry *amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device * | |||||||
| 			    &amdgpu_ras_debugfs_eeprom_ops); | 			    &amdgpu_ras_debugfs_eeprom_ops); | ||||||
| 	debugfs_create_u32("bad_page_cnt_threshold", 0444, dir, | 	debugfs_create_u32("bad_page_cnt_threshold", 0444, dir, | ||||||
| 			   &con->bad_page_cnt_threshold); | 			   &con->bad_page_cnt_threshold); | ||||||
|  | 	debugfs_create_x32("ras_hw_enabled", 0444, dir, &adev->ras_hw_enabled); | ||||||
|  | 	debugfs_create_x32("ras_enabled", 0444, dir, &adev->ras_enabled); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * After one uncorrectable error happens, usually GPU recovery will | 	 * After one uncorrectable error happens, usually GPU recovery will | ||||||
| @ -1561,7 +1583,7 @@ static void amdgpu_ras_log_on_err_counter(struct amdgpu_device *adev) | |||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 	struct ras_manager *obj; | 	struct ras_manager *obj; | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry(obj, &con->head, node) { | 	list_for_each_entry(obj, &con->head, node) { | ||||||
| @ -1611,7 +1633,7 @@ static void amdgpu_ras_query_err_status(struct amdgpu_device *adev) | |||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 	struct ras_manager *obj; | 	struct ras_manager *obj; | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry(obj, &con->head, node) { | 	list_for_each_entry(obj, &con->head, node) { | ||||||
| @ -1925,7 +1947,7 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) | |||||||
| 	bool exc_err_limit = false; | 	bool exc_err_limit = false; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (adev->ras_features && con) | 	if (adev->ras_enabled && con) | ||||||
| 		data = &con->eh_data; | 		data = &con->eh_data; | ||||||
| 	else | 	else | ||||||
| 		return 0; | 		return 0; | ||||||
| @ -1962,6 +1984,9 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) | |||||||
| 		ret = amdgpu_ras_load_bad_pages(adev); | 		ret = amdgpu_ras_load_bad_pages(adev); | ||||||
| 		if (ret) | 		if (ret) | ||||||
| 			goto free; | 			goto free; | ||||||
|  | 
 | ||||||
|  | 		if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->send_hbm_bad_pages_num) | ||||||
|  | 			adev->smu.ppt_funcs->send_hbm_bad_pages_num(&adev->smu, con->eeprom_control.num_recs); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -2028,6 +2053,25 @@ static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev) | |||||||
| 		adev->asic_type == CHIP_SIENNA_CICHLID; | 		adev->asic_type == CHIP_SIENNA_CICHLID; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * this is workaround for vega20 workstation sku, | ||||||
|  |  * force enable gfx ras, ignore vbios gfx ras flag | ||||||
|  |  * due to GC EDC can not write | ||||||
|  |  */ | ||||||
|  | static void amdgpu_ras_get_quirks(struct amdgpu_device *adev) | ||||||
|  | { | ||||||
|  | 	struct atom_context *ctx = adev->mode_info.atom_context; | ||||||
|  | 
 | ||||||
|  | 	if (!ctx) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (strnstr(ctx->vbios_version, "D16406", | ||||||
|  | 		    sizeof(ctx->vbios_version)) || | ||||||
|  | 		strnstr(ctx->vbios_version, "D36002", | ||||||
|  | 			sizeof(ctx->vbios_version))) | ||||||
|  | 		adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__GFX); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * check hardware's ras ability which will be saved in hw_supported. |  * check hardware's ras ability which will be saved in hw_supported. | ||||||
|  * if hardware does not support ras, we can skip some ras initializtion and |  * if hardware does not support ras, we can skip some ras initializtion and | ||||||
| @ -2037,11 +2081,9 @@ static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev) | |||||||
|  * we have to initialize ras as normal. but need check if operation is |  * we have to initialize ras as normal. but need check if operation is | ||||||
|  * allowed or not in each function. |  * allowed or not in each function. | ||||||
|  */ |  */ | ||||||
| static void amdgpu_ras_check_supported(struct amdgpu_device *adev, | static void amdgpu_ras_check_supported(struct amdgpu_device *adev) | ||||||
| 		uint32_t *hw_supported, uint32_t *supported) |  | ||||||
| { | { | ||||||
| 	*hw_supported = 0; | 	adev->ras_hw_enabled = adev->ras_enabled = 0; | ||||||
| 	*supported = 0; |  | ||||||
| 
 | 
 | ||||||
| 	if (amdgpu_sriov_vf(adev) || !adev->is_atom_fw || | 	if (amdgpu_sriov_vf(adev) || !adev->is_atom_fw || | ||||||
| 	    !amdgpu_ras_asic_supported(adev)) | 	    !amdgpu_ras_asic_supported(adev)) | ||||||
| @ -2050,7 +2092,7 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev, | |||||||
| 	if (!adev->gmc.xgmi.connected_to_cpu) { | 	if (!adev->gmc.xgmi.connected_to_cpu) { | ||||||
| 		if (amdgpu_atomfirmware_mem_ecc_supported(adev)) { | 		if (amdgpu_atomfirmware_mem_ecc_supported(adev)) { | ||||||
| 			dev_info(adev->dev, "MEM ECC is active.\n"); | 			dev_info(adev->dev, "MEM ECC is active.\n"); | ||||||
| 			*hw_supported |= (1 << AMDGPU_RAS_BLOCK__UMC | | 			adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__UMC | | ||||||
| 						   1 << AMDGPU_RAS_BLOCK__DF); | 						   1 << AMDGPU_RAS_BLOCK__DF); | ||||||
| 		} else { | 		} else { | ||||||
| 			dev_info(adev->dev, "MEM ECC is not presented.\n"); | 			dev_info(adev->dev, "MEM ECC is not presented.\n"); | ||||||
| @ -2058,7 +2100,7 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev, | |||||||
| 
 | 
 | ||||||
| 		if (amdgpu_atomfirmware_sram_ecc_supported(adev)) { | 		if (amdgpu_atomfirmware_sram_ecc_supported(adev)) { | ||||||
| 			dev_info(adev->dev, "SRAM ECC is active.\n"); | 			dev_info(adev->dev, "SRAM ECC is active.\n"); | ||||||
| 			*hw_supported |= ~(1 << AMDGPU_RAS_BLOCK__UMC | | 			adev->ras_hw_enabled |= ~(1 << AMDGPU_RAS_BLOCK__UMC | | ||||||
| 						    1 << AMDGPU_RAS_BLOCK__DF); | 						    1 << AMDGPU_RAS_BLOCK__DF); | ||||||
| 		} else { | 		} else { | ||||||
| 			dev_info(adev->dev, "SRAM ECC is not presented.\n"); | 			dev_info(adev->dev, "SRAM ECC is not presented.\n"); | ||||||
| @ -2066,17 +2108,42 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev, | |||||||
| 	} else { | 	} else { | ||||||
| 		/* driver only manages a few IP blocks RAS feature
 | 		/* driver only manages a few IP blocks RAS feature
 | ||||||
| 		 * when GPU is connected cpu through XGMI */ | 		 * when GPU is connected cpu through XGMI */ | ||||||
| 		*hw_supported |= (1 << AMDGPU_RAS_BLOCK__GFX | | 		adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__GFX | | ||||||
| 					   1 << AMDGPU_RAS_BLOCK__SDMA | | 					   1 << AMDGPU_RAS_BLOCK__SDMA | | ||||||
| 					   1 << AMDGPU_RAS_BLOCK__MMHUB); | 					   1 << AMDGPU_RAS_BLOCK__MMHUB); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* hw_supported needs to be aligned with RAS block mask. */ | 	amdgpu_ras_get_quirks(adev); | ||||||
| 	*hw_supported &= AMDGPU_RAS_BLOCK_MASK; |  | ||||||
| 
 | 
 | ||||||
| 	*supported = amdgpu_ras_enable == 0 ? | 	/* hw_supported needs to be aligned with RAS block mask. */ | ||||||
| 			0 : *hw_supported & amdgpu_ras_mask; | 	adev->ras_hw_enabled &= AMDGPU_RAS_BLOCK_MASK; | ||||||
| 	adev->ras_features = *supported; | 
 | ||||||
|  | 	adev->ras_enabled = amdgpu_ras_enable == 0 ? 0 : | ||||||
|  | 		adev->ras_hw_enabled & amdgpu_ras_mask; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void amdgpu_ras_counte_dw(struct work_struct *work) | ||||||
|  | { | ||||||
|  | 	struct amdgpu_ras *con = container_of(work, struct amdgpu_ras, | ||||||
|  | 					      ras_counte_delay_work.work); | ||||||
|  | 	struct amdgpu_device *adev = con->adev; | ||||||
|  | 	struct drm_device *dev = adev_to_drm(adev); | ||||||
|  | 	unsigned long ce_count, ue_count; | ||||||
|  | 	int res; | ||||||
|  | 
 | ||||||
|  | 	res = pm_runtime_get_sync(dev->dev); | ||||||
|  | 	if (res < 0) | ||||||
|  | 		goto Out; | ||||||
|  | 
 | ||||||
|  | 	/* Cache new values.
 | ||||||
|  | 	 */ | ||||||
|  | 	amdgpu_ras_query_error_count(adev, &ce_count, &ue_count); | ||||||
|  | 	atomic_set(&con->ras_ce_count, ce_count); | ||||||
|  | 	atomic_set(&con->ras_ue_count, ue_count); | ||||||
|  | 
 | ||||||
|  | 	pm_runtime_mark_last_busy(dev->dev); | ||||||
|  | Out: | ||||||
|  | 	pm_runtime_put_autosuspend(dev->dev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int amdgpu_ras_init(struct amdgpu_device *adev) | int amdgpu_ras_init(struct amdgpu_device *adev) | ||||||
| @ -2093,17 +2160,22 @@ int amdgpu_ras_init(struct amdgpu_device *adev) | |||||||
| 	if (!con) | 	if (!con) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | 	con->adev = adev; | ||||||
|  | 	INIT_DELAYED_WORK(&con->ras_counte_delay_work, amdgpu_ras_counte_dw); | ||||||
|  | 	atomic_set(&con->ras_ce_count, 0); | ||||||
|  | 	atomic_set(&con->ras_ue_count, 0); | ||||||
|  | 
 | ||||||
| 	con->objs = (struct ras_manager *)(con + 1); | 	con->objs = (struct ras_manager *)(con + 1); | ||||||
| 
 | 
 | ||||||
| 	amdgpu_ras_set_context(adev, con); | 	amdgpu_ras_set_context(adev, con); | ||||||
| 
 | 
 | ||||||
| 	amdgpu_ras_check_supported(adev, &con->hw_supported, | 	amdgpu_ras_check_supported(adev); | ||||||
| 			&con->supported); | 
 | ||||||
| 	if (!con->hw_supported || (adev->asic_type == CHIP_VEGA10)) { | 	if (!adev->ras_enabled || adev->asic_type == CHIP_VEGA10) { | ||||||
| 		/* set gfx block ras context feature for VEGA20 Gaming
 | 		/* set gfx block ras context feature for VEGA20 Gaming
 | ||||||
| 		 * send ras disable cmd to ras ta during ras late init. | 		 * send ras disable cmd to ras ta during ras late init. | ||||||
| 		 */ | 		 */ | ||||||
| 		if (!adev->ras_features && adev->asic_type == CHIP_VEGA20) { | 		if (!adev->ras_enabled && adev->asic_type == CHIP_VEGA20) { | ||||||
| 			con->features |= BIT(AMDGPU_RAS_BLOCK__GFX); | 			con->features |= BIT(AMDGPU_RAS_BLOCK__GFX); | ||||||
| 
 | 
 | ||||||
| 			return 0; | 			return 0; | ||||||
| @ -2154,7 +2226,8 @@ int amdgpu_ras_init(struct amdgpu_device *adev) | |||||||
| 
 | 
 | ||||||
| 	dev_info(adev->dev, "RAS INFO: ras initialized successfully, " | 	dev_info(adev->dev, "RAS INFO: ras initialized successfully, " | ||||||
| 		 "hardware ability[%x] ras_mask[%x]\n", | 		 "hardware ability[%x] ras_mask[%x]\n", | ||||||
| 			con->hw_supported, con->supported); | 		 adev->ras_hw_enabled, adev->ras_enabled); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| release_con: | release_con: | ||||||
| 	amdgpu_ras_set_context(adev, NULL); | 	amdgpu_ras_set_context(adev, NULL); | ||||||
| @ -2163,7 +2236,7 @@ release_con: | |||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int amdgpu_persistent_edc_harvesting_supported(struct amdgpu_device *adev) | int amdgpu_persistent_edc_harvesting_supported(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	if (adev->gmc.xgmi.connected_to_cpu) | 	if (adev->gmc.xgmi.connected_to_cpu) | ||||||
| 		return 1; | 		return 1; | ||||||
| @ -2195,6 +2268,8 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev, | |||||||
| 			 struct ras_fs_if *fs_info, | 			 struct ras_fs_if *fs_info, | ||||||
| 			 struct ras_ih_if *ih_info) | 			 struct ras_ih_if *ih_info) | ||||||
| { | { | ||||||
|  | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
|  | 	unsigned long ue_count, ce_count; | ||||||
| 	int r; | 	int r; | ||||||
| 
 | 
 | ||||||
| 	/* disable RAS feature per IP block if it is not supported */ | 	/* disable RAS feature per IP block if it is not supported */ | ||||||
| @ -2235,6 +2310,12 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev, | |||||||
| 	if (r) | 	if (r) | ||||||
| 		goto sysfs; | 		goto sysfs; | ||||||
| 
 | 
 | ||||||
|  | 	/* Those are the cached values at init.
 | ||||||
|  | 	 */ | ||||||
|  | 	amdgpu_ras_query_error_count(adev, &ce_count, &ue_count); | ||||||
|  | 	atomic_set(&con->ras_ce_count, ce_count); | ||||||
|  | 	atomic_set(&con->ras_ue_count, ue_count); | ||||||
|  | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| cleanup: | cleanup: | ||||||
| 	amdgpu_ras_sysfs_remove(adev, ras_block); | 	amdgpu_ras_sysfs_remove(adev, ras_block); | ||||||
| @ -2268,7 +2349,7 @@ void amdgpu_ras_resume(struct amdgpu_device *adev) | |||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 	struct ras_manager *obj, *tmp; | 	struct ras_manager *obj, *tmp; | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) { | 	if (!adev->ras_enabled || !con) { | ||||||
| 		/* clean ras context for VEGA20 Gaming after send ras disable cmd */ | 		/* clean ras context for VEGA20 Gaming after send ras disable cmd */ | ||||||
| 		amdgpu_release_ras_context(adev); | 		amdgpu_release_ras_context(adev); | ||||||
| 
 | 
 | ||||||
| @ -2314,7 +2395,7 @@ void amdgpu_ras_suspend(struct amdgpu_device *adev) | |||||||
| { | { | ||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	amdgpu_ras_disable_all_features(adev, 0); | 	amdgpu_ras_disable_all_features(adev, 0); | ||||||
| @ -2328,9 +2409,10 @@ int amdgpu_ras_pre_fini(struct amdgpu_device *adev) | |||||||
| { | { | ||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| 	/* Need disable ras on all IPs here before ip [hw/sw]fini */ | 	/* Need disable ras on all IPs here before ip [hw/sw]fini */ | ||||||
| 	amdgpu_ras_disable_all_features(adev, 0); | 	amdgpu_ras_disable_all_features(adev, 0); | ||||||
| 	amdgpu_ras_recovery_fini(adev); | 	amdgpu_ras_recovery_fini(adev); | ||||||
| @ -2341,7 +2423,7 @@ int amdgpu_ras_fini(struct amdgpu_device *adev) | |||||||
| { | { | ||||||
| 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | 	struct amdgpu_ras *con = amdgpu_ras_get_context(adev); | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features || !con) | 	if (!adev->ras_enabled || !con) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	amdgpu_ras_fs_fini(adev); | 	amdgpu_ras_fs_fini(adev); | ||||||
| @ -2352,6 +2434,8 @@ int amdgpu_ras_fini(struct amdgpu_device *adev) | |||||||
| 	if (con->features) | 	if (con->features) | ||||||
| 		amdgpu_ras_disable_all_features(adev, 1); | 		amdgpu_ras_disable_all_features(adev, 1); | ||||||
| 
 | 
 | ||||||
|  | 	cancel_delayed_work_sync(&con->ras_counte_delay_work); | ||||||
|  | 
 | ||||||
| 	amdgpu_ras_set_context(adev, NULL); | 	amdgpu_ras_set_context(adev, NULL); | ||||||
| 	kfree(con); | 	kfree(con); | ||||||
| 
 | 
 | ||||||
| @ -2360,10 +2444,8 @@ int amdgpu_ras_fini(struct amdgpu_device *adev) | |||||||
| 
 | 
 | ||||||
| void amdgpu_ras_global_ras_isr(struct amdgpu_device *adev) | void amdgpu_ras_global_ras_isr(struct amdgpu_device *adev) | ||||||
| { | { | ||||||
| 	uint32_t hw_supported, supported; | 	amdgpu_ras_check_supported(adev); | ||||||
| 
 | 	if (!adev->ras_hw_enabled) | ||||||
| 	amdgpu_ras_check_supported(adev, &hw_supported, &supported); |  | ||||||
| 	if (!hw_supported) |  | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (atomic_cmpxchg(&amdgpu_ras_in_intr, 0, 1) == 0) { | 	if (atomic_cmpxchg(&amdgpu_ras_in_intr, 0, 1) == 0) { | ||||||
| @ -2392,7 +2474,7 @@ void amdgpu_release_ras_context(struct amdgpu_device *adev) | |||||||
| 	if (!con) | 	if (!con) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (!adev->ras_features && con->features & BIT(AMDGPU_RAS_BLOCK__GFX)) { | 	if (!adev->ras_enabled && con->features & BIT(AMDGPU_RAS_BLOCK__GFX)) { | ||||||
| 		con->features &= ~BIT(AMDGPU_RAS_BLOCK__GFX); | 		con->features &= ~BIT(AMDGPU_RAS_BLOCK__GFX); | ||||||
| 		amdgpu_ras_set_context(adev, NULL); | 		amdgpu_ras_set_context(adev, NULL); | ||||||
| 		kfree(con); | 		kfree(con); | ||||||
|  | |||||||
| @ -313,9 +313,6 @@ struct ras_common_if { | |||||||
| struct amdgpu_ras { | struct amdgpu_ras { | ||||||
| 	/* ras infrastructure */ | 	/* ras infrastructure */ | ||||||
| 	/* for ras itself. */ | 	/* for ras itself. */ | ||||||
| 	uint32_t hw_supported; |  | ||||||
| 	/* for IP to check its ras ability. */ |  | ||||||
| 	uint32_t supported; |  | ||||||
| 	uint32_t features; | 	uint32_t features; | ||||||
| 	struct list_head head; | 	struct list_head head; | ||||||
| 	/* sysfs */ | 	/* sysfs */ | ||||||
| @ -343,6 +340,11 @@ struct amdgpu_ras { | |||||||
| 
 | 
 | ||||||
| 	/* disable ras error count harvest in recovery */ | 	/* disable ras error count harvest in recovery */ | ||||||
| 	bool disable_ras_err_cnt_harvest; | 	bool disable_ras_err_cnt_harvest; | ||||||
|  | 
 | ||||||
|  | 	/* RAS count errors delayed work */ | ||||||
|  | 	struct delayed_work ras_counte_delay_work; | ||||||
|  | 	atomic_t ras_ue_count; | ||||||
|  | 	atomic_t ras_ce_count; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct ras_fs_data { | struct ras_fs_data { | ||||||
| @ -478,7 +480,7 @@ static inline int amdgpu_ras_is_supported(struct amdgpu_device *adev, | |||||||
| 
 | 
 | ||||||
| 	if (block >= AMDGPU_RAS_BLOCK_COUNT) | 	if (block >= AMDGPU_RAS_BLOCK_COUNT) | ||||||
| 		return 0; | 		return 0; | ||||||
| 	return ras && (ras->supported & (1 << block)); | 	return ras && (adev->ras_enabled & (1 << block)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int amdgpu_ras_recovery_init(struct amdgpu_device *adev); | int amdgpu_ras_recovery_init(struct amdgpu_device *adev); | ||||||
| @ -488,8 +490,9 @@ int amdgpu_ras_request_reset_on_boot(struct amdgpu_device *adev, | |||||||
| void amdgpu_ras_resume(struct amdgpu_device *adev); | void amdgpu_ras_resume(struct amdgpu_device *adev); | ||||||
| void amdgpu_ras_suspend(struct amdgpu_device *adev); | void amdgpu_ras_suspend(struct amdgpu_device *adev); | ||||||
| 
 | 
 | ||||||
| unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev, | void amdgpu_ras_query_error_count(struct amdgpu_device *adev, | ||||||
| 		bool is_ce); | 				  unsigned long *ce_count, | ||||||
|  | 				  unsigned long *ue_count); | ||||||
| 
 | 
 | ||||||
| /* error handling functions */ | /* error handling functions */ | ||||||
| int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, | int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, | ||||||
| @ -628,4 +631,7 @@ void amdgpu_ras_set_error_query_ready(struct amdgpu_device *adev, bool ready); | |||||||
| bool amdgpu_ras_need_emergency_restart(struct amdgpu_device *adev); | bool amdgpu_ras_need_emergency_restart(struct amdgpu_device *adev); | ||||||
| 
 | 
 | ||||||
| void amdgpu_release_ras_context(struct amdgpu_device *adev); | void amdgpu_release_ras_context(struct amdgpu_device *adev); | ||||||
|  | 
 | ||||||
|  | int amdgpu_persistent_edc_harvesting_supported(struct amdgpu_device *adev); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <drm/drm_mm.h> | #include <drm/drm_mm.h> | ||||||
| #include <drm/ttm/ttm_resource.h> | #include <drm/ttm/ttm_resource.h> | ||||||
|  | #include <drm/ttm/ttm_range_manager.h> | ||||||
| 
 | 
 | ||||||
| /* state back for walking over vram_mgr and gtt_mgr allocations */ | /* state back for walking over vram_mgr and gtt_mgr allocations */ | ||||||
| struct amdgpu_res_cursor { | struct amdgpu_res_cursor { | ||||||
| @ -53,7 +54,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res, | |||||||
| { | { | ||||||
| 	struct drm_mm_node *node; | 	struct drm_mm_node *node; | ||||||
| 
 | 
 | ||||||
| 	if (!res || !res->mm_node) { | 	if (!res) { | ||||||
| 		cur->start = start; | 		cur->start = start; | ||||||
| 		cur->size = size; | 		cur->size = size; | ||||||
| 		cur->remaining = size; | 		cur->remaining = size; | ||||||
| @ -63,7 +64,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res, | |||||||
| 
 | 
 | ||||||
| 	BUG_ON(start + size > res->num_pages << PAGE_SHIFT); | 	BUG_ON(start + size > res->num_pages << PAGE_SHIFT); | ||||||
| 
 | 
 | ||||||
| 	node = res->mm_node; | 	node = to_ttm_range_mgr_node(res)->mm_nodes; | ||||||
| 	while (start >= node->size << PAGE_SHIFT) | 	while (start >= node->size << PAGE_SHIFT) | ||||||
| 		start -= node++->size << PAGE_SHIFT; | 		start -= node++->size << PAGE_SHIFT; | ||||||
| 
 | 
 | ||||||
|  | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Linus Torvalds
						Linus Torvalds