mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-16 12:14:06 +00: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
1291 changed files with 312156 additions and 22330 deletions
|
@ -11,7 +11,9 @@ maintainers:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm2835-vec
|
||||
enum:
|
||||
- brcm,bcm2711-vec
|
||||
- brcm,bcm2835-vec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -18,7 +18,7 @@ properties:
|
|||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
maxItems: 3
|
||||
items:
|
||||
- description:
|
||||
Register block of mhdptx apb registers up to PHY mapped area (AUX_CONFIG_P).
|
||||
|
@ -26,13 +26,16 @@ properties:
|
|||
included in the associated PHY.
|
||||
- description:
|
||||
Register block for DSS_EDP0_INTG_CFG_VP registers in case of TI J7 SoCs.
|
||||
- description:
|
||||
Register block of mhdptx sapb registers.
|
||||
|
||||
reg-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
maxItems: 3
|
||||
items:
|
||||
- const: mhdptx
|
||||
- const: j721e-intg
|
||||
- const: mhdptx-sapb
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
@ -99,14 +102,18 @@ allOf:
|
|||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
reg-names:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
required:
|
||||
- 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:
|
||||
- enum:
|
||||
- amlogic,meson-g12a-mali
|
||||
- mediatek,mt8183-mali
|
||||
- realtek,rtd1619-mali
|
||||
- rockchip,px30-mali
|
||||
- const: arm,mali-bifrost # Mali Bifrost GPU model/revision is fully discoverable
|
||||
|
@ -41,10 +42,13 @@ properties:
|
|||
|
||||
mali-supply: true
|
||||
|
||||
sram-supply: true
|
||||
|
||||
operating-points-v2: true
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
@ -89,6 +93,30 @@ allOf:
|
|||
then:
|
||||
required:
|
||||
- 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:
|
||||
- |
|
||||
|
|
|
@ -178,6 +178,15 @@ DMA Fence Array
|
|||
.. kernel-doc:: include/linux/dma-fence-array.h
|
||||
: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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -66,3 +66,9 @@ Display Core
|
|||
============
|
||||
|
||||
**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
|
||||
: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
|
||||
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
|
||||
-----------------------------------
|
||||
|
||||
|
|
|
@ -469,8 +469,8 @@ DRM MM Range Allocator Function References
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_mm.c
|
||||
:export:
|
||||
|
||||
DRM Cache Handling
|
||||
==================
|
||||
DRM Cache Handling and Fast WC memcpy()
|
||||
=======================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_cache.c
|
||||
:export:
|
||||
|
|
|
@ -210,13 +210,13 @@ DPIO
|
|||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpio_phy.c
|
||||
:doc: DPIO
|
||||
|
||||
CSR firmware support for DMC
|
||||
----------------------------
|
||||
DMC Firmware Support
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_csr.c
|
||||
:doc: csr support for dmc
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c
|
||||
: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:
|
||||
|
||||
Video BIOS Table (VBT)
|
||||
|
@ -537,7 +537,7 @@ The HuC FW layout is the same as the GuC one, see `GuC Firmware Layout`_
|
|||
|
||||
DMC
|
||||
---
|
||||
See `CSR firmware support for DMC`_
|
||||
See `DMC Firmware Support`_
|
||||
|
||||
Tracing
|
||||
=======
|
||||
|
|
|
@ -10,6 +10,7 @@ Linux GPU Driver Developer's Guide
|
|||
drm-kms
|
||||
drm-kms-helpers
|
||||
drm-uapi
|
||||
driver-uapi
|
||||
drm-client
|
||||
drivers
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
Level: Intermediate
|
||||
|
|
30
MAINTAINERS
30
MAINTAINERS
|
@ -878,7 +878,7 @@ M: Harry Wentland <harry.wentland@amd.com>
|
|||
M: Leo Li <sunpeng.li@amd.com>
|
||||
L: amd-gfx@lists.freedesktop.org
|
||||
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/
|
||||
|
||||
AMD FAM15H PROCESSOR POWER MONITORING DRIVER
|
||||
|
@ -954,7 +954,7 @@ AMD POWERPLAY
|
|||
M: Evan Quan <evan.quan@amd.com>
|
||||
L: amd-gfx@lists.freedesktop.org
|
||||
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/
|
||||
|
||||
AMD SEATTLE DEVICE TREE SUPPORT
|
||||
|
@ -5912,6 +5912,13 @@ S: Orphan / Obsolete
|
|||
F: drivers/gpu/drm/savage/
|
||||
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
|
||||
S: Orphan / Obsolete
|
||||
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: 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
|
||||
M: Qiang Yu <yuq825@gmail.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
|
@ -6281,7 +6296,7 @@ M: Christian Koenig <christian.koenig@amd.com>
|
|||
M: Huang Rui <ray.huang@amd.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
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: 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
|
||||
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
|
||||
M: Andy Walls <awalls@md.metrocast.net>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -15336,6 +15359,7 @@ F: drivers/net/wireless/quantenna
|
|||
RADEON and AMDGPU DRM DRIVERS
|
||||
M: Alex Deucher <alexander.deucher@amd.com>
|
||||
M: Christian König <christian.koenig@amd.com>
|
||||
M: Pan, Xinhui <Xinhui.Pan@amd.com>
|
||||
L: amd-gfx@lists.freedesktop.org
|
||||
S: Supported
|
||||
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_ICL_11_IDS(&gen11_early_ops),
|
||||
INTEL_EHL_IDS(&gen11_early_ops),
|
||||
INTEL_JSL_IDS(&gen11_early_ops),
|
||||
INTEL_TGL_12_IDS(&gen11_early_ops),
|
||||
INTEL_RKL_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);
|
||||
|
|
|
@ -234,7 +234,7 @@ retry:
|
|||
shared_count = fobj->shared_count;
|
||||
else
|
||||
shared_count = 0;
|
||||
fence_excl = rcu_dereference(resv->fence_excl);
|
||||
fence_excl = dma_resv_excl_fence(resv);
|
||||
if (read_seqcount_retry(&resv->seq, seq)) {
|
||||
rcu_read_unlock();
|
||||
goto retry;
|
||||
|
@ -1147,8 +1147,7 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
|||
long ret;
|
||||
|
||||
/* Wait on any implicit rendering fences */
|
||||
ret = dma_resv_wait_timeout_rcu(resv, write, true,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
ret = dma_resv_wait_timeout(resv, write, true, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -1349,15 +1348,14 @@ EXPORT_SYMBOL_GPL(dma_buf_vunmap);
|
|||
#ifdef CONFIG_DEBUG_FS
|
||||
static int dma_buf_debug_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
int ret;
|
||||
struct dma_buf *buf_obj;
|
||||
struct dma_buf_attachment *attach_obj;
|
||||
struct dma_resv *robj;
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *fence;
|
||||
unsigned seq;
|
||||
int count = 0, attach_count, shared_count, i;
|
||||
size_t size = 0;
|
||||
int ret;
|
||||
|
||||
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 ?: "");
|
||||
|
||||
robj = buf_obj->resv;
|
||||
while (true) {
|
||||
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();
|
||||
}
|
||||
|
||||
fence = dma_resv_excl_fence(robj);
|
||||
if (fence)
|
||||
seq_printf(s, "\tExclusive fence: %s %s %ssignalled\n",
|
||||
fence->ops->get_driver_name(fence),
|
||||
fence->ops->get_timeline_name(fence),
|
||||
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++) {
|
||||
fence = rcu_dereference(fobj->shared[i]);
|
||||
if (!dma_fence_get_rcu(fence))
|
||||
continue;
|
||||
fence = rcu_dereference_protected(fobj->shared[i],
|
||||
dma_resv_held(robj));
|
||||
seq_printf(s, "\tShared fence: %s %s %ssignalled\n",
|
||||
fence->ops->get_driver_name(fence),
|
||||
fence->ops->get_timeline_name(fence),
|
||||
dma_fence_is_signaled(fence) ? "" : "un");
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
seq_puts(s, "\tAttached Devices:\n");
|
||||
attach_count = 0;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
#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
|
||||
* @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);
|
||||
|
||||
old = dma_resv_get_list(obj);
|
||||
|
||||
old = dma_resv_shared_list(obj);
|
||||
if (old && old->shared_max) {
|
||||
if ((old->shared_count + num_fences) <= old->shared_max)
|
||||
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 {
|
||||
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);
|
||||
|
||||
#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
|
||||
* @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);
|
||||
|
||||
fobj = dma_resv_get_list(obj);
|
||||
fobj = dma_resv_shared_list(obj);
|
||||
count = fobj->shared_count;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
u32 i = 0;
|
||||
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
old = dma_resv_get_list(obj);
|
||||
old = dma_resv_shared_list(obj);
|
||||
if (old)
|
||||
i = old->shared_count;
|
||||
|
||||
|
@ -337,26 +314,26 @@ void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
|
|||
EXPORT_SYMBOL(dma_resv_add_excl_fence);
|
||||
|
||||
/**
|
||||
* dma_resv_copy_fences - Copy all fences from src to dst.
|
||||
* @dst: the destination reservation object
|
||||
* @src: the source reservation object
|
||||
*
|
||||
* Copy all fences from src to dst. dst-lock must be held.
|
||||
*/
|
||||
* dma_resv_copy_fences - Copy all fences from src to dst.
|
||||
* @dst: the destination reservation object
|
||||
* @src: the source reservation object
|
||||
*
|
||||
* Copy all fences from src to dst. dst-lock must be held.
|
||||
*/
|
||||
int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
|
||||
{
|
||||
struct dma_resv_list *src_list, *dst_list;
|
||||
struct dma_fence *old, *new;
|
||||
unsigned i;
|
||||
unsigned int i;
|
||||
|
||||
dma_resv_assert_held(dst);
|
||||
|
||||
rcu_read_lock();
|
||||
src_list = rcu_dereference(src->fence);
|
||||
src_list = dma_resv_shared_list(src);
|
||||
|
||||
retry:
|
||||
if (src_list) {
|
||||
unsigned shared_count = src_list->shared_count;
|
||||
unsigned int shared_count = src_list->shared_count;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -365,7 +342,7 @@ retry:
|
|||
return -ENOMEM;
|
||||
|
||||
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) {
|
||||
kfree(dst_list);
|
||||
goto retry;
|
||||
|
@ -373,6 +350,7 @@ retry:
|
|||
|
||||
dst_list->shared_count = 0;
|
||||
for (i = 0; i < src_list->shared_count; ++i) {
|
||||
struct dma_fence __rcu **dst;
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference(src_list->shared[i]);
|
||||
|
@ -382,7 +360,7 @@ retry:
|
|||
|
||||
if (!dma_fence_get_rcu(fence)) {
|
||||
dma_resv_list_free(dst_list);
|
||||
src_list = rcu_dereference(src->fence);
|
||||
src_list = dma_resv_shared_list(src);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
@ -391,7 +369,8 @@ retry:
|
|||
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 {
|
||||
dst_list = NULL;
|
||||
|
@ -400,8 +379,8 @@ retry:
|
|||
new = dma_fence_get_rcu_safe(&src->fence_excl);
|
||||
rcu_read_unlock();
|
||||
|
||||
src_list = dma_resv_get_list(dst);
|
||||
old = dma_resv_get_excl(dst);
|
||||
src_list = dma_resv_shared_list(dst);
|
||||
old = dma_resv_excl_fence(dst);
|
||||
|
||||
write_seqcount_begin(&dst->seq);
|
||||
/* write_seqcount_begin provides the necessary memory barrier */
|
||||
|
@ -417,7 +396,7 @@ retry:
|
|||
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
|
||||
* @obj: the reservation object
|
||||
* @pfence_excl: the returned exclusive fence (or NULL)
|
||||
|
@ -429,10 +408,9 @@ EXPORT_SYMBOL(dma_resv_copy_fences);
|
|||
* exclusive fence is not specified the fence is put into the array of the
|
||||
* shared fences as well. Returns either zero or -ENOMEM.
|
||||
*/
|
||||
int dma_resv_get_fences_rcu(struct dma_resv *obj,
|
||||
struct dma_fence **pfence_excl,
|
||||
unsigned *pshared_count,
|
||||
struct dma_fence ***pshared)
|
||||
int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl,
|
||||
unsigned int *pshared_count,
|
||||
struct dma_fence ***pshared)
|
||||
{
|
||||
struct dma_fence **shared = NULL;
|
||||
struct dma_fence *fence_excl;
|
||||
|
@ -449,11 +427,11 @@ int dma_resv_get_fences_rcu(struct dma_resv *obj,
|
|||
rcu_read_lock();
|
||||
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))
|
||||
goto unlock;
|
||||
|
||||
fobj = rcu_dereference(obj->fence);
|
||||
fobj = dma_resv_shared_list(obj);
|
||||
if (fobj)
|
||||
sz += sizeof(*shared) * fobj->shared_max;
|
||||
|
||||
|
@ -515,27 +493,28 @@ unlock:
|
|||
*pshared = shared;
|
||||
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.
|
||||
* @obj: the reservation object
|
||||
* @wait_all: if true, wait on all fences, else wait on just exclusive fence
|
||||
* @intr: if true, do interruptible wait
|
||||
* @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 -ERESTARTSYS if interrupted, 0 if the wait timed out, or
|
||||
* greater than zer on success.
|
||||
*/
|
||||
long dma_resv_wait_timeout_rcu(struct dma_resv *obj,
|
||||
bool wait_all, bool intr,
|
||||
unsigned long timeout)
|
||||
long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr,
|
||||
unsigned long timeout)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
unsigned seq, shared_count;
|
||||
long ret = timeout ? timeout : 1;
|
||||
unsigned int seq, shared_count;
|
||||
struct dma_fence *fence;
|
||||
int i;
|
||||
|
||||
retry:
|
||||
|
@ -544,7 +523,7 @@ retry:
|
|||
rcu_read_lock();
|
||||
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 (!dma_fence_get_rcu(fence))
|
||||
goto unlock_retry;
|
||||
|
@ -559,14 +538,15 @@ retry:
|
|||
}
|
||||
|
||||
if (wait_all) {
|
||||
struct dma_resv_list *fobj = rcu_dereference(obj->fence);
|
||||
struct dma_resv_list *fobj = dma_resv_shared_list(obj);
|
||||
|
||||
if (fobj)
|
||||
shared_count = fobj->shared_count;
|
||||
|
||||
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,
|
||||
&lfence->flags))
|
||||
continue;
|
||||
|
@ -602,7 +582,7 @@ unlock_retry:
|
|||
rcu_read_unlock();
|
||||
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)
|
||||
|
@ -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
|
||||
* fences have been signaled.
|
||||
* dma_resv_test_signaled - Test if a reservation object's fences have been
|
||||
* signaled.
|
||||
* @obj: the reservation object
|
||||
* @test_all: if true, test all fences, otherwise only test the exclusive
|
||||
* fence
|
||||
*
|
||||
* Callers are not required to hold specific locks, but maybe hold
|
||||
* dma_resv_lock() already
|
||||
* RETURNS
|
||||
* 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;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -643,16 +625,16 @@ retry:
|
|||
seq = read_seqcount_begin(&obj->seq);
|
||||
|
||||
if (test_all) {
|
||||
unsigned i;
|
||||
|
||||
struct dma_resv_list *fobj = rcu_dereference(obj->fence);
|
||||
struct dma_resv_list *fobj = dma_resv_shared_list(obj);
|
||||
unsigned int i;
|
||||
|
||||
if (fobj)
|
||||
shared_count = fobj->shared_count;
|
||||
|
||||
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);
|
||||
if (ret < 0)
|
||||
goto retry;
|
||||
|
@ -665,7 +647,7 @@ retry:
|
|||
}
|
||||
|
||||
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) {
|
||||
ret = dma_resv_test_signaled_single(fence_excl);
|
||||
|
@ -680,4 +662,47 @@ retry:
|
|||
rcu_read_unlock();
|
||||
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
|
||||
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
|
||||
bool "Enable refcount backtrace history in the DP MST helpers"
|
||||
depends on STACKTRACE_SUPPORT
|
||||
|
@ -115,8 +98,18 @@ config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
|
|||
config DRM_FBDEV_EMULATION
|
||||
bool "Enable legacy fbdev support for your modesetting driver"
|
||||
depends on DRM
|
||||
depends on FB
|
||||
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
|
||||
help
|
||||
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"
|
||||
|
||||
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
|
||||
|
||||
menuconfig DRM_LEGACY
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Makefile for the drm device driver. This driver provides support for the
|
||||
# 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_drv.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_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_memory.o drm_scatter.o drm_vm.o
|
||||
drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.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_COMPAT) += drm_ioc32.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_PANEL) += drm_panel.o
|
||||
drm-$(CONFIG_OF) += drm_of.o
|
||||
drm-$(CONFIG_AGP) += drm_agpsupport.o
|
||||
drm-$(CONFIG_PCI) += drm_pci.o
|
||||
drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.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-y += xlnx/
|
||||
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 \
|
||||
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_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_atomfirmware.o \
|
||||
amdgpu_vf_error.o amdgpu_sched.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_gtt_mgr.o amdgpu_preempt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o \
|
||||
amdgpu_atomfirmware.o amdgpu_vf_error.o amdgpu_sched.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_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
|
||||
|
||||
|
@ -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 \
|
||||
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 \
|
||||
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
|
||||
amdgpu-y += \
|
||||
|
|
|
@ -227,7 +227,7 @@ static int aldebaran_mode2_restore_ip(struct amdgpu_device *adev)
|
|||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* Reinit NBIF block */
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
#include "amdgpu_gfxhub.h"
|
||||
#include "amdgpu_df.h"
|
||||
#include "amdgpu_smuio.h"
|
||||
#include "amdgpu_fdinfo.h"
|
||||
|
||||
#define MAX_GPU_INSTANCE 16
|
||||
|
||||
|
@ -129,6 +130,13 @@ struct amdgpu_mgpu_info
|
|||
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
|
||||
{
|
||||
bool timeout_fatal_disable;
|
||||
|
@ -203,6 +211,7 @@ extern int amdgpu_discovery;
|
|||
extern int amdgpu_mes;
|
||||
extern int amdgpu_noretry;
|
||||
extern int amdgpu_force_asic_type;
|
||||
extern int amdgpu_smartshift_bias;
|
||||
#ifdef CONFIG_HSA_AMD
|
||||
extern int sched_policy;
|
||||
extern bool debug_evictions;
|
||||
|
@ -260,6 +269,10 @@ extern int amdgpu_num_kcq;
|
|||
#define CIK_CURSOR_WIDTH 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_ib;
|
||||
struct amdgpu_cs_parser;
|
||||
|
@ -267,7 +280,6 @@ struct amdgpu_job;
|
|||
struct amdgpu_irq_src;
|
||||
struct amdgpu_fpriv;
|
||||
struct amdgpu_bo_va_mapping;
|
||||
struct amdgpu_atif;
|
||||
struct kfd_vm_fault_info;
|
||||
struct amdgpu_hive_info;
|
||||
struct amdgpu_reset_context;
|
||||
|
@ -681,20 +693,6 @@ struct amdgpu_vram_scratch {
|
|||
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
|
||||
*/
|
||||
|
@ -824,8 +822,6 @@ struct amdgpu_device {
|
|||
struct notifier_block acpi_nb;
|
||||
struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
|
||||
struct debugfs_blob_wrapper debugfs_vbios_blob;
|
||||
struct amdgpu_atif *atif;
|
||||
struct amdgpu_atcs atcs;
|
||||
struct mutex srbm_mutex;
|
||||
/* GRBM index mutex. Protects concurrent access to GRBM index */
|
||||
struct mutex grbm_idx_mutex;
|
||||
|
@ -1074,9 +1070,10 @@ struct amdgpu_device {
|
|||
|
||||
atomic_t throttling_logging_enabled;
|
||||
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 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,
|
||||
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);
|
||||
|
||||
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.
|
||||
*/
|
||||
#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 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_px(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_is_peer_accessible(struct amdgpu_device *adev,
|
||||
struct amdgpu_device *peer_adev);
|
||||
int amdgpu_device_baco_enter(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 */
|
||||
#if defined(CONFIG_VGA_SWITCHEROO)
|
||||
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);
|
||||
void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
||||
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_suspend(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);
|
||||
|
||||
/* 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)
|
||||
int amdgpu_acpi_init(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_power_shift_control_supported(void);
|
||||
int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
|
||||
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);
|
||||
|
||||
void amdgpu_acpi_get_backlight_caps(struct amdgpu_device *adev,
|
||||
struct amdgpu_dm_backlight_caps *caps);
|
||||
void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps);
|
||||
bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev);
|
||||
void amdgpu_acpi_detect(void);
|
||||
#else
|
||||
static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; }
|
||||
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 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
|
||||
|
||||
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_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
|
||||
*/
|
||||
/**
|
||||
* amdgpu_atif_call - call an ATIF method
|
||||
*
|
||||
* @handle: acpi handle
|
||||
* @atif: atif structure
|
||||
* @function: the ATIF function to execute
|
||||
* @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
|
||||
*
|
||||
* @handle: acpi handle
|
||||
* @atif: amdgpu atif struct
|
||||
*
|
||||
* Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function
|
||||
|
@ -208,40 +226,10 @@ out:
|
|||
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
|
||||
*
|
||||
* @handle: acpi handle
|
||||
* @n: atif notification configuration struct
|
||||
* @atif: acpi handle
|
||||
*
|
||||
* Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function
|
||||
* 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
|
||||
*
|
||||
* @handle: acpi handle
|
||||
* @atif: acpi handle
|
||||
*
|
||||
* Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function
|
||||
* to determine the acceptable range of backlight values
|
||||
|
@ -363,7 +351,7 @@ out:
|
|||
/**
|
||||
* amdgpu_atif_get_sbios_requests - get requested sbios event
|
||||
*
|
||||
* @handle: acpi handle
|
||||
* @atif: acpi handle
|
||||
* @req: atif sbios request struct
|
||||
*
|
||||
* Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function
|
||||
|
@ -416,7 +404,7 @@ out:
|
|||
static int amdgpu_atif_handler(struct amdgpu_device *adev,
|
||||
struct acpi_bus_event *event)
|
||||
{
|
||||
struct amdgpu_atif *atif = adev->atif;
|
||||
struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif;
|
||||
int count;
|
||||
|
||||
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;
|
||||
|
||||
/* Is this actually our event? */
|
||||
if (!atif ||
|
||||
!atif->notification_cfg.enabled ||
|
||||
if (!atif->notification_cfg.enabled ||
|
||||
event->type != atif->notification_cfg.command_code) {
|
||||
/* These events will generate keypresses otherwise */
|
||||
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
|
||||
*
|
||||
* @handle: acpi handle
|
||||
* @atcs: atcs structure
|
||||
* @function: the ATCS function to execute
|
||||
* @params: ATCS function params
|
||||
*
|
||||
* Executes the requested ATCS function (all asics).
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
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_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_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
|
||||
*
|
||||
* @handle: acpi handle
|
||||
* @atcs: amdgpu atcs struct
|
||||
*
|
||||
* 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).
|
||||
* returns 0 on success, error on failure.
|
||||
*/
|
||||
static int amdgpu_atcs_verify_interface(acpi_handle handle,
|
||||
struct amdgpu_atcs *atcs)
|
||||
static int amdgpu_atcs_verify_interface(struct amdgpu_atcs *atcs)
|
||||
{
|
||||
union acpi_object *info;
|
||||
struct atcs_verify_interface output;
|
||||
size_t size;
|
||||
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)
|
||||
return -EIO;
|
||||
|
||||
|
@ -605,7 +592,7 @@ out:
|
|||
*/
|
||||
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)
|
||||
return true;
|
||||
|
@ -613,6 +600,18 @@ bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *ade
|
|||
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
|
||||
*
|
||||
|
@ -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)
|
||||
{
|
||||
acpi_handle handle;
|
||||
union acpi_object *info;
|
||||
struct amdgpu_atcs *atcs = &adev->atcs;
|
||||
|
||||
/* Get the device handle */
|
||||
handle = ACPI_HANDLE(&adev->pdev->dev);
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs;
|
||||
|
||||
if (!atcs->functions.pcie_dev_rdy)
|
||||
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)
|
||||
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,
|
||||
u8 perf_req, bool advertise)
|
||||
{
|
||||
acpi_handle handle;
|
||||
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_output atcs_output;
|
||||
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))
|
||||
return -EINVAL;
|
||||
|
||||
/* Get the device handle */
|
||||
handle = ACPI_HANDLE(&adev->pdev->dev);
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
|
||||
if (!atcs->functions.pcie_perf_req)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -693,7 +680,7 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
|
|||
params.pointer = &atcs_input;
|
||||
|
||||
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)
|
||||
return -EIO;
|
||||
|
||||
|
@ -726,6 +713,96 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
|
|||
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
|
||||
*
|
||||
|
@ -769,50 +846,15 @@ static int amdgpu_acpi_event(struct notifier_block *nb,
|
|||
*/
|
||||
int amdgpu_acpi_init(struct amdgpu_device *adev)
|
||||
{
|
||||
acpi_handle handle, atif_handle;
|
||||
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;
|
||||
struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif;
|
||||
|
||||
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
|
||||
if (atif->notifications.brightness_change) {
|
||||
if (amdgpu_device_has_dc_support(adev)) {
|
||||
#if defined(CONFIG_DRM_AMD_DC)
|
||||
struct amdgpu_display_manager *dm = &adev->dm;
|
||||
atif->bd = dm->backlight_dev;
|
||||
if (dm->backlight_dev)
|
||||
atif->bd = dm->backlight_dev;
|
||||
#endif
|
||||
} else {
|
||||
struct drm_encoder *tmp;
|
||||
|
@ -834,6 +876,129 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
|
|||
}
|
||||
}
|
||||
#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) {
|
||||
/* XXX check this workraround, if sbios request function is
|
||||
|
@ -863,42 +1028,13 @@ int amdgpu_acpi_init(struct amdgpu_device *adev)
|
|||
} else {
|
||||
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
|
||||
*
|
||||
* @adev: amdgpu_device_pointer
|
||||
*
|
||||
* returns true if supported, false if not.
|
||||
*/
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
const uint32_t flush_type = 0;
|
||||
bool all_hub = false;
|
||||
|
||||
if (adev->family == AMDGPU_FAMILY_AI)
|
||||
|
|
|
@ -36,13 +36,26 @@
|
|||
|
||||
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 kfd_bo_va_list {
|
||||
struct list_head bo_list;
|
||||
struct amdgpu_bo_va *bo_va;
|
||||
void *kgd_dev;
|
||||
enum kfd_mem_attachment_type {
|
||||
KFD_MEM_ATT_SHARED, /* Share kgd_mem->bo or another attachment's */
|
||||
KFD_MEM_ATT_USERPTR, /* SG bo to DMA map pages from a userptr bo */
|
||||
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;
|
||||
struct amdgpu_bo_va *bo_va;
|
||||
struct amdgpu_device *adev;
|
||||
uint64_t va;
|
||||
uint64_t pte_flags;
|
||||
};
|
||||
|
@ -50,7 +63,8 @@ struct kfd_bo_va_list {
|
|||
struct kgd_mem {
|
||||
struct mutex lock;
|
||||
struct amdgpu_bo *bo;
|
||||
struct list_head bo_va_list;
|
||||
struct dma_buf *dmabuf;
|
||||
struct list_head attachments;
|
||||
/* protected by amdkfd_process_info.lock */
|
||||
struct ttm_validate_buffer validate_list;
|
||||
struct ttm_validate_buffer resv_list;
|
||||
|
@ -75,6 +89,7 @@ struct amdgpu_amdkfd_fence {
|
|||
struct mm_struct *mm;
|
||||
spinlock_t lock;
|
||||
char timeline_name[TASK_COMM_LEN];
|
||||
struct svm_range_bo *svm_bo;
|
||||
};
|
||||
|
||||
struct amdgpu_kfd_dev {
|
||||
|
@ -127,14 +142,15 @@ void amdgpu_amdkfd_interrupt(struct amdgpu_device *adev,
|
|||
const void *ih_ring_entry);
|
||||
void amdgpu_amdkfd_device_probe(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,
|
||||
uint32_t vmid, uint64_t gpu_addr,
|
||||
uint32_t *ib_cmd, uint32_t ib_len);
|
||||
void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle);
|
||||
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_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);
|
||||
|
||||
|
@ -148,7 +164,8 @@ int amdgpu_queue_mask_bit_to_set_resource_bit(struct amdgpu_device *adev,
|
|||
int queue_bit);
|
||||
|
||||
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)
|
||||
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);
|
||||
|
@ -234,22 +251,27 @@ uint8_t amdgpu_amdkfd_get_xgmi_hops_count(struct kgd_dev *dst, struct kgd_dev *s
|
|||
})
|
||||
|
||||
/* 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,
|
||||
struct file *filp, u32 pasid,
|
||||
void **vm, void **process_info,
|
||||
void **process_info,
|
||||
struct dma_fence **ef);
|
||||
void amdgpu_amdkfd_gpuvm_release_process_vm(struct kgd_dev *kgd, void *vm);
|
||||
uint64_t amdgpu_amdkfd_gpuvm_get_process_page_dir(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 *drm_priv);
|
||||
int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
|
||||
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);
|
||||
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(
|
||||
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(
|
||||
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(
|
||||
struct kgd_dev *kgd, struct kgd_mem *mem, bool intr);
|
||||
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);
|
||||
int amdgpu_amdkfd_gpuvm_import_dmabuf(struct kgd_dev *kgd,
|
||||
struct dma_buf *dmabuf,
|
||||
uint64_t va, void *vm,
|
||||
uint64_t va, void *drm_priv,
|
||||
struct kgd_mem **mem, uint64_t *size,
|
||||
uint64_t *mmap_offset);
|
||||
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,
|
||||
struct amdgpu_vm *vm);
|
||||
void amdgpu_amdkfd_unreserve_memory_limit(struct amdgpu_bo *bo);
|
||||
void amdgpu_amdkfd_reserve_system_mem(uint64_t size);
|
||||
#else
|
||||
static inline
|
||||
void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_amdkfd_arcturus.h"
|
||||
#include "sdma0/sdma0_4_2_2_offset.h"
|
||||
#include "sdma0/sdma0_4_2_2_sh_mask.h"
|
||||
#include "sdma1/sdma1_4_2_2_offset.h"
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "kfd_svm.h"
|
||||
|
||||
static const struct dma_fence_ops amdkfd_fence_ops;
|
||||
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 mm_struct *mm)
|
||||
struct mm_struct *mm,
|
||||
struct svm_range_bo *svm_bo)
|
||||
{
|
||||
struct amdgpu_amdkfd_fence *fence;
|
||||
|
||||
|
@ -73,7 +75,7 @@ struct amdgpu_amdkfd_fence *amdgpu_amdkfd_fence_create(u64 context,
|
|||
fence->mm = mm;
|
||||
get_task_comm(fence->timeline_name, current);
|
||||
spin_lock_init(&fence->lock);
|
||||
|
||||
fence->svm_bo = svm_bo;
|
||||
dma_fence_init(&fence->base, &amdkfd_fence_ops, &fence->lock,
|
||||
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.
|
||||
* If fence is already signaled return true.
|
||||
* 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)
|
||||
{
|
||||
|
@ -122,16 +126,20 @@ static bool amdkfd_fence_enable_signaling(struct dma_fence *f)
|
|||
if (dma_fence_is_signaled(f))
|
||||
return true;
|
||||
|
||||
if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, f))
|
||||
return true;
|
||||
|
||||
if (!fence->svm_bo) {
|
||||
if (!kgd2kfd_schedule_evict_and_restore_process(fence->mm, f))
|
||||
return true;
|
||||
} else {
|
||||
if (!svm_range_schedule_evict_svm_bo(fence))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdkfd_fence_release - callback that fence can be freed
|
||||
*
|
||||
* @fence: fence
|
||||
* @f: dma_fence
|
||||
*
|
||||
* This function is called when the reference count becomes zero.
|
||||
* 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);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(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_CONFIG, sh_mem_config);
|
||||
WREG32_SOC15(GC, 0, mmSH_MEM_BASES, sh_mem_bases);
|
||||
/* APE1 no longer exists on GFX9 */
|
||||
|
||||
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);
|
||||
|
||||
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__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;
|
||||
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. */
|
||||
data = REG_SET_FIELD(m->cp_hqd_pq_doorbell_control,
|
||||
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) {
|
||||
/* 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 += (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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__,
|
||||
(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));
|
||||
}
|
||||
|
||||
/* 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,
|
||||
CP_HQD_EOP_RPTR, INIT_FETCHER, 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);
|
||||
|
||||
|
@ -365,7 +365,7 @@ static int kgd_hqd_dump(struct kgd_dev *kgd,
|
|||
if (WARN_ON_ONCE(i >= HQD_N_REGS)) \
|
||||
break; \
|
||||
(*dump)[i][0] = (addr) << 2; \
|
||||
(*dump)[i++][1] = RREG32(addr); \
|
||||
(*dump)[i++][1] = RREG32_SOC15_IP(GC, addr); \
|
||||
} while (0)
|
||||
|
||||
*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;
|
||||
|
||||
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) {
|
||||
low = lower_32_bits(queue_address >> 8);
|
||||
high = upper_32_bits(queue_address >> 8);
|
||||
|
||||
if (low == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE)) &&
|
||||
high == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE_HI)))
|
||||
if (low == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE) &&
|
||||
high == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE_HI))
|
||||
retval = true;
|
||||
}
|
||||
release_queue(kgd);
|
||||
|
@ -621,11 +621,11 @@ loop:
|
|||
preempt_enable();
|
||||
#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;
|
||||
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))
|
||||
break;
|
||||
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);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmGRBM_GFX_INDEX), gfx_index_val);
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, mmSQ_CMD), sq_cmd);
|
||||
WREG32_SOC15(GC, 0, mmGRBM_GFX_INDEX, gfx_index_val);
|
||||
WREG32_SOC15(GC, 0, mmSQ_CMD, sq_cmd);
|
||||
|
||||
data = REG_SET_FIELD(data, GRBM_GFX_INDEX,
|
||||
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,
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(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_CONFIG, sh_mem_config);
|
||||
WREG32_SOC15(GC, 0, mmSH_MEM_BASES, sh_mem_bases);
|
||||
/* APE1 no longer exists on GFX9 */
|
||||
|
||||
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);
|
||||
|
||||
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__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",
|
||||
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,
|
||||
((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. */
|
||||
|
@ -224,13 +224,13 @@ static int hqd_load_v10_3(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
|
|||
|
||||
for (reg = hqd_base;
|
||||
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. */
|
||||
data = REG_SET_FIELD(m->cp_hqd_pq_doorbell_control,
|
||||
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) {
|
||||
/* 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 += (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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__,
|
||||
(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));
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
||||
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);
|
||||
|
||||
|
@ -350,7 +350,7 @@ static int hqd_dump_v10_3(struct kgd_dev *kgd,
|
|||
if (WARN_ON_ONCE(i >= HQD_N_REGS)) \
|
||||
break; \
|
||||
(*dump)[i][0] = (addr) << 2; \
|
||||
(*dump)[i++][1] = RREG32(addr); \
|
||||
(*dump)[i++][1] = RREG32_SOC15_IP(GC, addr); \
|
||||
} while (0)
|
||||
|
||||
*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;
|
||||
|
||||
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) {
|
||||
low = lower_32_bits(queue_address >> 8);
|
||||
high = upper_32_bits(queue_address >> 8);
|
||||
|
||||
if (low == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE)) &&
|
||||
high == RREG32(SOC15_REG_OFFSET(GC, 0, mmCP_HQD_PQ_BASE_HI)))
|
||||
if (low == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE) &&
|
||||
high == RREG32_SOC15(GC, 0, mmCP_HQD_PQ_BASE_HI))
|
||||
retval = true;
|
||||
}
|
||||
release_queue(kgd);
|
||||
|
@ -542,11 +542,11 @@ static int hqd_destroy_v10_3(struct kgd_dev *kgd, void *mqd,
|
|||
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;
|
||||
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))
|
||||
break;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
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
|
||||
* 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
|
||||
* process whose pasid is provided as a parameter. The process could have ZERO
|
||||
* or more queues running and submitting waves to compute units.
|
||||
*
|
||||
* @kgd: Handle of device from which to get number of waves in flight
|
||||
* @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
|
||||
* @max_waves_per_cu: Output parameter updated with maximum number of waves
|
||||
* 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
|
||||
* to an iaccurate wave count. Following is a high-level sequence:
|
||||
* 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,
|
||||
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
|
||||
*
|
||||
|
@ -1787,7 +1796,6 @@ void amdgpu_atombios_fini(struct amdgpu_device *adev)
|
|||
adev->mode_info.atom_context = NULL;
|
||||
kfree(adev->mode_info.atom_card_info);
|
||||
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 =
|
||||
kzalloc(sizeof(struct card_info), GFP_KERNEL);
|
||||
int ret;
|
||||
|
||||
if (!atom_card_info)
|
||||
return -ENOMEM;
|
||||
|
@ -1828,17 +1835,14 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
|
|||
if (adev->is_atom_fw) {
|
||||
amdgpu_atomfirmware_scratch_regs_init(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 {
|
||||
amdgpu_atombios_scratch_regs_init(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,23 +29,59 @@
|
|||
#include "atombios.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,
|
||||
firmwareinfo);
|
||||
uint16_t data_offset;
|
||||
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;
|
||||
|
||||
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);
|
||||
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
firmwareinfo);
|
||||
|
||||
if (le32_to_cpu(firmware_info->firmware_capability) &
|
||||
ATOM_FIRMWARE_CAP_GPU_VIRTUALIZATION)
|
||||
return true;
|
||||
if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context,
|
||||
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);
|
||||
fw_cap = le32_to_cpu(firmware_info->v31.firmware_capability);
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
@ -400,41 +436,36 @@ bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev)
|
|||
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
|
||||
*/
|
||||
bool amdgpu_atomfirmware_sram_ecc_supported(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_mode_info *mode_info = &adev->mode_info;
|
||||
int index;
|
||||
u16 data_offset, size;
|
||||
union firmware_info *firmware_info;
|
||||
u8 frev, crev;
|
||||
bool sram_ecc_supported = false;
|
||||
u32 fw_cap;
|
||||
|
||||
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
firmwareinfo);
|
||||
fw_cap = adev->mode_info.firmware_flags;
|
||||
|
||||
if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context,
|
||||
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 (fw_cap & 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 {
|
||||
|
@ -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_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;
|
||||
}
|
||||
|
||||
|
@ -519,6 +546,21 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
int index;
|
||||
u32 fw_cap;
|
||||
|
||||
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
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);
|
||||
fw_cap = adev->mode_info.firmware_flags;
|
||||
|
||||
DRM_DEBUG("atom firmware capability:0x%08x.\n",
|
||||
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;
|
||||
return (fw_cap & ATOM_FIRMWARE_CAP_ENABLE_2STAGE_BIST_TRAINING) ? true : false;
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
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);
|
||||
int amdgpu_atomfirmware_allocate_fb_scratch(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);
|
||||
bool amdgpu_atomfirmware_mem_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_mem_train_support(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -396,10 +396,10 @@ void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes,
|
|||
spin_unlock(&adev->mm_stats.lock);
|
||||
}
|
||||
|
||||
static int amdgpu_cs_bo_validate(struct amdgpu_cs_parser *p,
|
||||
struct amdgpu_bo *bo)
|
||||
static int amdgpu_cs_bo_validate(void *param, struct amdgpu_bo *bo)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
struct amdgpu_cs_parser *p = param;
|
||||
struct ttm_operation_ctx ctx = {
|
||||
.interruptible = true,
|
||||
.no_wait_gpu = false,
|
||||
|
@ -451,21 +451,6 @@ retry:
|
|||
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,
|
||||
struct list_head *validated)
|
||||
{
|
||||
|
@ -493,7 +478,7 @@ static int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p,
|
|||
lobj->user_pages);
|
||||
}
|
||||
|
||||
r = amdgpu_cs_validate(p, bo);
|
||||
r = amdgpu_cs_bo_validate(p, bo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -593,7 +578,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
|||
p->bytes_moved_vis = 0;
|
||||
|
||||
r = amdgpu_vm_validate_pt_bos(p->adev, &fpriv->vm,
|
||||
amdgpu_cs_validate, p);
|
||||
amdgpu_cs_bo_validate, p);
|
||||
if (r) {
|
||||
DRM_ERROR("amdgpu_vm_validate_pt_bos() failed.\n");
|
||||
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.
|
||||
* @error: error number
|
||||
* @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.
|
||||
**/
|
||||
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)
|
||||
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)
|
||||
return r;
|
||||
|
||||
|
@ -807,7 +792,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
|||
if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) {
|
||||
bo_va = fpriv->csa_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)
|
||||
return r;
|
||||
|
||||
|
@ -826,7 +811,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
|||
if (bo_va == NULL)
|
||||
continue;
|
||||
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false);
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -847,7 +832,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
|||
if (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) {
|
||||
/* 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
|
||||
* @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
|
||||
* @addr: VM address
|
||||
|
|
|
@ -331,10 +331,13 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define AMDGPU_RAS_COUNTE_DELAY_MS 3000
|
||||
|
||||
static int amdgpu_ctx_query2(struct amdgpu_device *adev,
|
||||
struct amdgpu_fpriv *fpriv, uint32_t id,
|
||||
union drm_amdgpu_ctx_out *out)
|
||||
struct amdgpu_fpriv *fpriv, uint32_t id,
|
||||
union drm_amdgpu_ctx_out *out)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct amdgpu_ctx *ctx;
|
||||
struct amdgpu_ctx_mgr *mgr;
|
||||
|
||||
|
@ -361,6 +364,30 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev,
|
|||
if (atomic_read(&ctx->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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -635,3 +662,81 @@ void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
|
|||
idr_destroy(&mgr->ctx_handles);
|
||||
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;
|
||||
|
||||
#define AMDGPU_MAX_ENTITY_NUM 4
|
||||
#define AMDGPU_CTX_FENCE_USAGE_MIN_RATIO(max, total) ((max) > 16384ULL*(total))
|
||||
|
||||
struct amdgpu_ctx_entity {
|
||||
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);
|
||||
long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout);
|
||||
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
|
||||
|
|
|
@ -990,7 +990,7 @@ err:
|
|||
}
|
||||
|
||||
/**
|
||||
* amdgpu_debugfs_regs_gfxoff_write - Enable/disable GFXOFF
|
||||
* amdgpu_debugfs_gfxoff_write - Enable/disable GFXOFF
|
||||
*
|
||||
* @f: open file handle
|
||||
* @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
|
||||
* @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",
|
||||
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)
|
||||
break;
|
||||
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);
|
||||
|
|
|
@ -71,6 +71,8 @@
|
|||
#include <drm/task_barrier.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/vega12_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/navi12_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/vangogh_gpu_info.bin");
|
||||
MODULE_FIRMWARE("amdgpu/yellow_carp_gpu_info.bin");
|
||||
|
||||
#define AMDGPU_RESUME_MS 2000
|
||||
|
||||
|
@ -119,6 +122,8 @@ const char *amdgpu_asic_name[] = {
|
|||
"NAVY_FLOUNDER",
|
||||
"VANGOGH",
|
||||
"DIMGREY_CAVEFISH",
|
||||
"BEIGE_GOBY",
|
||||
"YELLOW_CARP",
|
||||
"LAST",
|
||||
};
|
||||
|
||||
|
@ -262,6 +267,21 @@ bool amdgpu_device_supports_baco(struct drm_device *dev)
|
|||
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
|
||||
*/
|
||||
|
@ -281,7 +301,10 @@ void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos,
|
|||
unsigned long flags;
|
||||
uint32_t hi = ~0;
|
||||
uint64_t last;
|
||||
int idx;
|
||||
|
||||
if (!drm_dev_enter(&adev->ddev, &idx))
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
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) {
|
||||
memcpy_toio(addr, buf, count);
|
||||
mb();
|
||||
amdgpu_asic_flush_hdp(adev, NULL);
|
||||
amdgpu_device_flush_hdp(adev, NULL);
|
||||
} else {
|
||||
amdgpu_asic_invalidate_hdp(adev, NULL);
|
||||
amdgpu_device_invalidate_hdp(adev, NULL);
|
||||
mb();
|
||||
memcpy_fromio(buf, addr, count);
|
||||
}
|
||||
|
||||
if (count == size)
|
||||
return;
|
||||
goto exit;
|
||||
|
||||
pos += count;
|
||||
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);
|
||||
}
|
||||
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 */
|
||||
bool amdgpu_device_skip_hw_access(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->in_pci_err_recovery)
|
||||
if (adev->no_hw_access)
|
||||
return true;
|
||||
|
||||
#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->is_rlcg_access_range) {
|
||||
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 {
|
||||
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_NAVY_FLOUNDER:
|
||||
case CHIP_DIMGREY_CAVEFISH:
|
||||
case CHIP_BEIGE_GOBY:
|
||||
default:
|
||||
return 0;
|
||||
case CHIP_VEGA10:
|
||||
|
@ -1857,6 +1886,9 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
|
|||
case CHIP_VANGOGH:
|
||||
chip_name = "vangogh";
|
||||
break;
|
||||
case CHIP_YELLOW_CARP:
|
||||
chip_name = "yellow_carp";
|
||||
break;
|
||||
}
|
||||
|
||||
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_NAVY_FLOUNDER:
|
||||
case CHIP_DIMGREY_CAVEFISH:
|
||||
case CHIP_BEIGE_GOBY:
|
||||
case CHIP_VANGOGH:
|
||||
case CHIP_YELLOW_CARP:
|
||||
if (adev->asic_type == CHIP_VANGOGH)
|
||||
adev->family = AMDGPU_FAMILY_VGH;
|
||||
else if (adev->asic_type == CHIP_YELLOW_CARP)
|
||||
adev->family = AMDGPU_FAMILY_YC;
|
||||
else
|
||||
adev->family = AMDGPU_FAMILY_NV;
|
||||
|
||||
|
@ -2571,34 +2607,26 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev)
|
|||
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)
|
||||
static int amdgpu_device_ip_fini_early(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);
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
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_xgmi_remove_device(adev);
|
||||
amdgpu_amdkfd_suspend(adev, false);
|
||||
|
||||
amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
|
||||
amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
|
||||
|
||||
amdgpu_amdkfd_device_fini(adev);
|
||||
|
||||
/* need to disable SMC first */
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
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;
|
||||
}
|
||||
|
||||
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--) {
|
||||
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,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ip_order); i++) {
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
int j;
|
||||
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 (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;
|
||||
} else {
|
||||
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_NAVY_FLOUNDER:
|
||||
case CHIP_DIMGREY_CAVEFISH:
|
||||
case CHIP_BEIGE_GOBY:
|
||||
case CHIP_VANGOGH:
|
||||
case CHIP_YELLOW_CARP:
|
||||
#endif
|
||||
return amdgpu_dc != 0;
|
||||
#endif
|
||||
|
@ -3181,8 +3238,8 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
|
|||
int ret = 0;
|
||||
|
||||
/*
|
||||
* By default timeout for non compute jobs is 10000.
|
||||
* And there is no timeout enforced on compute jobs.
|
||||
* By default timeout for non compute jobs is 10000
|
||||
* and 60000 for compute jobs.
|
||||
* In SR-IOV or passthrough mode, timeout for compute
|
||||
* 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))
|
||||
adev->compute_timeout = amdgpu_sriov_is_pp_one_vf(adev) ?
|
||||
msecs_to_jiffies(60000) : msecs_to_jiffies(10000);
|
||||
else if (amdgpu_passthrough(adev))
|
||||
adev->compute_timeout = msecs_to_jiffies(60000);
|
||||
else
|
||||
adev->compute_timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
adev->compute_timeout = msecs_to_jiffies(60000);
|
||||
|
||||
if (strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
|
||||
while ((timeout_setting = strsep(&input, ",")) &&
|
||||
|
@ -3251,7 +3306,6 @@ static const struct attribute *amdgpu_dev_attributes[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* amdgpu_device_init - initialize the driver
|
||||
*
|
||||
|
@ -3653,6 +3707,27 @@ failed_unmap:
|
|||
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
|
||||
*
|
||||
|
@ -3661,15 +3736,13 @@ failed_unmap:
|
|||
* Tear down the driver info (all asics).
|
||||
* 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");
|
||||
flush_delayed_work(&adev->delayed_init_work);
|
||||
ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
|
||||
adev->shutdown = true;
|
||||
|
||||
kfree(adev->pci_state);
|
||||
|
||||
/* make sure IB test finished before entering exclusive mode
|
||||
* to avoid preemption on IB test
|
||||
* */
|
||||
|
@ -3686,11 +3759,29 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
|
|||
else
|
||||
drm_atomic_helper_shutdown(adev_to_drm(adev));
|
||||
}
|
||||
amdgpu_fence_driver_fini(adev);
|
||||
amdgpu_fence_driver_fini_hw(adev);
|
||||
|
||||
if (adev->pm_sysfs_en)
|
||||
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_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_fence_driver_fini_sw(adev);
|
||||
release_firmware(adev->firmware.gpu_info_fw);
|
||||
adev->firmware.gpu_info_fw = NULL;
|
||||
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)
|
||||
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))
|
||||
amdgpu_pmu_fini(adev);
|
||||
if (adev->mman.discovery_bin)
|
||||
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)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
int r;
|
||||
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
|
||||
if (fbcon)
|
||||
|
@ -3758,7 +3848,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
|
|||
|
||||
amdgpu_ras_suspend(adev);
|
||||
|
||||
r = amdgpu_device_ip_suspend_phase1(adev);
|
||||
amdgpu_device_ip_suspend_phase1(adev);
|
||||
|
||||
if (!adev->in_s0ix)
|
||||
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);
|
||||
|
||||
r = amdgpu_device_ip_suspend_phase2(adev);
|
||||
amdgpu_device_ip_suspend_phase2(adev);
|
||||
/* evict remaining vram memory
|
||||
* This second call to evict vram is to evict the gart page table
|
||||
* using the CPU.
|
||||
|
@ -3858,6 +3948,9 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon)
|
|||
#endif
|
||||
adev->in_suspend = false;
|
||||
|
||||
if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D0))
|
||||
DRM_WARN("smart shift update failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4031,6 +4124,7 @@ static int amdgpu_device_recover_vram(struct amdgpu_device *adev)
|
|||
{
|
||||
struct dma_fence *fence = NULL, *next = NULL;
|
||||
struct amdgpu_bo *shadow;
|
||||
struct amdgpu_bo_vm *vmbo;
|
||||
long r = 1, tmo;
|
||||
|
||||
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");
|
||||
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 */
|
||||
if (shadow->tbo.mem.mem_type != TTM_PL_TT ||
|
||||
shadow->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET ||
|
||||
shadow->parent->tbo.mem.mem_type != TTM_PL_VRAM)
|
||||
if (shadow->tbo.resource->mem_type != TTM_PL_TT ||
|
||||
shadow->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET ||
|
||||
shadow->parent->tbo.resource->mem_type != TTM_PL_VRAM)
|
||||
continue;
|
||||
|
||||
r = amdgpu_bo_restore_shadow(shadow, &next);
|
||||
|
@ -4634,7 +4728,7 @@ static int amdgpu_device_suspend_display_audio(struct amdgpu_device *adev)
|
|||
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_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);
|
||||
} else {
|
||||
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)))
|
||||
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);
|
||||
|
||||
return amdgpu_dpm_baco_enter(adev);
|
||||
|
@ -5144,7 +5241,8 @@ int amdgpu_device_baco_exit(struct drm_device *dev)
|
|||
if (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);
|
||||
|
||||
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_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);
|
||||
adev->in_pci_err_recovery = false;
|
||||
adev->no_hw_access = false;
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
|
@ -5387,4 +5485,31 @@ bool amdgpu_device_load_pci_state(struct pci_dev *pdev)
|
|||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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++) {
|
||||
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)
|
||||
*major = ip->major;
|
||||
if (minor)
|
||||
|
@ -373,6 +373,14 @@ int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id,
|
|||
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)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
void amdgpu_discovery_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_discovery_reg_base_init(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 amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev);
|
||||
|
||||
#endif /* __AMDGPU_DISCOVERY__ */
|
||||
|
|
|
@ -203,9 +203,8 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
|
|||
goto unpin;
|
||||
}
|
||||
|
||||
r = dma_resv_get_fences_rcu(new_abo->tbo.base.resv, &work->excl,
|
||||
&work->shared_count,
|
||||
&work->shared);
|
||||
r = dma_resv_get_fences(new_abo->tbo.base.resv, &work->excl,
|
||||
&work->shared_count, &work->shared);
|
||||
if (unlikely(r != 0)) {
|
||||
DRM_ERROR("failed to get fences for buffer\n");
|
||||
goto unpin;
|
||||
|
@ -1075,12 +1074,9 @@ int amdgpu_display_gem_fb_verify_and_init(
|
|||
/* Verify that the modifier is supported. */
|
||||
if (!drm_any_plane_has_format(dev, mode_cmd->pixel_format,
|
||||
mode_cmd->modifier[0])) {
|
||||
struct drm_format_name_buf format_name;
|
||||
drm_dbg_kms(dev,
|
||||
"unsupported pixel format %s / modifier 0x%llx\n",
|
||||
drm_get_format_name(mode_cmd->pixel_format,
|
||||
&format_name),
|
||||
mode_cmd->modifier[0]);
|
||||
"unsupported pixel format %p4cc / modifier 0x%llx\n",
|
||||
&mode_cmd->pixel_format, mode_cmd->modifier[0]);
|
||||
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
|
|
|
@ -42,52 +42,6 @@
|
|||
#include <linux/pci-p2pdma.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
|
||||
__dma_resv_make_exclusive(struct dma_resv *obj)
|
||||
{
|
||||
|
@ -95,10 +49,10 @@ __dma_resv_make_exclusive(struct dma_resv *obj)
|
|||
unsigned int count;
|
||||
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;
|
||||
|
||||
r = dma_resv_get_fences_rcu(obj, NULL, &count, &fences);
|
||||
r = dma_resv_get_fences(obj, NULL, &count, &fences);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -284,12 +238,12 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
|
|||
if (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)) {
|
||||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
switch (bo->tbo.mem.mem_type) {
|
||||
switch (bo->tbo.resource->mem_type) {
|
||||
case TTM_PL_TT:
|
||||
sgt = drm_prime_pages_to_sg(obj->dev,
|
||||
bo->tbo.ttm->pages,
|
||||
|
@ -303,8 +257,9 @@ static struct sg_table *amdgpu_dma_buf_map(struct dma_buf_attachment *attach,
|
|||
break;
|
||||
|
||||
case TTM_PL_VRAM:
|
||||
r = amdgpu_vram_mgr_alloc_sgt(adev, &bo->tbo.mem, 0,
|
||||
bo->tbo.base.size, attach->dev, dir, &sgt);
|
||||
r = amdgpu_vram_mgr_alloc_sgt(adev, bo->tbo.resource, 0,
|
||||
bo->tbo.base.size, attach->dev,
|
||||
dir, &sgt);
|
||||
if (r)
|
||||
return ERR_PTR(r);
|
||||
break;
|
||||
|
@ -494,7 +449,7 @@ amdgpu_dma_buf_move_notify(struct dma_buf_attachment *attach)
|
|||
struct amdgpu_vm_bo_base *bo_base;
|
||||
int r;
|
||||
|
||||
if (bo->tbo.mem.mem_type == TTM_PL_SYSTEM)
|
||||
if (bo->tbo.resource->mem_type == TTM_PL_SYSTEM)
|
||||
return;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
/* 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);
|
||||
bool amdgpu_dmabuf_is_xgmi_accessible(struct amdgpu_device *adev,
|
||||
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;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_aperture.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
@ -42,7 +43,7 @@
|
|||
#include "amdgpu_irq.h"
|
||||
#include "amdgpu_dma_buf.h"
|
||||
#include "amdgpu_sched.h"
|
||||
|
||||
#include "amdgpu_fdinfo.h"
|
||||
#include "amdgpu_amdkfd.h"
|
||||
|
||||
#include "amdgpu_ras.h"
|
||||
|
@ -94,9 +95,10 @@
|
|||
* - 3.39.0 - DMABUF implicit sync does a full pipeline sync
|
||||
* - 3.40.0 - Add AMDGPU_IDS_FLAGS_TMZ
|
||||
* - 3.41.0 - Add video codec query
|
||||
* - 3.42.0 - Add 16bpc fixed point display support
|
||||
*/
|
||||
#define KMS_DRIVER_MAJOR 3
|
||||
#define KMS_DRIVER_MINOR 41
|
||||
#define KMS_DRIVER_MINOR 42
|
||||
#define KMS_DRIVER_PATCHLEVEL 0
|
||||
|
||||
int amdgpu_vram_limit;
|
||||
|
@ -171,6 +173,7 @@ int amdgpu_tmz = -1; /* auto */
|
|||
uint amdgpu_freesync_vid_mode;
|
||||
int amdgpu_reset_method = -1; /* auto */
|
||||
int amdgpu_num_kcq = -1;
|
||||
int amdgpu_smartshift_bias;
|
||||
|
||||
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.
|
||||
*
|
||||
* 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."
|
||||
" 0: keep default value. negative: infinity timeout), "
|
||||
"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)
|
||||
* 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))
|
||||
*/
|
||||
MODULE_PARM_DESC(noretry,
|
||||
|
@ -833,8 +837,23 @@ module_param_named(tmz, amdgpu_tmz, int, 0444);
|
|||
|
||||
/**
|
||||
* DOC: freesync_video (uint)
|
||||
* Enabled the optimization to adjust front porch timing to achieve seamless mode change experience
|
||||
* when setting a freesync supported mode for which full modeset is not needed.
|
||||
* Enable the optimization to adjust front porch timing to achieve seamless
|
||||
* 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).
|
||||
*/
|
||||
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, 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, 0x7410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN|AMD_EXP_HW_SUPPORT},
|
||||
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
@ -1258,7 +1278,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
|
|||
#endif
|
||||
|
||||
/* 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)
|
||||
return ret;
|
||||
|
||||
|
@ -1310,14 +1330,16 @@ amdgpu_pci_remove(struct pci_dev *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);
|
||||
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_set_drvdata(pdev, NULL);
|
||||
pci_wait_for_pending_transaction(pdev);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1552,6 +1574,10 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
|
|||
if (!adev->runpm)
|
||||
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)) {
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
|
||||
|
@ -1597,17 +1623,15 @@ static int amdgpu_pmops_runtime_idle(struct device *dev)
|
|||
if (amdgpu_device_has_dc_support(adev)) {
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
drm_modeset_lock_all(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;
|
||||
drm_modeset_unlock(&crtc->mutex);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drm_modeset_unlock_all(drm_dev);
|
||||
|
||||
} else {
|
||||
struct drm_connector *list_connector;
|
||||
struct drm_connector_list_iter iter;
|
||||
|
@ -1688,12 +1712,15 @@ static const struct file_operations amdgpu_driver_kms_fops = {
|
|||
.flush = amdgpu_flush,
|
||||
.release = drm_release,
|
||||
.unlocked_ioctl = amdgpu_drm_ioctl,
|
||||
.mmap = amdgpu_mmap,
|
||||
.mmap = drm_gem_mmap,
|
||||
.poll = drm_poll,
|
||||
.read = drm_read,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = amdgpu_kms_compat_ioctl,
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
.show_fdinfo = amdgpu_show_fdinfo
|
||||
#endif
|
||||
};
|
||||
|
||||
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_map_offset = amdgpu_mode_dumb_mmap,
|
||||
.fops = &amdgpu_driver_kms_fops,
|
||||
.release = &amdgpu_driver_release_kms,
|
||||
|
||||
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_import = amdgpu_gem_prime_import,
|
||||
.gem_prime_mmap = amdgpu_gem_prime_mmap,
|
||||
.gem_prime_mmap = drm_gem_prime_mmap,
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
|
@ -1768,6 +1796,18 @@ static struct pci_error_handlers amdgpu_pci_err_handler = {
|
|||
.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 = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
|
@ -1776,6 +1816,7 @@ static struct pci_driver amdgpu_kms_pci_driver = {
|
|||
.shutdown = amdgpu_pci_shutdown,
|
||||
.driver.pm = &amdgpu_pm_ops,
|
||||
.err_handler = &amdgpu_pci_err_handler,
|
||||
.dev_groups = amdgpu_sysfs_groups,
|
||||
};
|
||||
|
||||
static int __init amdgpu_init(void)
|
||||
|
@ -1797,6 +1838,7 @@ static int __init amdgpu_init(void)
|
|||
|
||||
DRM_INFO("amdgpu kernel modesetting enabled.\n");
|
||||
amdgpu_register_atpx_handler();
|
||||
amdgpu_acpi_detect();
|
||||
|
||||
/* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */
|
||||
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/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include "amdgpu.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
|
||||
* @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).
|
||||
* 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).
|
||||
*/
|
||||
void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
|
||||
void amdgpu_fence_driver_fini_hw(struct amdgpu_device *adev)
|
||||
{
|
||||
unsigned i, j;
|
||||
int r;
|
||||
int i, r;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
|
||||
struct amdgpu_ring *ring = adev->rings[i];
|
||||
|
@ -535,16 +536,33 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
|
|||
continue;
|
||||
if (!ring->no_scheduler)
|
||||
drm_sched_fini(&ring->sched);
|
||||
r = amdgpu_fence_wait_empty(ring);
|
||||
if (r) {
|
||||
/* no need to trigger GPU reset as we are unloading */
|
||||
/* 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);
|
||||
else
|
||||
r = -ENODEV;
|
||||
/* no need to trigger GPU reset as we are unloading */
|
||||
if (r)
|
||||
amdgpu_fence_driver_force_completion(ring);
|
||||
}
|
||||
|
||||
if (ring->fence_drv.irq_src)
|
||||
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
|
||||
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)
|
||||
dma_fence_put(ring->fence_drv.fences[j]);
|
||||
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)
|
||||
{
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return 0;
|
||||
|
||||
if (adev->asic_type >= CHIP_SIENNA_CICHLID)
|
||||
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
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
* 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)
|
||||
return;
|
||||
|
@ -250,7 +250,7 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
|
|||
}
|
||||
}
|
||||
mb();
|
||||
amdgpu_asic_flush_hdp(adev, NULL);
|
||||
amdgpu_device_flush_hdp(adev, NULL);
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
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
|
||||
* @offset: offset into the GPU's gart aperture
|
||||
* @pages: number of pages to bind
|
||||
* @pagelist: pages to bind
|
||||
* @dma_addr: DMA addresses of pages
|
||||
* @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.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
int r, i;
|
||||
|
||||
if (!adev->gart.ready) {
|
||||
WARN(1, "trying to bind memory to uninitialized GART !\n");
|
||||
return -EINVAL;
|
||||
|
@ -322,16 +319,26 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
|
|||
if (!adev->gart.ptr)
|
||||
return 0;
|
||||
|
||||
r = amdgpu_gart_map(adev, offset, pages, dma_addr, flags,
|
||||
adev->gart.ptr);
|
||||
if (r)
|
||||
return r;
|
||||
return amdgpu_gart_map(adev, offset, pages, dma_addr, flags,
|
||||
adev->gart.ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
amdgpu_asic_flush_hdp(adev, NULL);
|
||||
amdgpu_device_flush_hdp(adev, NULL);
|
||||
for (i = 0; i < adev->num_vmhubs; i++)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
void amdgpu_gart_table_vram_unpin(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 pages);
|
||||
int amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset,
|
||||
int pages, dma_addr_t *dma_addr, uint64_t flags,
|
||||
void *dst);
|
||||
int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
|
||||
int pages, struct page **pagelist,
|
||||
dma_addr_t *dma_addr, uint64_t flags);
|
||||
|
||||
int pages, dma_addr_t *dma_addr, uint64_t flags);
|
||||
void amdgpu_gart_invalidate_tlb(struct amdgpu_device *adev);
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/dma-buf.h>
|
||||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_gem_ttm_helper.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
|
@ -41,6 +42,46 @@
|
|||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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))
|
||||
goto out_unlock;
|
||||
|
||||
fence = dma_resv_get_excl(bo->tbo.base.resv);
|
||||
fence = dma_resv_excl_fence(bo->tbo.base.resv);
|
||||
if (fence) {
|
||||
amdgpu_bo_fence(bo, fence, true);
|
||||
fence = NULL;
|
||||
|
@ -205,6 +246,18 @@ out_unlock:
|
|||
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 = {
|
||||
.free = amdgpu_gem_object_free,
|
||||
.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,
|
||||
.vmap = drm_gem_ttm_vmap,
|
||||
.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) {
|
||||
r = amdgpu_bo_reserve(vm->root.base.bo, false);
|
||||
r = amdgpu_bo_reserve(vm->root.bo, false);
|
||||
if (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);
|
||||
|
@ -298,9 +353,9 @@ retry:
|
|||
if (!r) {
|
||||
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)
|
||||
return r;
|
||||
|
@ -471,8 +526,7 @@ int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
|
|||
return -ENOENT;
|
||||
}
|
||||
robj = gem_to_amdgpu_bo(gobj);
|
||||
ret = dma_resv_wait_timeout_rcu(robj->tbo.base.resv, true, true,
|
||||
timeout);
|
||||
ret = dma_resv_wait_timeout(robj->tbo.base.resv, true, true, timeout);
|
||||
|
||||
/* ret == 0 means not 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 ||
|
||||
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)
|
||||
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);
|
||||
|
||||
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.domain_flags = robj->flags;
|
||||
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)
|
||||
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;
|
||||
amdgpu_bo_unreserve(robj);
|
||||
goto out;
|
||||
|
|
|
@ -607,7 +607,6 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev)
|
|||
struct ras_ih_if ih_info = {
|
||||
.cb = amdgpu_gfx_process_ras_data_cb,
|
||||
};
|
||||
struct ras_query_if info = { 0 };
|
||||
|
||||
if (!adev->gfx.ras_if) {
|
||||
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;
|
||||
|
||||
if (amdgpu_ras_is_supported(adev, adev->gfx.ras_if->block)) {
|
||||
if (adev->gmc.xgmi.connected_to_cpu) {
|
||||
info.head = *adev->gfx.ras_if;
|
||||
amdgpu_ras_query_error_status(adev, &info);
|
||||
} else {
|
||||
if (!amdgpu_persistent_edc_harvesting_supported(adev))
|
||||
amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX);
|
||||
}
|
||||
|
||||
r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
|
||||
if (r)
|
||||
|
|
|
@ -34,6 +34,7 @@ struct amdgpu_gfxhub_funcs {
|
|||
void (*set_fault_enable_default)(struct amdgpu_device *adev, bool value);
|
||||
void (*init)(struct amdgpu_device *adev);
|
||||
int (*get_xgmi_info)(struct amdgpu_device *adev);
|
||||
void (*utcl2_harvest)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_gfxhub {
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_xgmi.h"
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
switch (bo->tbo.mem.mem_type) {
|
||||
switch (bo->tbo.resource->mem_type) {
|
||||
case TTM_PL_TT:
|
||||
*addr = bo->tbo.ttm->dma_address[0];
|
||||
break;
|
||||
|
@ -110,7 +112,7 @@ void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level,
|
|||
*addr = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
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.
|
||||
|
@ -158,6 +164,9 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
|
|||
value = addr & 0x0000FFFFFFFFF000ULL;
|
||||
value |= flags;
|
||||
writeq(value, ptr + (gpu_page_idx * 8));
|
||||
|
||||
drm_dev_exit(idx);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -348,8 +368,7 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
|
|||
uint16_t pasid, uint64_t timestamp)
|
||||
{
|
||||
struct amdgpu_gmc *gmc = &adev->gmc;
|
||||
|
||||
uint64_t stamp, key = addr << 4 | pasid;
|
||||
uint64_t stamp, key = amdgpu_gmc_fault_key(addr, pasid);
|
||||
struct amdgpu_gmc_fault *fault;
|
||||
uint32_t hash;
|
||||
|
||||
|
@ -365,7 +384,7 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
|
|||
while (fault->timestamp >= stamp) {
|
||||
uint64_t tmp;
|
||||
|
||||
if (fault->key == key)
|
||||
if (atomic64_read(&fault->key) == key)
|
||||
return true;
|
||||
|
||||
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 */
|
||||
fault = &gmc->fault_ring[gmc->last_fault];
|
||||
fault->key = key;
|
||||
atomic64_set(&fault->key, key);
|
||||
fault->timestamp = timestamp;
|
||||
|
||||
/* And update the hash */
|
||||
|
@ -387,6 +406,36 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
|
|||
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 r;
|
||||
|
@ -415,6 +464,13 @@ int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -426,11 +482,15 @@ void amdgpu_gmc_ras_fini(struct amdgpu_device *adev)
|
|||
|
||||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->ras_fini)
|
||||
amdgpu_mmhub_ras_fini(adev);
|
||||
adev->mmhub.ras_funcs->ras_fini(adev);
|
||||
|
||||
if (adev->gmc.xgmi.ras_funcs &&
|
||||
adev->gmc.xgmi.ras_funcs->ras_fini)
|
||||
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
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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++) {
|
||||
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)
|
||||
tmp |= hub->vm_cntx_cntl_vm_fault;
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
struct amdgpu_gmc_fault {
|
||||
uint64_t timestamp;
|
||||
uint64_t timestamp:48;
|
||||
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);
|
||||
bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
|
||||
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);
|
||||
void amdgpu_gmc_ras_fini(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);
|
||||
|
||||
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);
|
||||
uint64_t amdgpu_gmc_vram_mc2pa(struct amdgpu_device *adev, uint64_t mc_addr);
|
||||
|
|
|
@ -22,17 +22,26 @@
|
|||
* Authors: Christian König
|
||||
*/
|
||||
|
||||
#include <drm/ttm/ttm_range_manager.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);
|
||||
}
|
||||
|
||||
struct amdgpu_gtt_node {
|
||||
struct drm_mm_node node;
|
||||
struct ttm_buffer_object *tbo;
|
||||
};
|
||||
static inline struct amdgpu_gtt_node *
|
||||
to_amdgpu_gtt_node(struct ttm_resource *res)
|
||||
{
|
||||
return container_of(res, struct amdgpu_gtt_node, base.base);
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: mem_info_gtt_total
|
||||
|
@ -43,12 +52,14 @@ struct amdgpu_gtt_node {
|
|||
* the GTT block, in bytes
|
||||
*/
|
||||
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 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);
|
||||
}
|
||||
|
||||
|
@ -61,12 +72,14 @@ static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev,
|
|||
* size of the GTT block, in bytes
|
||||
*/
|
||||
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 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));
|
||||
}
|
||||
|
||||
|
@ -75,90 +88,28 @@ static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
|
|||
static DEVICE_ATTR(mem_info_gtt_used, S_IRUGO,
|
||||
amdgpu_mem_info_gtt_used_show, NULL);
|
||||
|
||||
static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func;
|
||||
/**
|
||||
* 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;
|
||||
int ret;
|
||||
static struct attribute *amdgpu_gtt_mgr_attributes[] = {
|
||||
&dev_attr_mem_info_gtt_total.attr,
|
||||
&dev_attr_mem_info_gtt_used.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
const struct attribute_group amdgpu_gtt_mgr_attr_group = {
|
||||
.attrs = amdgpu_gtt_mgr_attributes
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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,
|
||||
struct ttm_buffer_object *tbo,
|
||||
const struct ttm_place *place,
|
||||
struct ttm_resource *mem)
|
||||
struct ttm_resource **res)
|
||||
{
|
||||
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
|
||||
uint32_t num_pages = PFN_UP(tbo->base.size);
|
||||
struct amdgpu_gtt_node *node;
|
||||
int r;
|
||||
|
||||
spin_lock(&mgr->lock);
|
||||
if ((&tbo->mem == mem || tbo->mem.mem_type != TTM_PL_TT) &&
|
||||
atomic64_read(&mgr->available) < mem->num_pages) {
|
||||
if (tbo->resource && tbo->resource->mem_type != TTM_PL_TT &&
|
||||
atomic64_read(&mgr->available) < num_pages) {
|
||||
spin_unlock(&mgr->lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
atomic64_sub(mem->num_pages, &mgr->available);
|
||||
atomic64_sub(num_pages, &mgr->available);
|
||||
spin_unlock(&mgr->lock);
|
||||
|
||||
if (!place->lpfn) {
|
||||
mem->mm_node = NULL;
|
||||
mem->start = AMDGPU_BO_INVALID_OFFSET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||||
node = kzalloc(struct_size(node, base.mm_nodes, 1), GFP_KERNEL);
|
||||
if (!node) {
|
||||
r = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
node->tbo = tbo;
|
||||
ttm_resource_init(tbo, place, &node->base.base);
|
||||
|
||||
spin_lock(&mgr->lock);
|
||||
r = drm_mm_insert_node_in_range(&mgr->mm, &node->node, mem->num_pages,
|
||||
mem->page_alignment, 0, place->fpfn,
|
||||
place->lpfn, DRM_MM_INSERT_BEST);
|
||||
spin_unlock(&mgr->lock);
|
||||
if (place->lpfn) {
|
||||
spin_lock(&mgr->lock);
|
||||
r = drm_mm_insert_node_in_range(&mgr->mm,
|
||||
&node->base.mm_nodes[0],
|
||||
num_pages, tbo->page_alignment,
|
||||
0, place->fpfn, place->lpfn,
|
||||
DRM_MM_INSERT_BEST);
|
||||
spin_unlock(&mgr->lock);
|
||||
if (unlikely(r))
|
||||
goto err_free;
|
||||
|
||||
if (unlikely(r))
|
||||
goto err_free;
|
||||
|
||||
mem->mm_node = node;
|
||||
mem->start = node->node.start;
|
||||
node->base.base.start = node->base.mm_nodes[0].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;
|
||||
|
||||
err_free:
|
||||
kfree(node);
|
||||
|
||||
err_out:
|
||||
atomic64_add(mem->num_pages, &mgr->available);
|
||||
atomic64_add(num_pages, &mgr->available);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -235,19 +189,18 @@ err_out:
|
|||
* Free the allocated GTT again.
|
||||
*/
|
||||
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_node *node = mem->mm_node;
|
||||
|
||||
if (node) {
|
||||
spin_lock(&mgr->lock);
|
||||
drm_mm_remove_node(&node->node);
|
||||
spin_unlock(&mgr->lock);
|
||||
kfree(node);
|
||||
}
|
||||
spin_lock(&mgr->lock);
|
||||
if (drm_mm_node_allocated(&node->base.mm_nodes[0]))
|
||||
drm_mm_remove_node(&node->base.mm_nodes[0]);
|
||||
spin_unlock(&mgr->lock);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
|
||||
struct amdgpu_device *adev;
|
||||
struct amdgpu_gtt_node *node;
|
||||
struct drm_mm_node *mm_node;
|
||||
int r = 0;
|
||||
|
||||
adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
|
||||
spin_lock(&mgr->lock);
|
||||
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);
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&mgr->lock);
|
||||
|
||||
amdgpu_gart_invalidate_tlb(adev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -311,3 +275,61 @@ static const struct ttm_resource_manager_func amdgpu_gtt_mgr_func = {
|
|||
.free = amdgpu_gtt_mgr_del,
|
||||
.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__
|
||||
#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 {
|
||||
void (*flush_hdp)(struct amdgpu_device *adev, struct amdgpu_ring *ring);
|
||||
void (*invalidate_hdp)(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring);
|
||||
void (*reset_ras_error_count)(struct amdgpu_device *adev);
|
||||
void (*update_clock_gating)(struct amdgpu_device *adev, bool enable);
|
||||
void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags);
|
||||
void (*init_registers)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_hdp {
|
||||
struct ras_common_if *ras_if;
|
||||
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__ */
|
||||
|
|
|
@ -130,7 +130,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
|
|||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_ib *ib = &ibs[0];
|
||||
struct dma_fence *tmp = NULL;
|
||||
bool skip_preamble, need_ctx_switch;
|
||||
bool need_ctx_switch;
|
||||
unsigned patch_offset = ~0;
|
||||
struct amdgpu_vm *vm;
|
||||
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)
|
||||
patch_offset = amdgpu_ring_init_cond_exec(ring);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
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);
|
||||
}
|
||||
amdgpu_device_flush_hdp(adev, ring);
|
||||
|
||||
if (need_ctx_switch)
|
||||
status |= AMDGPU_HAVE_CTX_SWITCH;
|
||||
|
||||
skip_preamble = ring->current_ctx == fence_ctx;
|
||||
if (job && ring->funcs->emit_cntxcntl) {
|
||||
status |= job->preamble_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) {
|
||||
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 (secure != !!(ib->flags & AMDGPU_IB_FLAGS_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)
|
||||
amdgpu_ring_emit_frame_cntl(ring, false, secure);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
if (!(adev->flags & AMD_IS_APU))
|
||||
#endif
|
||||
amdgpu_asic_invalidate_hdp(adev, ring);
|
||||
amdgpu_device_invalidate_hdp(adev, ring);
|
||||
|
||||
if (ib->flags & AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE)
|
||||
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++) {
|
||||
if (i == AMDGPU_IB_POOL_DIRECT)
|
||||
size = PAGE_SIZE * 2;
|
||||
size = PAGE_SIZE * 6;
|
||||
else
|
||||
size = AMDGPU_IB_POOL_SIZE;
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv,
|
|||
unsigned count;
|
||||
int r;
|
||||
|
||||
r = dma_resv_get_fences_rcu(resv, NULL, &count, &fences);
|
||||
r = dma_resv_get_fences(resv, NULL, &count, &fences);
|
||||
if (r)
|
||||
goto fallback;
|
||||
|
||||
|
@ -156,8 +156,7 @@ fallback:
|
|||
/* Not enough memory for the delayed delete, as last resort
|
||||
* block for all the fences to complete.
|
||||
*/
|
||||
dma_resv_wait_timeout_rcu(resv, true, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
dma_resv_wait_timeout(resv, true, false, MAX_SCHEDULE_TIMEOUT);
|
||||
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
|
||||
* @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
|
||||
* @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
|
||||
* @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
|
||||
* @ring: ring we want to submit job to
|
||||
|
|
|
@ -115,9 +115,11 @@ 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)
|
||||
{
|
||||
|
||||
if (!ih->ring)
|
||||
return;
|
||||
|
||||
if (ih->use_bus_addr) {
|
||||
if (!ih->ring)
|
||||
return;
|
||||
|
||||
/* add 8 bytes for the rptr/wptr shadows and
|
||||
* 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;
|
||||
*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_vblank.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_ih.h"
|
||||
#include "atom.h"
|
||||
|
@ -348,6 +349,25 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
|
|||
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
|
||||
*
|
||||
|
@ -357,19 +377,10 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
|
|||
* functionality, shuts down vblank, hotplug and reset interrupt handling,
|
||||
* 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;
|
||||
|
||||
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) {
|
||||
if (!adev->irq.client[i].sources)
|
||||
continue;
|
||||
|
|
|
@ -103,7 +103,8 @@ void amdgpu_irq_disable_all(struct amdgpu_device *adev);
|
|||
irqreturn_t amdgpu_irq_handler(int irq, void *arg);
|
||||
|
||||
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,
|
||||
unsigned client_id, unsigned src_id,
|
||||
struct amdgpu_irq_src *source);
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
#include "amdgpu.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_task_info ti;
|
||||
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));
|
||||
|
||||
|
@ -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)) {
|
||||
DRM_ERROR("ring %s timeout, but soft recovered\n",
|
||||
s_job->sched->name);
|
||||
return DRM_GPU_SCHED_STAT_NOMINAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
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)) {
|
||||
amdgpu_device_gpu_recover(ring->adev, job);
|
||||
return DRM_GPU_SCHED_STAT_NOMINAL;
|
||||
} else {
|
||||
drm_sched_suspend_timeout(&ring->sched);
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
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,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "amdgpu.h"
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include "amdgpu_uvd.h"
|
||||
#include "amdgpu_vce.h"
|
||||
#include "atom.h"
|
||||
|
@ -91,8 +92,11 @@ void amdgpu_driver_unload_kms(struct drm_device *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_device_fini(adev);
|
||||
amdgpu_device_fini_hw(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);
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -209,11 +229,40 @@ int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags)
|
|||
DPM_FLAG_MAY_SKIP_RESUME);
|
||||
pm_runtime_use_autosuspend(dev->dev);
|
||||
pm_runtime_set_autosuspend_delay(dev->dev, 5000);
|
||||
|
||||
pm_runtime_allow(dev->dev);
|
||||
|
||||
pm_runtime_mark_last_busy(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:
|
||||
if (r) {
|
||||
/* 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)))
|
||||
? -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:
|
||||
DRM_DEBUG_KMS("Invalid request %d\n",
|
||||
info->vbios_info.type);
|
||||
|
@ -986,7 +1050,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
|||
|
||||
if (!ras)
|
||||
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,
|
||||
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!");
|
||||
pasid = 0;
|
||||
}
|
||||
r = amdgpu_vm_init(adev, &fpriv->vm, AMDGPU_VM_CONTEXT_GFX, pasid);
|
||||
|
||||
r = amdgpu_vm_init(adev, &fpriv->vm, pasid);
|
||||
if (r)
|
||||
goto error_pasid;
|
||||
|
||||
|
@ -1197,7 +1262,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
|
|||
}
|
||||
|
||||
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_vm_fini(adev, &fpriv->vm);
|
||||
|
@ -1219,6 +1284,15 @@ void amdgpu_driver_postclose_kms(struct drm_device *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.
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@ struct amdgpu_mmhub_ras_funcs {
|
|||
void *ras_error_status);
|
||||
void (*query_ras_error_status)(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 {
|
||||
|
|
|
@ -75,8 +75,8 @@ static bool amdgpu_mn_invalidate_gfx(struct mmu_interval_notifier *mni,
|
|||
|
||||
mmu_interval_set_seq(mni, cur_seq);
|
||||
|
||||
r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, true, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, true, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
mutex_unlock(&adev->notifier_lock);
|
||||
if (r <= 0)
|
||||
DRM_ERROR("(%ld) failed to wait for user bo\n", r);
|
||||
|
@ -155,3 +155,89 @@ void amdgpu_mn_unregister(struct amdgpu_bo *bo)
|
|||
mmu_interval_notifier_remove(&bo->notifier);
|
||||
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/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)
|
||||
int amdgpu_mn_register(struct amdgpu_bo *bo, unsigned long addr);
|
||||
void amdgpu_mn_unregister(struct amdgpu_bo *bo);
|
||||
|
|
|
@ -344,7 +344,7 @@ struct amdgpu_mode_info {
|
|||
/* pointer to fbdev info structure */
|
||||
struct amdgpu_fbdev *rfbdev;
|
||||
/* firmware flags */
|
||||
u16 firmware_flags;
|
||||
u32 firmware_flags;
|
||||
/* pointer to backlight encoder */
|
||||
struct amdgpu_encoder *bl_encoder;
|
||||
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)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
|
||||
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);
|
||||
|
||||
if (bo->tbo.base.import_attach)
|
||||
drm_prime_gem_destroy(&bo->tbo.base, bo->tbo.sg);
|
||||
drm_gem_object_release(&bo->tbo.base);
|
||||
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;
|
||||
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
kfree(ubo->metadata);
|
||||
amdgpu_bo_destroy(tbo);
|
||||
}
|
||||
|
||||
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(&bo->shadow_list)) {
|
||||
if (!list_empty(&vmbo->shadow_list)) {
|
||||
mutex_lock(&adev->shadow_list_lock);
|
||||
list_del_init(&bo->shadow_list);
|
||||
list_del_init(&vmbo->shadow_list);
|
||||
mutex_unlock(&adev->shadow_list_lock);
|
||||
}
|
||||
amdgpu_bo_unref(&bo->parent);
|
||||
|
||||
if (bo->tbo.type == ttm_bo_type_device) {
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
kfree(ubo->metadata);
|
||||
}
|
||||
|
||||
kvfree(bo);
|
||||
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)
|
||||
{
|
||||
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 false;
|
||||
}
|
||||
|
||||
|
@ -157,7 +149,9 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
|
|||
if (domain & AMDGPU_GEM_DOMAIN_GTT) {
|
||||
places[c].fpfn = 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;
|
||||
c++;
|
||||
}
|
||||
|
@ -386,14 +380,14 @@ int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
|
|||
if (cpu_addr)
|
||||
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) {
|
||||
(*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT;
|
||||
(*bo_ptr)->placements[i].lpfn = (offset + size) >> PAGE_SHIFT;
|
||||
}
|
||||
r = ttm_bo_mem_space(&(*bo_ptr)->tbo, &(*bo_ptr)->placement,
|
||||
&(*bo_ptr)->tbo.mem, &ctx);
|
||||
&(*bo_ptr)->tbo.resource, &ctx);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
|
@ -515,7 +509,18 @@ bool amdgpu_bo_support_uswc(u64 bo_flags)
|
|||
#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 **bo_ptr)
|
||||
{
|
||||
|
@ -556,7 +561,6 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
|
|||
if (bo == NULL)
|
||||
return -ENOMEM;
|
||||
drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size);
|
||||
INIT_LIST_HEAD(&bo->shadow_list);
|
||||
bo->vm_bo = NULL;
|
||||
bo->preferred_domains = bp->preferred_domain ? bp->preferred_domain :
|
||||
bp->domain;
|
||||
|
@ -579,22 +583,25 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
|
|||
if (bp->type == ttm_bo_type_kernel)
|
||||
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,
|
||||
&bo->placement, page_align, &ctx, NULL,
|
||||
bp->resv, &amdgpu_bo_destroy);
|
||||
bp->resv, bp->destroy);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
|
||||
if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
|
||||
bo->tbo.mem.mem_type == TTM_PL_VRAM &&
|
||||
bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT)
|
||||
bo->tbo.resource->mem_type == TTM_PL_VRAM &&
|
||||
bo->tbo.resource->start < adev->gmc.visible_vram_size >> PAGE_SHIFT)
|
||||
amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved,
|
||||
ctx.bytes_moved);
|
||||
else
|
||||
amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0);
|
||||
|
||||
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;
|
||||
|
||||
r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence);
|
||||
|
@ -625,80 +632,6 @@ fail_unreserve:
|
|||
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
|
||||
* @adev: amdgpu device object
|
||||
|
@ -718,15 +651,49 @@ int amdgpu_bo_create_user(struct amdgpu_device *adev,
|
|||
struct amdgpu_bo *bo_ptr;
|
||||
int r;
|
||||
|
||||
bp->flags = bp->flags & ~AMDGPU_GEM_CREATE_SHADOW;
|
||||
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)
|
||||
return r;
|
||||
|
||||
*ubo_ptr = to_amdgpu_bo_user(bo_ptr);
|
||||
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
|
||||
* @bo: pointer to the buffer object
|
||||
|
@ -761,6 +728,22 @@ retry:
|
|||
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
|
||||
*
|
||||
|
@ -815,12 +798,12 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
r = dma_resv_wait_timeout_rcu(bo->tbo.base.resv, false, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, false, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0)
|
||||
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)
|
||||
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);
|
||||
|
||||
if (bo->tbo.pin_count) {
|
||||
uint32_t mem_type = bo->tbo.mem.mem_type;
|
||||
uint32_t mem_flags = bo->tbo.mem.placement;
|
||||
uint32_t mem_type = bo->tbo.resource->mem_type;
|
||||
uint32_t mem_flags = bo->tbo.resource->placement;
|
||||
|
||||
if (!(domain & amdgpu_mem_type_to_domain(mem_type)))
|
||||
return -EINVAL;
|
||||
|
@ -994,7 +977,7 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
|
|||
|
||||
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) {
|
||||
atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size);
|
||||
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)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
|
||||
ttm_bo_unpin(&bo->tbo);
|
||||
if (bo->tbo.pin_count)
|
||||
return;
|
||||
|
||||
amdgpu_bo_subtract_pin_size(bo);
|
||||
|
||||
if (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)
|
||||
{
|
||||
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);
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
if (metadata_size)
|
||||
*metadata_size = ubo->metadata_size;
|
||||
|
||||
if (buffer) {
|
||||
if (buffer_size < ubo->metadata_size)
|
||||
return -EINVAL;
|
||||
|
@ -1254,8 +1244,6 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
|
|||
memcpy(buffer, ubo->metadata, ubo->metadata_size);
|
||||
}
|
||||
|
||||
if (metadata_size)
|
||||
*metadata_size = ubo->metadata_size;
|
||||
if (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_bo *abo;
|
||||
struct ttm_resource *old_mem = &bo->mem;
|
||||
struct ttm_resource *old_mem = bo->resource;
|
||||
|
||||
if (!amdgpu_bo_is_amdgpu_bo(bo))
|
||||
return;
|
||||
|
@ -1289,7 +1277,7 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
|
|||
amdgpu_bo_kunmap(abo);
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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
|
||||
* @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)
|
||||
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))
|
||||
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 ttm_operation_ctx ctx = { false, false };
|
||||
struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
|
||||
unsigned long offset, size;
|
||||
unsigned long offset;
|
||||
int r;
|
||||
|
||||
/* Remember that this BO was accessed by the CPU */
|
||||
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;
|
||||
|
||||
size = bo->mem.num_pages << PAGE_SHIFT;
|
||||
offset = bo->mem.start << PAGE_SHIFT;
|
||||
if ((offset + size) <= adev->gmc.visible_vram_size)
|
||||
offset = bo->resource->start << PAGE_SHIFT;
|
||||
if ((offset + bo->base.size) <= adev->gmc.visible_vram_size)
|
||||
return 0;
|
||||
|
||||
/* 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))
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
offset = bo->mem.start << PAGE_SHIFT;
|
||||
offset = bo->resource->start << PAGE_SHIFT;
|
||||
/* this should never happen */
|
||||
if (bo->mem.mem_type == TTM_PL_VRAM &&
|
||||
(offset + size) > adev->gmc.visible_vram_size)
|
||||
if (bo->resource->mem_type == TTM_PL_VRAM &&
|
||||
(offset + bo->base.size) > adev->gmc.visible_vram_size)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
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)
|
||||
{
|
||||
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) &&
|
||||
!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.mem.mem_type == TTM_PL_VRAM &&
|
||||
WARN_ON_ONCE(bo->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET);
|
||||
WARN_ON_ONCE(bo->tbo.resource->mem_type == TTM_PL_VRAM &&
|
||||
!(bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS));
|
||||
|
||||
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);
|
||||
uint64_t offset;
|
||||
|
||||
offset = (bo->tbo.mem.start << PAGE_SHIFT) +
|
||||
amdgpu_ttm_domain_start(adev, bo->tbo.mem.mem_type);
|
||||
offset = (bo->tbo.resource->start << PAGE_SHIFT) +
|
||||
amdgpu_ttm_domain_start(adev, bo->tbo.resource->mem_type);
|
||||
|
||||
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;
|
||||
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) {
|
||||
case AMDGPU_GEM_DOMAIN_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, CPU_GTT_USWC);
|
||||
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, VM_ALWAYS_VALID);
|
||||
amdgpu_bo_print_flag(m, bo, EXPLICIT_SYNC);
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_res_cursor.h"
|
||||
|
||||
#ifdef CONFIG_MMU_NOTIFIER
|
||||
#include <linux/mmu_notifier.h>
|
||||
#endif
|
||||
|
@ -37,7 +39,12 @@
|
|||
#define AMDGPU_BO_INVALID_OFFSET LONG_MAX
|
||||
#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_vm(abo) container_of((abo), struct amdgpu_bo_vm, bo)
|
||||
|
||||
struct amdgpu_bo_param {
|
||||
unsigned long size;
|
||||
|
@ -48,7 +55,8 @@ struct amdgpu_bo_param {
|
|||
u64 flags;
|
||||
enum ttm_bo_type type;
|
||||
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 */
|
||||
|
@ -97,16 +105,10 @@ struct amdgpu_bo {
|
|||
struct amdgpu_vm_bo_base *vm_bo;
|
||||
/* Constant after initialization */
|
||||
struct amdgpu_bo *parent;
|
||||
struct amdgpu_bo *shadow;
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_MMU_NOTIFIER
|
||||
struct mmu_interval_notifier notifier;
|
||||
#endif
|
||||
|
||||
struct list_head shadow_list;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
unsigned fpfn = adev->gmc.visible_vram_size >> PAGE_SHIFT;
|
||||
struct drm_mm_node *node = bo->tbo.mem.mm_node;
|
||||
unsigned long pages_left;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
|
||||
if (bo->tbo.mem.mem_type != TTM_PL_VRAM)
|
||||
if (bo->tbo.resource->mem_type != TTM_PL_VRAM)
|
||||
return false;
|
||||
|
||||
for (pages_left = bo->tbo.mem.num_pages; pages_left;
|
||||
pages_left -= node->size, node++)
|
||||
if (node->start < fpfn)
|
||||
amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor);
|
||||
while (cursor.remaining) {
|
||||
if (cursor.start < adev->gmc.visible_vram_size)
|
||||
return true;
|
||||
|
||||
amdgpu_res_next(&cursor, cursor.size);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -245,6 +255,22 @@ static inline bool amdgpu_bo_encrypted(struct amdgpu_bo *bo)
|
|||
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);
|
||||
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,
|
||||
struct amdgpu_bo_param *bp,
|
||||
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 **cpu_addr);
|
||||
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_no_check(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,
|
||||
struct dma_fence **fence);
|
||||
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/dma-mapping.h>
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_psp.h"
|
||||
|
@ -38,6 +39,9 @@
|
|||
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_securedisplay.h"
|
||||
#include "amdgpu_atomfirmware.h"
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
|
||||
static int psp_sysfs_init(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_VANGOGH:
|
||||
case CHIP_DIMGREY_CAVEFISH:
|
||||
case CHIP_BEIGE_GOBY:
|
||||
psp_v11_0_set_psp_funcs(psp);
|
||||
psp->autoload_supported = true;
|
||||
break;
|
||||
|
@ -113,6 +118,10 @@ static int psp_early_init(void *handle)
|
|||
case CHIP_ALDEBARAN:
|
||||
psp_v13_0_set_psp_funcs(psp);
|
||||
break;
|
||||
case CHIP_YELLOW_CARP:
|
||||
psp_v13_0_set_psp_funcs(psp);
|
||||
psp->autoload_supported = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -162,11 +171,81 @@ Err_out:
|
|||
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)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
struct psp_context *psp = &adev->psp;
|
||||
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)) {
|
||||
ret = psp_init_microcode(psp);
|
||||
|
@ -174,17 +253,47 @@ static int psp_sw_init(void *handle)
|
|||
DRM_ERROR("Failed to load psp firmware!\n");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
ret = psp_memory_training_init(psp);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize memory training!\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;
|
||||
}
|
||||
ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to process memory training!\n");
|
||||
return ret;
|
||||
|
||||
if (mem_training_ctx->enable_mem_training) {
|
||||
ret = psp_memory_training_init(psp);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize memory training!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to process memory training!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_SIENNA_CICHLID) {
|
||||
|
@ -229,7 +338,7 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
|
|||
int i;
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
|
||||
if (psp->adev->in_pci_err_recovery)
|
||||
if (psp->adev->no_hw_access)
|
||||
return 0;
|
||||
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
int index;
|
||||
int index, idx;
|
||||
int timeout = 20000;
|
||||
bool ras_intr = 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;
|
||||
|
||||
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);
|
||||
if (ret) {
|
||||
atomic_dec(&psp->fence_value);
|
||||
mutex_unlock(&psp->mutex);
|
||||
return ret;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
amdgpu_asic_invalidate_hdp(psp->adev, NULL);
|
||||
amdgpu_device_invalidate_hdp(psp->adev, NULL);
|
||||
while (*((unsigned int *)psp->fence_buf) != index) {
|
||||
if (--timeout == 0)
|
||||
break;
|
||||
|
@ -288,7 +399,7 @@ psp_cmd_submit_buf(struct psp_context *psp,
|
|||
if (ras_intr)
|
||||
break;
|
||||
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 */
|
||||
|
@ -312,8 +423,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
|
|||
psp->cmd_buf_mem->cmd_id,
|
||||
psp->cmd_buf_mem->resp.status);
|
||||
if (!timeout) {
|
||||
mutex_unlock(&psp->mutex);
|
||||
return -EINVAL;
|
||||
ret = -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_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
|
||||
}
|
||||
mutex_unlock(&psp->mutex);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&psp->mutex);
|
||||
drm_dev_exit(idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -366,8 +479,7 @@ static int psp_load_toc(struct psp_context *psp,
|
|||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
/* Copy toc to psp firmware private buffer */
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->toc_start_addr, psp->toc_bin_size);
|
||||
psp_copy_fw(psp, psp->toc_start_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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
switch (psp->adev->asic_type) {
|
||||
case CHIP_NAVI12:
|
||||
case CHIP_SIENNA_CICHLID:
|
||||
case CHIP_ALDEBARAN:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -552,20 +645,43 @@ int psp_get_fw_attestation_records_addr(struct psp_context *psp,
|
|||
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_gfx_cmd_resp *cmd = psp->cmd;
|
||||
|
||||
if (adev->asic_type != CHIP_SIENNA_CICHLID || amdgpu_sriov_vf(adev))
|
||||
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_SET;
|
||||
cmd->cmd.boot_cfg.boot_config = BOOT_CONFIG_GECC;
|
||||
cmd->cmd.boot_cfg.boot_config_valid = BOOT_CONFIG_GECC;
|
||||
cmd->cmd.boot_cfg.boot_config = boot_cfg;
|
||||
cmd->cmd.boot_cfg.boot_config_valid = boot_cfg;
|
||||
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->asd_start_addr, psp->asd_ucode_size);
|
||||
psp_copy_fw(psp, psp->asd_start_addr, psp->asd_ucode_size);
|
||||
|
||||
psp_prep_asd_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
|
||||
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);
|
||||
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);
|
||||
return ret;
|
||||
|
@ -777,8 +894,7 @@ static int psp_xgmi_load(struct psp_context *psp)
|
|||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
|
||||
psp_copy_fw(psp, psp->ta_xgmi_start_addr, psp->ta_xgmi_ucode_size);
|
||||
|
||||
psp_prep_ta_load_cmd_buf(cmd,
|
||||
psp->fw_pri_mc_addr,
|
||||
|
@ -1034,8 +1150,14 @@ static int psp_ras_load(struct psp_context *psp)
|
|||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->ta_ras_start_addr, psp->ta_ras_ucode_size);
|
||||
psp_copy_fw(psp, 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->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,
|
||||
psp->fence_buf_mc_addr);
|
||||
|
||||
ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf;
|
||||
|
||||
if (!ret) {
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
union ta_ras_cmd_input *info, bool enable)
|
||||
{
|
||||
|
@ -1151,7 +1296,7 @@ int psp_ras_enable_features(struct psp_context *psp,
|
|||
if (ret)
|
||||
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)
|
||||
|
@ -1184,19 +1329,62 @@ static int psp_ras_terminate(struct psp_context *psp)
|
|||
static int psp_ras_initialize(struct psp_context *psp)
|
||||
{
|
||||
int ret;
|
||||
uint32_t boot_cfg = 0xFF;
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
|
||||
/*
|
||||
* TODO: bypass the initialize in sriov for now
|
||||
*/
|
||||
if (amdgpu_sriov_vf(psp->adev))
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return 0;
|
||||
|
||||
if (!psp->adev->psp.ta_ras_ucode_size ||
|
||||
!psp->adev->psp.ta_ras_start_addr) {
|
||||
dev_info(psp->adev->dev, "RAS: optional ras ta ucode is not available\n");
|
||||
if (!adev->psp.ta_ras_ucode_size ||
|
||||
!adev->psp.ta_ras_start_addr) {
|
||||
dev_info(adev->dev, "RAS: optional ras ta ucode is not available\n");
|
||||
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) {
|
||||
ret = psp_ras_init_shared_buf(psp);
|
||||
if (ret)
|
||||
|
@ -1234,7 +1422,7 @@ int psp_ras_trigger_error(struct psp_context *psp,
|
|||
if (amdgpu_ras_intr_triggered())
|
||||
return 0;
|
||||
|
||||
return ras_cmd->ras_status;
|
||||
return psp_ras_status_to_errno(psp->adev, ras_cmd->ras_status);
|
||||
}
|
||||
// ras end
|
||||
|
||||
|
@ -1271,9 +1459,8 @@ static int psp_hdcp_load(struct psp_context *psp)
|
|||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->ta_hdcp_start_addr,
|
||||
psp->ta_hdcp_ucode_size);
|
||||
psp_copy_fw(psp, psp->ta_hdcp_start_addr,
|
||||
psp->ta_hdcp_ucode_size);
|
||||
|
||||
psp_prep_ta_load_cmd_buf(cmd,
|
||||
psp->fw_pri_mc_addr,
|
||||
|
@ -1423,8 +1610,7 @@ static int psp_dtm_load(struct psp_context *psp)
|
|||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
|
||||
psp_copy_fw(psp, psp->ta_dtm_start_addr, psp->ta_dtm_ucode_size);
|
||||
|
||||
psp_prep_ta_load_cmd_buf(cmd,
|
||||
psp->fw_pri_mc_addr,
|
||||
|
@ -1569,8 +1755,7 @@ static int psp_rap_load(struct psp_context *psp)
|
|||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
|
||||
psp_copy_fw(psp, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
|
||||
|
||||
psp_prep_ta_load_cmd_buf(cmd,
|
||||
psp->fw_pri_mc_addr,
|
||||
|
@ -1920,17 +2105,6 @@ static int psp_hw_start(struct psp_context *psp)
|
|||
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);
|
||||
if (ret) {
|
||||
DRM_ERROR("PSP tmr init failed!\n");
|
||||
|
@ -2166,12 +2340,9 @@ static int psp_load_smu_fw(struct psp_context *psp)
|
|||
return 0;
|
||||
|
||||
if ((amdgpu_in_reset(adev) &&
|
||||
ras && ras->supported &&
|
||||
ras && adev->ras_enabled &&
|
||||
(adev->asic_type == CHIP_ARCTURUS ||
|
||||
adev->asic_type == CHIP_VEGA20)) ||
|
||||
(adev->in_runpm &&
|
||||
adev->asic_type >= CHIP_NAVI10 &&
|
||||
adev->asic_type <= CHIP_NAVI12)) {
|
||||
adev->asic_type == CHIP_VEGA20))) {
|
||||
ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD);
|
||||
if (ret) {
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG,
|
||||
AMDGPU_GEM_DOMAIN_GTT,
|
||||
&psp->fw_pri_bo,
|
||||
&psp->fw_pri_mc_addr,
|
||||
&psp->fw_pri_buf);
|
||||
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,
|
||||
AMDGPU_GEM_DOMAIN_GTT,
|
||||
&psp->fw_pri_bo,
|
||||
&psp->fw_pri_mc_addr,
|
||||
&psp->fw_pri_buf);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
|
@ -2434,7 +2614,6 @@ static int psp_hw_fini(void *handle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
|
||||
struct psp_context *psp = &adev->psp;
|
||||
int ret;
|
||||
|
||||
if (psp->adev->psp.ta_fw) {
|
||||
psp_ras_terminate(psp);
|
||||
|
@ -2445,11 +2624,6 @@ static int psp_hw_fini(void *handle)
|
|||
}
|
||||
|
||||
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_ring_destroy(psp, PSP_RING_TYPE__KM);
|
||||
|
@ -2539,10 +2713,12 @@ static int psp_resume(void *handle)
|
|||
|
||||
DRM_INFO("PSP is resuming...\n");
|
||||
|
||||
ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to process memory training!\n");
|
||||
return ret;
|
||||
if (psp->mem_train_ctx.enable_mem_training) {
|
||||
ret = psp_mem_training(psp, PSP_MEM_TRAIN_RESUME);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to process memory training!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
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_lo = lower_32_bits(fence_mc_addr);
|
||||
write_frame->fence_value = index;
|
||||
amdgpu_asic_flush_hdp(adev, NULL);
|
||||
amdgpu_device_flush_hdp(adev, NULL);
|
||||
|
||||
/* Update the write Pointer in DWORDs */
|
||||
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;
|
||||
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_start_addr = (uint8_t *)asd_hdr +
|
||||
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;
|
||||
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_start_addr = (uint8_t *)toc_hdr +
|
||||
le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes);
|
||||
|
@ -2774,6 +2950,50 @@ out:
|
|||
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,
|
||||
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_3 *sos_hdr_v1_3;
|
||||
int err = 0;
|
||||
uint8_t *ucode_array_start_addr;
|
||||
|
||||
if (!chip_name) {
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
switch (sos_hdr->header.header_version_major) {
|
||||
case 1:
|
||||
adev->psp.sos_fw_version = le32_to_cpu(sos_hdr->header.ucode_version);
|
||||
adev->psp.sos_feature_version = le32_to_cpu(sos_hdr->ucode_feature_version);
|
||||
adev->psp.sos_bin_size = le32_to_cpu(sos_hdr->sos_size_bytes);
|
||||
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);
|
||||
err = psp_init_sos_base_fw(adev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (sos_hdr->header.header_version_minor == 1) {
|
||||
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 +
|
||||
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);
|
||||
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_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) {
|
||||
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 +
|
||||
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) {
|
||||
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_start_addr = (uint8_t *)adev->psp.sys_start_addr +
|
||||
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_start_addr = (uint8_t *)adev->psp.sys_start_addr +
|
||||
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_start_addr = (uint8_t *)adev->psp.sys_start_addr +
|
||||
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_start_addr = (uint8_t *)adev->psp.sys_start_addr +
|
||||
le32_to_cpu(sos_hdr_v1_3->rl_offset_bytes);
|
||||
adev->psp.toc_bin_size = le32_to_cpu(sos_hdr_v1_3->v1_1.toc.size_bytes);
|
||||
adev->psp.toc_start_addr = ucode_array_start_addr +
|
||||
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_start_addr = ucode_array_start_addr +
|
||||
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_start_addr = ucode_array_start_addr +
|
||||
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_start_addr = ucode_array_start_addr +
|
||||
le32_to_cpu(sos_hdr_v1_3->rl.offset_bytes);
|
||||
}
|
||||
break;
|
||||
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);
|
||||
void *cpu_addr;
|
||||
dma_addr_t dma_addr;
|
||||
int ret;
|
||||
int ret, idx;
|
||||
char fw_name[100];
|
||||
const struct firmware *usbc_pd_fw;
|
||||
|
||||
|
@ -3027,6 +3246,9 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!drm_dev_enter(ddev, &idx))
|
||||
return -ENODEV;
|
||||
|
||||
snprintf(fw_name, sizeof(fw_name), "amdgpu/%s", buf);
|
||||
ret = request_firmware(&usbc_pd_fw, fw_name, adev->dev);
|
||||
if (ret)
|
||||
|
@ -3058,16 +3280,29 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
|
|||
rel_buf:
|
||||
dma_free_coherent(adev->dev, usbc_pd_fw->size, cpu_addr, dma_addr);
|
||||
release_firmware(usbc_pd_fw);
|
||||
|
||||
fail:
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to load USBC PD FW, err = %d", ret);
|
||||
return ret;
|
||||
count = ret;
|
||||
}
|
||||
|
||||
drm_dev_exit(idx);
|
||||
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,
|
||||
psp_usbc_pd_fw_sysfs_read,
|
||||
psp_usbc_pd_fw_sysfs_write);
|
||||
|
|
|
@ -225,6 +225,61 @@ struct psp_memory_training_context {
|
|||
|
||||
enum psp_memory_training_init_flag init;
|
||||
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
|
||||
|
@ -325,6 +380,8 @@ struct psp_context
|
|||
struct psp_securedisplay_context securedisplay_context;
|
||||
struct mutex mutex;
|
||||
struct psp_memory_training_context mem_train_ctx;
|
||||
|
||||
uint32_t boot_cfg_bitmask;
|
||||
};
|
||||
|
||||
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,
|
||||
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
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_atomfirmware.h"
|
||||
#include "amdgpu_xgmi.h"
|
||||
#include "ivsrcid/nbio/irqsrcs_nbif_7_4.h"
|
||||
#include "atom.h"
|
||||
|
||||
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.
|
||||
* "enable" requires the block and error type.
|
||||
* "inject" requires the block, error type, address, and value.
|
||||
*
|
||||
* The block is one of: umc, sdma, gfx, etc.
|
||||
* see ras_block_string[] for details
|
||||
*
|
||||
* The error type is one of: ue, ce, where,
|
||||
* ue is multi-uncorrectable
|
||||
* ce is single-correctable
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
|
@ -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 ras_manager *obj;
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
if (!adev->ras_enabled || !con)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
int i;
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
if (!adev->ras_enabled || !con)
|
||||
return NULL;
|
||||
|
||||
if (head) {
|
||||
|
@ -585,36 +590,11 @@ struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev,
|
|||
}
|
||||
/* 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 */
|
||||
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 con->hw_supported & BIT(head->block);
|
||||
return adev->ras_hw_enabled & BIT(head->block);
|
||||
}
|
||||
|
||||
static int amdgpu_ras_is_feature_enabled(struct amdgpu_device *adev,
|
||||
|
@ -658,11 +638,7 @@ static int __amdgpu_ras_feature_enable(struct amdgpu_device *adev,
|
|||
con->features |= BIT(head->block);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -708,15 +684,10 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev,
|
|||
if (!amdgpu_ras_intr_triggered()) {
|
||||
ret = psp_ras_enable_features(&adev->psp, info, enable);
|
||||
if (ret) {
|
||||
amdgpu_ras_parse_status_code(adev,
|
||||
enable ? "enable":"disable",
|
||||
ras_block_str(head->block),
|
||||
(enum ta_ras_status)ret);
|
||||
if (ret == TA_RAS_STATUS__RESET_NEEDED)
|
||||
ret = -EAGAIN;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
dev_err(adev->dev, "ras %s %s failed %d\n",
|
||||
enable ? "enable":"disable",
|
||||
ras_block_str(head->block),
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -770,6 +741,10 @@ int amdgpu_ras_feature_enable_on_boot(struct amdgpu_device *adev,
|
|||
con->features |= BIT(head->block);
|
||||
|
||||
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
|
||||
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, &err_data);
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -901,17 +881,42 @@ int amdgpu_ras_query_error_status(struct amdgpu_device *adev,
|
|||
info->ce_count = obj->err_data.ce_count;
|
||||
|
||||
if (err_data.ce_count) {
|
||||
dev_info(adev->dev, "%ld correctable hardware errors "
|
||||
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 "
|
||||
"detected in %s block, no user "
|
||||
"action is needed.\n",
|
||||
obj->err_data.ce_count,
|
||||
ras_block_str(info->head.block));
|
||||
}
|
||||
}
|
||||
if (err_data.ue_count) {
|
||||
dev_info(adev->dev, "%ld uncorrectable hardware errors "
|
||||
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 "
|
||||
"detected in %s block\n",
|
||||
obj->err_data.ue_count,
|
||||
ras_block_str(info->head.block));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -937,11 +942,20 @@ int amdgpu_ras_reset_error_status(struct amdgpu_device *adev,
|
|||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->reset_ras_error_count)
|
||||
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;
|
||||
case AMDGPU_RAS_BLOCK__SDMA:
|
||||
if (adev->sdma.funcs->reset_ras_error_count)
|
||||
adev->sdma.funcs->reset_ras_error_count(adev);
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -1022,38 +1036,44 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev,
|
|||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
amdgpu_ras_parse_status_code(adev,
|
||||
"inject",
|
||||
ras_block_str(info->head.block),
|
||||
(enum ta_ras_status)ret);
|
||||
if (ret)
|
||||
dev_err(adev->dev, "ras inject %s failed %d\n",
|
||||
ras_block_str(info->head.block), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get the total error counts on all IPs */
|
||||
unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev,
|
||||
bool is_ce)
|
||||
void amdgpu_ras_query_error_count(struct amdgpu_device *adev,
|
||||
unsigned long *ce_count,
|
||||
unsigned long *ue_count)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct ras_manager *obj;
|
||||
struct ras_err_data data = {0, 0};
|
||||
unsigned long ce, ue;
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
return 0;
|
||||
if (!adev->ras_enabled || !con)
|
||||
return;
|
||||
|
||||
ce = 0;
|
||||
ue = 0;
|
||||
list_for_each_entry(obj, &con->head, node) {
|
||||
struct ras_query_if info = {
|
||||
.head = obj->head,
|
||||
};
|
||||
|
||||
if (amdgpu_ras_query_error_status(adev, &info))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
data.ce_count += info.ce_count;
|
||||
data.ue_count += info.ue_count;
|
||||
ce += info.ce_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 */
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
debugfs_create_u32("bad_page_cnt_threshold", 0444, dir,
|
||||
&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
|
||||
|
@ -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 ras_manager *obj;
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
if (!adev->ras_enabled || !con)
|
||||
return;
|
||||
|
||||
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 ras_manager *obj;
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
if (!adev->ras_enabled || !con)
|
||||
return;
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
if (adev->ras_features && con)
|
||||
if (adev->ras_enabled && con)
|
||||
data = &con->eh_data;
|
||||
else
|
||||
return 0;
|
||||
|
@ -1962,6 +1984,9 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev)
|
|||
ret = amdgpu_ras_load_bad_pages(adev);
|
||||
if (ret)
|
||||
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;
|
||||
|
@ -2028,6 +2053,25 @@ static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev)
|
|||
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.
|
||||
* 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
|
||||
* allowed or not in each function.
|
||||
*/
|
||||
static void amdgpu_ras_check_supported(struct amdgpu_device *adev,
|
||||
uint32_t *hw_supported, uint32_t *supported)
|
||||
static void amdgpu_ras_check_supported(struct amdgpu_device *adev)
|
||||
{
|
||||
*hw_supported = 0;
|
||||
*supported = 0;
|
||||
adev->ras_hw_enabled = adev->ras_enabled = 0;
|
||||
|
||||
if (amdgpu_sriov_vf(adev) || !adev->is_atom_fw ||
|
||||
!amdgpu_ras_asic_supported(adev))
|
||||
|
@ -2050,33 +2092,58 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev,
|
|||
if (!adev->gmc.xgmi.connected_to_cpu) {
|
||||
if (amdgpu_atomfirmware_mem_ecc_supported(adev)) {
|
||||
dev_info(adev->dev, "MEM ECC is active.\n");
|
||||
*hw_supported |= (1 << AMDGPU_RAS_BLOCK__UMC |
|
||||
1 << AMDGPU_RAS_BLOCK__DF);
|
||||
adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__UMC |
|
||||
1 << AMDGPU_RAS_BLOCK__DF);
|
||||
} else {
|
||||
dev_info(adev->dev, "MEM ECC is not presented.\n");
|
||||
}
|
||||
|
||||
if (amdgpu_atomfirmware_sram_ecc_supported(adev)) {
|
||||
dev_info(adev->dev, "SRAM ECC is active.\n");
|
||||
*hw_supported |= ~(1 << AMDGPU_RAS_BLOCK__UMC |
|
||||
1 << AMDGPU_RAS_BLOCK__DF);
|
||||
adev->ras_hw_enabled |= ~(1 << AMDGPU_RAS_BLOCK__UMC |
|
||||
1 << AMDGPU_RAS_BLOCK__DF);
|
||||
} else {
|
||||
dev_info(adev->dev, "SRAM ECC is not presented.\n");
|
||||
}
|
||||
} else {
|
||||
/* driver only manages a few IP blocks RAS feature
|
||||
* when GPU is connected cpu through XGMI */
|
||||
*hw_supported |= (1 << AMDGPU_RAS_BLOCK__GFX |
|
||||
1 << AMDGPU_RAS_BLOCK__SDMA |
|
||||
1 << AMDGPU_RAS_BLOCK__MMHUB);
|
||||
adev->ras_hw_enabled |= (1 << AMDGPU_RAS_BLOCK__GFX |
|
||||
1 << AMDGPU_RAS_BLOCK__SDMA |
|
||||
1 << AMDGPU_RAS_BLOCK__MMHUB);
|
||||
}
|
||||
|
||||
/* hw_supported needs to be aligned with RAS block mask. */
|
||||
*hw_supported &= AMDGPU_RAS_BLOCK_MASK;
|
||||
amdgpu_ras_get_quirks(adev);
|
||||
|
||||
*supported = amdgpu_ras_enable == 0 ?
|
||||
0 : *hw_supported & amdgpu_ras_mask;
|
||||
adev->ras_features = *supported;
|
||||
/* hw_supported needs to be aligned with RAS block mask. */
|
||||
adev->ras_hw_enabled &= AMDGPU_RAS_BLOCK_MASK;
|
||||
|
||||
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)
|
||||
|
@ -2093,17 +2160,22 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
|
|||
if (!con)
|
||||
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);
|
||||
|
||||
amdgpu_ras_set_context(adev, con);
|
||||
|
||||
amdgpu_ras_check_supported(adev, &con->hw_supported,
|
||||
&con->supported);
|
||||
if (!con->hw_supported || (adev->asic_type == CHIP_VEGA10)) {
|
||||
amdgpu_ras_check_supported(adev);
|
||||
|
||||
if (!adev->ras_enabled || adev->asic_type == CHIP_VEGA10) {
|
||||
/* set gfx block ras context feature for VEGA20 Gaming
|
||||
* 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);
|
||||
|
||||
return 0;
|
||||
|
@ -2153,8 +2225,9 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
|
|||
}
|
||||
|
||||
dev_info(adev->dev, "RAS INFO: ras initialized successfully, "
|
||||
"hardware ability[%x] ras_mask[%x]\n",
|
||||
con->hw_supported, con->supported);
|
||||
"hardware ability[%x] ras_mask[%x]\n",
|
||||
adev->ras_hw_enabled, adev->ras_enabled);
|
||||
|
||||
return 0;
|
||||
release_con:
|
||||
amdgpu_ras_set_context(adev, NULL);
|
||||
|
@ -2163,7 +2236,7 @@ release_con:
|
|||
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)
|
||||
return 1;
|
||||
|
@ -2195,6 +2268,8 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev,
|
|||
struct ras_fs_if *fs_info,
|
||||
struct ras_ih_if *ih_info)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
unsigned long ue_count, ce_count;
|
||||
int r;
|
||||
|
||||
/* 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)
|
||||
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;
|
||||
cleanup:
|
||||
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 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 */
|
||||
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);
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
if (!adev->ras_enabled || !con)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
if (!adev->ras_enabled || !con)
|
||||
return 0;
|
||||
|
||||
|
||||
/* Need disable ras on all IPs here before ip [hw/sw]fini */
|
||||
amdgpu_ras_disable_all_features(adev, 0);
|
||||
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);
|
||||
|
||||
if (!adev->ras_features || !con)
|
||||
if (!adev->ras_enabled || !con)
|
||||
return 0;
|
||||
|
||||
amdgpu_ras_fs_fini(adev);
|
||||
|
@ -2352,6 +2434,8 @@ int amdgpu_ras_fini(struct amdgpu_device *adev)
|
|||
if (con->features)
|
||||
amdgpu_ras_disable_all_features(adev, 1);
|
||||
|
||||
cancel_delayed_work_sync(&con->ras_counte_delay_work);
|
||||
|
||||
amdgpu_ras_set_context(adev, NULL);
|
||||
kfree(con);
|
||||
|
||||
|
@ -2360,10 +2444,8 @@ int amdgpu_ras_fini(struct amdgpu_device *adev)
|
|||
|
||||
void amdgpu_ras_global_ras_isr(struct amdgpu_device *adev)
|
||||
{
|
||||
uint32_t hw_supported, supported;
|
||||
|
||||
amdgpu_ras_check_supported(adev, &hw_supported, &supported);
|
||||
if (!hw_supported)
|
||||
amdgpu_ras_check_supported(adev);
|
||||
if (!adev->ras_hw_enabled)
|
||||
return;
|
||||
|
||||
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)
|
||||
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);
|
||||
amdgpu_ras_set_context(adev, NULL);
|
||||
kfree(con);
|
||||
|
|
|
@ -313,9 +313,6 @@ struct ras_common_if {
|
|||
struct amdgpu_ras {
|
||||
/* ras infrastructure */
|
||||
/* for ras itself. */
|
||||
uint32_t hw_supported;
|
||||
/* for IP to check its ras ability. */
|
||||
uint32_t supported;
|
||||
uint32_t features;
|
||||
struct list_head head;
|
||||
/* sysfs */
|
||||
|
@ -343,6 +340,11 @@ struct amdgpu_ras {
|
|||
|
||||
/* disable ras error count harvest in recovery */
|
||||
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 {
|
||||
|
@ -478,7 +480,7 @@ static inline int amdgpu_ras_is_supported(struct amdgpu_device *adev,
|
|||
|
||||
if (block >= AMDGPU_RAS_BLOCK_COUNT)
|
||||
return 0;
|
||||
return ras && (ras->supported & (1 << block));
|
||||
return ras && (adev->ras_enabled & (1 << block));
|
||||
}
|
||||
|
||||
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_suspend(struct amdgpu_device *adev);
|
||||
|
||||
unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev,
|
||||
bool is_ce);
|
||||
void amdgpu_ras_query_error_count(struct amdgpu_device *adev,
|
||||
unsigned long *ce_count,
|
||||
unsigned long *ue_count);
|
||||
|
||||
/* error handling functions */
|
||||
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);
|
||||
|
||||
void amdgpu_release_ras_context(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_persistent_edc_harvesting_supported(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <drm/drm_mm.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 */
|
||||
struct amdgpu_res_cursor {
|
||||
|
@ -53,7 +54,7 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
|
|||
{
|
||||
struct drm_mm_node *node;
|
||||
|
||||
if (!res || !res->mm_node) {
|
||||
if (!res) {
|
||||
cur->start = start;
|
||||
cur->size = 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);
|
||||
|
||||
node = res->mm_node;
|
||||
node = to_ttm_range_mgr_node(res)->mm_nodes;
|
||||
while (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…
Add table
Reference in a new issue