drm for 5.13-rc1
- printk fourcc modifier support added %p4cc core: - drm_crtc_commit_wait - atomic plane state helpers reworked for full state - dma-buf heaps API rework - edid: rework and improvements for displayid dp-mst: - better topology logging bridge: - Chipone ICN6211 - Lontium LT8912B - anx7625 regulator support panel: - fix lt9611 4k panels handling simple-kms: - add plane state helpers ttm: - debugfs support - removal of unused sysfs - ignore signaled moved fences - ioremap buffer according to mem caching i915: - Alderlake S enablement - Conversion to dma_resv_locking - Bring back watchdog timeout support - legacy ioctl cleanups - add GEM TDDO and RFC process - DG1 LMEM preparation work - intel_display.c refactoring - Gen9/TGL PCH combination support - eDP MSO Support - multiple PSR instance support - Link training debug updates - Disable PSR2 support on JSL/EHL - DDR5/LPDDR5 support for bw calcs - LSPCON limited to gen9/10 platforms - HSW/BDW async flip/VTd corruption workaround = SAGV watermakr fixes - SNB hard hang on ring resume fix - Limit imported dma-buf size - move to use new tasklet API - refactor KBL/TGL/ADL-S display/gt steppings - refactoring legacy DP/HDMI, FB plane code out amdgpu: - uapi: add ioctl to query video capabilities - Iniital AMD Freesync HDMI support - Initial Adebaran support - 10bpc dithering improvements - DCN secure display support - Drop legacy IO BAR requirements - PCIE/S0ix/RAS/Prime/Reset fixes - Display ASSR support - SMU gfx busy queues for RV/PCO - Initial LTTPR display work amdkfd: - MMU notifier fixes - APU fixes radeon: - debugfs cleanps - fw error handling ifix - Flexible array cleanups msm: - big DSI phy/pll cleanup - sc7280 initial support - commong bandwidth scaling path - shrinker locking contention fixes - unpin/swap support for GEM objcets ast: - cursor plane handling reworked tegra: - don't register DP AUX channels before connectors zynqmp: - fix OOB struct padding memset gma500: - drop ttm and medfield support exynos: - request_irq cleanup function mediatek: - fine tune line time for EOTp - MT8192 dpi support - atomic crtc config updates - don't support HDMI connector creation mxsdb: - imx8mm support panfrost: -= MMU IRQ handling rework qxl: - locking fixes - resource deallocation changes sun4i: - add alpha properties to UI/VI layers vc4: - RPi4 CEC support vmwgfx: - doc cleanups arc: - moved to drm/tiny -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJgiNSVAAoJEAx081l5xIa+fvYP/1206BfOYOx5opt5K3By06ZY zrOsbeaqFdHzfUR7xVwO4vqQNhkX4Pt8H/U7uYZx8PRdrXzGENwWLIaIskyUrKOd BtwNqUr0ZXJGDlGg26StnUHKeAXuYXlpBKLta5y4LUTkI+bm6V/oVaDMq4dnah70 2CXS4C2mnaFRLBzuRlraxoGFN4eZkz6Waeyo6PJxn/l2GE2gw+jho0Yrh8e8F2w5 EjQeNF22/uHwznov03XFJlyugecuBDbE8A6Ma/znnkVdBXcT94eUMugbKOKi4Nn6 PuJOEdJxmj/9s3oi6kBERc8dvpOj0O+8Vp+xOzn2U3BVXebvu7VoJsq6FcAvL5lN ltj4iErxUlEud2GRIVUMx8OTFiKj4ThRFJ2/8Uf22r3P7RHO5E9BLnZBzqIAhDVr s2cDBMItcxcVHRCmE04h12XAO4libZBb2TVjbqG94Acq7beR76pMszFrmxPmHBEm NGe1s7+ajxMzsq/NIsk4XAhqSmJo6+ujKyyVnrgvKUVeEaWW1U4YvjhJaetnP4fB 47gF24wOSNFwiCUZlqaIpp/MR4Z8YmaJ7tayWQq4Oj/neWe/yc8xQgQIuE8GL20j P9eNQNvlBnoxkz275M9x4kVhJ5FRjr7OYnd3sFVnALuj6fnL3Z1RXLqI1lNtIz1d YM89veZuNxMaiDz8roPH =bLWZ -----END PGP SIGNATURE----- Merge tag 'drm-next-2021-04-28' of git://anongit.freedesktop.org/drm/drm Pull drm updates from Dave Airlie: "The usual lots of work all over the place. i915 has gotten some Alderlake work and prelim DG1 code, along with a major locking rework over the GEM code, and brings back the property of timing out long running jobs using a watchdog. amdgpu has some Alderbran support (new GPU), freesync HDMI support along with a lot other fixes. Outside of the drm, there is a new printf specifier added which should have all the correct acks/sobs: - printk fourcc modifier support added %p4cc Summary: core: - drm_crtc_commit_wait - atomic plane state helpers reworked for full state - dma-buf heaps API rework - edid: rework and improvements for displayid dp-mst: - better topology logging bridge: - Chipone ICN6211 - Lontium LT8912B - anx7625 regulator support panel: - fix lt9611 4k panels handling simple-kms: - add plane state helpers ttm: - debugfs support - removal of unused sysfs - ignore signaled moved fences - ioremap buffer according to mem caching i915: - Alderlake S enablement - Conversion to dma_resv_locking - Bring back watchdog timeout support - legacy ioctl cleanups - add GEM TDDO and RFC process - DG1 LMEM preparation work - intel_display.c refactoring - Gen9/TGL PCH combination support - eDP MSO Support - multiple PSR instance support - Link training debug updates - Disable PSR2 support on JSL/EHL - DDR5/LPDDR5 support for bw calcs - LSPCON limited to gen9/10 platforms - HSW/BDW async flip/VTd corruption workaround - SAGV watermark fixes - SNB hard hang on ring resume fix - Limit imported dma-buf size - move to use new tasklet API - refactor KBL/TGL/ADL-S display/gt steppings - refactoring legacy DP/HDMI, FB plane code out amdgpu: - uapi: add ioctl to query video capabilities - Iniital AMD Freesync HDMI support - Initial Adebaran support - 10bpc dithering improvements - DCN secure display support - Drop legacy IO BAR requirements - PCIE/S0ix/RAS/Prime/Reset fixes - Display ASSR support - SMU gfx busy queues for RV/PCO - Initial LTTPR display work amdkfd: - MMU notifier fixes - APU fixes radeon: - debugfs cleanps - fw error handling ifix - Flexible array cleanups msm: - big DSI phy/pll cleanup - sc7280 initial support - commong bandwidth scaling path - shrinker locking contention fixes - unpin/swap support for GEM objcets ast: - cursor plane handling reworked tegra: - don't register DP AUX channels before connectors zynqmp: - fix OOB struct padding memset gma500: - drop ttm and medfield support exynos: - request_irq cleanup function mediatek: - fine tune line time for EOTp - MT8192 dpi support - atomic crtc config updates - don't support HDMI connector creation mxsdb: - imx8mm support panfrost: - MMU IRQ handling rework qxl: - locking fixes - resource deallocation changes sun4i: - add alpha properties to UI/VI layers vc4: - RPi4 CEC support vmwgfx: - doc cleanups arc: - moved to drm/tiny" * tag 'drm-next-2021-04-28' of git://anongit.freedesktop.org/drm/drm: (1390 commits) drm/ttm: Don't count pages in SG BOs against pages_limit drm/ttm: fix return value check drm/bridge: lt8912b: fix incorrect handling of of_* return values drm: bridge: fix LONTIUM use of mipi_dsi_() functions drm: bridge: fix ANX7625 use of mipi_dsi_() functions drm/amdgpu: page retire over debugfs mechanism drm/radeon: Fix a missing check bug in radeon_dp_mst_detect() drm/amd/display: Fix the Wunused-function warning drm/radeon/r600: Fix variables that are not used after assignment drm/amdgpu/smu7: fix CAC setting on TOPAZ drm/amd/display: Update DCN302 SR Exit Latency drm/amdgpu: enable ras eeprom on aldebaran drm/amdgpu: RAS harvest on driver load drm/amdgpu: add ras aldebaran ras eeprom driver drm/amd/pm: increase time out value when sending msg to SMU drm/amdgpu: add DMUB outbox event IRQ source define/complete/debug flag drm/amd/pm: add the callback to get vbios bootup values for vangogh drm/radeon: Fix size overflow drm/amdgpu: Fix size overflow drm/amdgpu: move mmhub ras_func init to ip specific file ...
This commit is contained in:
commit
68a32ba141
|
@ -591,6 +591,24 @@ For printing netdev_features_t.
|
|||
|
||||
Passed by reference.
|
||||
|
||||
V4L2 and DRM FourCC code (pixel format)
|
||||
---------------------------------------
|
||||
|
||||
::
|
||||
|
||||
%p4cc
|
||||
|
||||
Print a FourCC code used by V4L2 or DRM, including format endianness and
|
||||
its numerical value as hexadecimal.
|
||||
|
||||
Passed by reference.
|
||||
|
||||
Examples::
|
||||
|
||||
%p4cc BG12 little-endian (0x32314742)
|
||||
%p4cc Y10 little-endian (0x20303159)
|
||||
%p4cc NV12 big-endian (0xb231564e)
|
||||
|
||||
Thanks
|
||||
======
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ description: |
|
|||
and CEC.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined
|
||||
in Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with
|
||||
the following device-specific properties.
|
||||
in bridge/synopsys,dw-hdmi.yaml with the following device-specific
|
||||
properties.
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
|
|
|
@ -109,7 +109,7 @@ required:
|
|||
- resets
|
||||
- ddc
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
@ -34,6 +34,15 @@ properties:
|
|||
description: used for reset chip control, RESET_N pin B7.
|
||||
maxItems: 1
|
||||
|
||||
vdd10-supply:
|
||||
description: Regulator that provides the supply 1.0V power.
|
||||
|
||||
vdd18-supply:
|
||||
description: Regulator that provides the supply 1.8V power.
|
||||
|
||||
vdd33-supply:
|
||||
description: Regulator that provides the supply 3.3V power.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
|
@ -55,6 +64,9 @@ properties:
|
|||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd10-supply
|
||||
- vdd18-supply
|
||||
- vdd33-supply
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
@ -72,6 +84,9 @@ examples:
|
|||
reg = <0x58>;
|
||||
enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>;
|
||||
vdd10-supply = <&pp1000_mipibrdg>;
|
||||
vdd18-supply = <&pp1800_mipibrdg>;
|
||||
vdd33-supply = <&pp3300_mipibrdg>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/chipone,icn6211.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Chipone ICN6211 MIPI-DSI to RGB Converter bridge
|
||||
|
||||
maintainers:
|
||||
- Jagan Teki <jagan@amarulasolutions.com>
|
||||
|
||||
description: |
|
||||
ICN6211 is MIPI-DSI to RGB Converter bridge from chipone.
|
||||
|
||||
It has a flexible configuration of MIPI DSI signal input and
|
||||
produce RGB565, RGB666, RGB888 output format.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- chipone,icn6211
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: virtual channel number of a DSI peripheral
|
||||
|
||||
enable-gpios:
|
||||
description: Bridge EN pin, chip is reset when EN is low.
|
||||
|
||||
vdd1-supply:
|
||||
description: A 1.8V/2.5V/3.3V supply that power the MIPI RX.
|
||||
|
||||
vdd2-supply:
|
||||
description: A 1.8V/2.5V/3.3V supply that power the PLL.
|
||||
|
||||
vdd3-supply:
|
||||
description: A 1.8V/2.5V/3.3V supply that power the RGB output.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Video port for MIPI DSI input
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Video port for MIPI DPI output (panel or connector).
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- enable-gpios
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
bridge@0 {
|
||||
compatible = "chipone,icn6211";
|
||||
reg = <0>;
|
||||
enable-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* LCD-RST: PL5 */
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
bridge_in_dsi: endpoint {
|
||||
remote-endpoint = <&dsi_out_bridge>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
bridge_out_panel: endpoint {
|
||||
remote-endpoint = <&panel_out_bridge>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,33 +0,0 @@
|
|||
Synopsys DesignWare HDMI TX Encoder
|
||||
===================================
|
||||
|
||||
This document defines device tree properties for the Synopsys DesignWare HDMI
|
||||
TX Encoder (DWC HDMI TX). It doesn't constitue a device tree binding
|
||||
specification by itself but is meant to be referenced by platform-specific
|
||||
device tree bindings.
|
||||
|
||||
When referenced from platform device tree bindings the properties defined in
|
||||
this document are defined as follows. The platform device tree bindings are
|
||||
responsible for defining whether each property is required or optional.
|
||||
|
||||
- reg: Memory mapped base address and length of the DWC HDMI TX registers.
|
||||
|
||||
- reg-io-width: Width of the registers specified by the reg property. The
|
||||
value is expressed in bytes and must be equal to 1 or 4 if specified. The
|
||||
register width defaults to 1 if the property is not present.
|
||||
|
||||
- interrupts: Reference to the DWC HDMI TX interrupt.
|
||||
|
||||
- clocks: References to all the clocks specified in the clock-names property
|
||||
as specified in Documentation/devicetree/bindings/clock/clock-bindings.txt.
|
||||
|
||||
- clock-names: The DWC HDMI TX uses the following clocks.
|
||||
|
||||
- "iahb" is the bus clock for either AHB and APB (mandatory).
|
||||
- "isfr" is the internal register configuration clock (mandatory).
|
||||
- "cec" is the HDMI CEC controller main clock (optional).
|
||||
|
||||
- ports: The connectivity of the DWC HDMI TX with the rest of the system is
|
||||
expressed in using ports as specified in the device graph bindings defined
|
||||
in Documentation/devicetree/bindings/graph.txt. The numbering of the ports
|
||||
is platform-specific.
|
|
@ -0,0 +1,102 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/lontium,lt8912b.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Lontium LT8912B MIPI to HDMI Bridge
|
||||
|
||||
maintainers:
|
||||
- Adrien Grassein <adrien.grassein@gmail.com>
|
||||
|
||||
description: |
|
||||
The LT8912B is a bridge device which convert DSI to HDMI
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- lontium,lt8912b
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO connected to active high RESET pin.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Primary MIPI port for MIPI input
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes: true
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: |
|
||||
HDMI port, should be connected to a node compatible with the
|
||||
hdmi-connector binding.
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
i2c4 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hdmi-bridge@48 {
|
||||
compatible = "lontium,lt8912b";
|
||||
reg = <0x48>;
|
||||
reset-gpios = <&max7323 0 GPIO_ACTIVE_LOW>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi_out_in: endpoint {
|
||||
data-lanes = <0 1 2 3>;
|
||||
remote-endpoint = <&mipi_dsi_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&hdmi_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -1,88 +0,0 @@
|
|||
Renesas Gen3 DWC HDMI TX Encoder
|
||||
================================
|
||||
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Shall contain one or more of
|
||||
- "renesas,r8a774a1-hdmi" for R8A774A1 (RZ/G2M) compatible HDMI TX
|
||||
- "renesas,r8a774b1-hdmi" for R8A774B1 (RZ/G2N) compatible HDMI TX
|
||||
- "renesas,r8a774e1-hdmi" for R8A774E1 (RZ/G2H) compatible HDMI TX
|
||||
- "renesas,r8a7795-hdmi" for R8A7795 (R-Car H3) compatible HDMI TX
|
||||
- "renesas,r8a7796-hdmi" for R8A7796 (R-Car M3-W) compatible HDMI TX
|
||||
- "renesas,r8a77961-hdmi" for R8A77961 (R-Car M3-W+) compatible HDMI TX
|
||||
- "renesas,r8a77965-hdmi" for R8A77965 (R-Car M3-N) compatible HDMI TX
|
||||
- "renesas,rcar-gen3-hdmi" for the generic R-Car Gen3 and RZ/G2 compatible
|
||||
HDMI TX
|
||||
|
||||
When compatible with generic versions, nodes must list the SoC-specific
|
||||
version corresponding to the platform first, followed by the
|
||||
family-specific version.
|
||||
|
||||
- reg: See dw_hdmi.txt.
|
||||
- interrupts: HDMI interrupt number
|
||||
- clocks: See dw_hdmi.txt.
|
||||
- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
|
||||
- ports: See dw_hdmi.txt. The DWC HDMI shall have one port numbered 0
|
||||
corresponding to the video input of the controller and one port numbered 1
|
||||
corresponding to its HDMI output, and one port numbered 2 corresponding to
|
||||
sound input of the controller. Each port shall have a single endpoint.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- power-domains: Shall reference the power domain that contains the DWC HDMI,
|
||||
if any.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
hdmi0: hdmi@fead0000 {
|
||||
compatible = "renesas,r8a7795-hdmi", "renesas,rcar-gen3-hdmi";
|
||||
reg = <0 0xfead0000 0 0x10000>;
|
||||
interrupts = <0 389 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_CORE R8A7795_CLK_S0D4>, <&cpg CPG_MOD 729>;
|
||||
clock-names = "iahb", "isfr";
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
dw_hdmi0_in: endpoint {
|
||||
remote-endpoint = <&du_out_hdmi0>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
rcar_dw_hdmi0_out: endpoint {
|
||||
remote-endpoint = <&hdmi0_con>;
|
||||
};
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
rcar_dw_hdmi0_sound_in: endpoint {
|
||||
remote-endpoint = <&hdmi_sound_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hdmi0-out {
|
||||
compatible = "hdmi-connector";
|
||||
label = "HDMI0 OUT";
|
||||
type = "a";
|
||||
|
||||
port {
|
||||
hdmi0_con: endpoint {
|
||||
remote-endpoint = <&rcar_dw_hdmi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,125 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/renesas,dw-hdmi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car DWC HDMI TX Encoder
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
allOf:
|
||||
- $ref: synopsys,dw-hdmi.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r8a774a1-hdmi # for RZ/G2M compatible HDMI TX
|
||||
- renesas,r8a774b1-hdmi # for RZ/G2N compatible HDMI TX
|
||||
- renesas,r8a774e1-hdmi # for RZ/G2H compatible HDMI TX
|
||||
- renesas,r8a7795-hdmi # for R-Car H3 compatible HDMI TX
|
||||
- renesas,r8a7796-hdmi # for R-Car M3-W compatible HDMI TX
|
||||
- renesas,r8a77961-hdmi # for R-Car M3-W+ compatible HDMI TX
|
||||
- renesas,r8a77965-hdmi # for R-Car M3-N compatible HDMI TX
|
||||
- const: renesas,rcar-gen3-hdmi
|
||||
|
||||
reg-io-width:
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Parallel RGB input port
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: HDMI output port
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Sound input port
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- ports
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/power/r8a7795-sysc.h>
|
||||
|
||||
hdmi@fead0000 {
|
||||
compatible = "renesas,r8a7795-hdmi", "renesas,rcar-gen3-hdmi";
|
||||
reg = <0xfead0000 0x10000>;
|
||||
interrupts = <0 389 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_CORE R8A7795_CLK_S0D4>, <&cpg CPG_MOD 729>;
|
||||
clock-names = "iahb", "isfr";
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
dw_hdmi0_in: endpoint {
|
||||
remote-endpoint = <&du_out_hdmi0>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
rcar_dw_hdmi0_out: endpoint {
|
||||
remote-endpoint = <&hdmi0_con>;
|
||||
};
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
rcar_dw_hdmi0_sound_in: endpoint {
|
||||
remote-endpoint = <&hdmi_sound_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hdmi0-out {
|
||||
compatible = "hdmi-connector";
|
||||
label = "HDMI0 OUT";
|
||||
type = "a";
|
||||
|
||||
port {
|
||||
hdmi0_con: endpoint {
|
||||
remote-endpoint = <&rcar_dw_hdmi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,55 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/synopsys,dw-hdmi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Common Properties for Synopsys DesignWare HDMI TX Controller
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
This document defines device tree properties for the Synopsys DesignWare HDMI
|
||||
TX controller (DWC HDMI TX) IP core. It doesn't constitute a full device tree
|
||||
binding specification by itself but is meant to be referenced by device tree
|
||||
bindings for the platform-specific integrations of the DWC HDMI TX.
|
||||
|
||||
When referenced from platform device tree bindings the properties defined in
|
||||
this document are defined as follows. The platform device tree bindings are
|
||||
responsible for defining whether each property is required or optional.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reg-io-width:
|
||||
description:
|
||||
Width (in bytes) of the registers specified by the reg property.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [1, 4]
|
||||
default: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
items:
|
||||
- description: The bus clock for either AHB and APB
|
||||
- description: The internal register configuration clock
|
||||
additionalItems: true
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
items:
|
||||
- const: iahb
|
||||
- const: isfr
|
||||
additionalItems: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
...
|
|
@ -0,0 +1,110 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/fsl,lcdif.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale/NXP i.MX LCD Interface (LCDIF)
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
- Stefan Agner <stefan@agner.ch>
|
||||
|
||||
description: |
|
||||
(e)LCDIF display controller found in the Freescale/NXP i.MX SoCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- fsl,imx23-lcdif
|
||||
- fsl,imx28-lcdif
|
||||
- fsl,imx6sx-lcdif
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,imx6sl-lcdif
|
||||
- fsl,imx6sll-lcdif
|
||||
- fsl,imx6ul-lcdif
|
||||
- fsl,imx7d-lcdif
|
||||
- fsl,imx8mm-lcdif
|
||||
- fsl,imx8mq-lcdif
|
||||
- const: fsl,imx6sx-lcdif
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Pixel clock
|
||||
- description: Bus clock
|
||||
- description: Display AXI clock
|
||||
minItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pix
|
||||
- const: axi
|
||||
- const: disp_axi
|
||||
minItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: The LCDIF output port
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,imx6sx-lcdif
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
required:
|
||||
- clock-names
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
maxItems: 1
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx6sx-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
display-controller@2220000 {
|
||||
compatible = "fsl,imx6sx-lcdif";
|
||||
reg = <0x02220000 0x4000>;
|
||||
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6SX_CLK_LCDIF1_PIX>,
|
||||
<&clks IMX6SX_CLK_LCDIF_APB>,
|
||||
<&clks IMX6SX_CLK_DISPLAY_AXI>;
|
||||
clock-names = "pix", "axi", "disp_axi";
|
||||
|
||||
port {
|
||||
endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -0,0 +1,126 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/imx/fsl,imx6-hdmi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale i.MX6 DWC HDMI TX Encoder
|
||||
|
||||
maintainers:
|
||||
- Philipp Zabel <p.zabel@pengutronix.de>
|
||||
|
||||
description: |
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
allOf:
|
||||
- $ref: ../bridge/synopsys,dw-hdmi.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx6dl-hdmi
|
||||
- fsl,imx6q-hdmi
|
||||
|
||||
reg-io-width:
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
|
||||
ddc-i2c-bus:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
The HDMI DDC bus can be connected to either a system I2C master or the
|
||||
functionally-reduced I2C master contained in the DWC HDMI. When connected
|
||||
to a system I2C master this property contains a phandle to that I2C
|
||||
master controller.
|
||||
|
||||
gpr:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to the iomuxc-gpr region containing the HDMI multiplexer control
|
||||
register.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
description: |
|
||||
This device has four video ports, corresponding to the four inputs of the
|
||||
HDMI multiplexer. Each port shall have a single endpoint.
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: First input of the HDMI multiplexer
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Second input of the HDMI multiplexer
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Third input of the HDMI multiplexer
|
||||
|
||||
port@3:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Fourth input of the HDMI multiplexer
|
||||
|
||||
anyOf:
|
||||
- required:
|
||||
- port@0
|
||||
- required:
|
||||
- port@1
|
||||
- required:
|
||||
- port@2
|
||||
- required:
|
||||
- port@3
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- gpr
|
||||
- interrupts
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx6qdl-clock.h>
|
||||
|
||||
hdmi: hdmi@120000 {
|
||||
reg = <0x00120000 0x9000>;
|
||||
interrupts = <0 115 0x04>;
|
||||
gpr = <&gpr>;
|
||||
clocks = <&clks IMX6QDL_CLK_HDMI_IAHB>,
|
||||
<&clks IMX6QDL_CLK_HDMI_ISFR>;
|
||||
clock-names = "iahb", "isfr";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -1,65 +0,0 @@
|
|||
Freescale i.MX6 DWC HDMI TX Encoder
|
||||
===================================
|
||||
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Shall be one of "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
|
||||
- reg: See dw_hdmi.txt.
|
||||
- interrupts: HDMI interrupt number
|
||||
- clocks: See dw_hdmi.txt.
|
||||
- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
|
||||
- ports: See dw_hdmi.txt. The DWC HDMI shall have between one and four ports,
|
||||
numbered 0 to 3, corresponding to the four inputs of the HDMI multiplexer.
|
||||
Each port shall have a single endpoint.
|
||||
- gpr : Shall contain a phandle to the iomuxc-gpr region containing the HDMI
|
||||
multiplexer control register.
|
||||
|
||||
Optional properties
|
||||
|
||||
- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master
|
||||
or the functionally-reduced I2C master contained in the DWC HDMI. When
|
||||
connected to a system I2C master this property contains a phandle to that
|
||||
I2C master controller.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
gpr: iomuxc-gpr@20e0000 {
|
||||
/* ... */
|
||||
};
|
||||
|
||||
hdmi: hdmi@120000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,imx6q-hdmi";
|
||||
reg = <0x00120000 0x9000>;
|
||||
interrupts = <0 115 0x04>;
|
||||
gpr = <&gpr>;
|
||||
clocks = <&clks 123>, <&clks 124>;
|
||||
clock-names = "iahb", "isfr";
|
||||
ddc-i2c-bus = <&i2c2>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
hdmi_mux_0: endpoint {
|
||||
remote-endpoint = <&ipu1_di0_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
hdmi_mux_1: endpoint {
|
||||
remote-endpoint = <&ipu1_di1_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -22,6 +22,7 @@ properties:
|
|||
- mediatek,mt7623-dpi
|
||||
- mediatek,mt8173-dpi
|
||||
- mediatek,mt8183-dpi
|
||||
- mediatek,mt8192-dpi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -50,15 +51,10 @@ properties:
|
|||
- const: sleep
|
||||
|
||||
port:
|
||||
type: object
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Output port node with endpoint definitions as described in
|
||||
Documentation/devicetree/bindings/graph.txt. This port should be connected
|
||||
to the input port of an attached HDMI or LVDS encoder chip.
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
type: object
|
||||
Output port node. This port should be connected to the input port of an
|
||||
attached HDMI or LVDS encoder chip.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
* Freescale MXS LCD Interface (LCDIF)
|
||||
|
||||
New bindings:
|
||||
=============
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx23-lcdif" for i.MX23.
|
||||
Should be "fsl,imx28-lcdif" for i.MX28.
|
||||
Should be "fsl,imx6sx-lcdif" for i.MX6SX.
|
||||
Should be "fsl,imx8mq-lcdif" for i.MX8MQ.
|
||||
- reg: Address and length of the register set for LCDIF
|
||||
- interrupts: Should contain LCDIF interrupt
|
||||
- clocks: A list of phandle + clock-specifier pairs, one for each
|
||||
entry in 'clock-names'.
|
||||
- clock-names: A list of clock names. For MXSFB it should contain:
|
||||
- "pix" for the LCDIF block clock
|
||||
- (MX6SX-only) "axi", "disp_axi" for the bus interface clock
|
||||
|
||||
Required sub-nodes:
|
||||
- port: The connection to an encoder chip.
|
||||
|
||||
Example:
|
||||
|
||||
lcdif1: display-controller@2220000 {
|
||||
compatible = "fsl,imx6sx-lcdif", "fsl,imx28-lcdif";
|
||||
reg = <0x02220000 0x4000>;
|
||||
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6SX_CLK_LCDIF1_PIX>,
|
||||
<&clks IMX6SX_CLK_LCDIF_APB>,
|
||||
<&clks IMX6SX_CLK_DISPLAY_AXI>;
|
||||
clock-names = "pix", "axi", "disp_axi";
|
||||
|
||||
port {
|
||||
parallel_out: endpoint {
|
||||
remote-endpoint = <&panel_in_parallel>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Deprecated bindings:
|
||||
====================
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx23-lcdif" for i.MX23.
|
||||
Should be "fsl,imx28-lcdif" for i.MX28.
|
||||
- reg: Address and length of the register set for LCDIF
|
||||
- interrupts: Should contain LCDIF interrupts
|
||||
- display: phandle to display node (see below for details)
|
||||
|
||||
* display node
|
||||
|
||||
Required properties:
|
||||
- bits-per-pixel: <16> for RGB565, <32> for RGB888/666.
|
||||
- bus-width: number of data lines. Could be <8>, <16>, <18> or <24>.
|
||||
|
||||
Required sub-node:
|
||||
- display-timings: Refer to binding doc display-timing.txt for details.
|
||||
|
||||
Examples:
|
||||
|
||||
lcdif@80030000 {
|
||||
compatible = "fsl,imx28-lcdif";
|
||||
reg = <0x80030000 2000>;
|
||||
interrupts = <38 86>;
|
||||
|
||||
display: display {
|
||||
bits-per-pixel = <32>;
|
||||
bus-width = <24>;
|
||||
|
||||
display-timings {
|
||||
native-mode = <&timing0>;
|
||||
timing0: timing0 {
|
||||
clock-frequency = <33500000>;
|
||||
hactive = <800>;
|
||||
vactive = <480>;
|
||||
hfront-porch = <164>;
|
||||
hback-porch = <89>;
|
||||
hsync-len = <10>;
|
||||
vback-porch = <23>;
|
||||
vfront-porch = <10>;
|
||||
vsync-len = <10>;
|
||||
hsync-active = <0>;
|
||||
vsync-active = <0>;
|
||||
de-active = <1>;
|
||||
pixelclk-active = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -161,6 +161,8 @@ properties:
|
|||
# Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel
|
||||
- innolux,g121x1-l03
|
||||
# Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
|
||||
- innolux,n116bca-ea1
|
||||
# Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
|
||||
- innolux,n116bge
|
||||
# InnoLux 13.3" FHD (1920x1080) eDP TFT LCD panel
|
||||
- innolux,n125hce-gn1
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
* Renesas R-Car Display Unit (DU)
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: must be one of the following.
|
||||
- "renesas,du-r8a7742" for R8A7742 (RZ/G1H) compatible DU
|
||||
- "renesas,du-r8a7743" for R8A7743 (RZ/G1M) compatible DU
|
||||
- "renesas,du-r8a7744" for R8A7744 (RZ/G1N) compatible DU
|
||||
- "renesas,du-r8a7745" for R8A7745 (RZ/G1E) compatible DU
|
||||
- "renesas,du-r8a77470" for R8A77470 (RZ/G1C) compatible DU
|
||||
- "renesas,du-r8a774a1" for R8A774A1 (RZ/G2M) compatible DU
|
||||
- "renesas,du-r8a774b1" for R8A774B1 (RZ/G2N) compatible DU
|
||||
- "renesas,du-r8a774c0" for R8A774C0 (RZ/G2E) compatible DU
|
||||
- "renesas,du-r8a774e1" for R8A774E1 (RZ/G2H) compatible DU
|
||||
- "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU
|
||||
- "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU
|
||||
- "renesas,du-r8a7791" for R8A7791 (R-Car M2-W) compatible DU
|
||||
- "renesas,du-r8a7792" for R8A7792 (R-Car V2H) compatible DU
|
||||
- "renesas,du-r8a7793" for R8A7793 (R-Car M2-N) compatible DU
|
||||
- "renesas,du-r8a7794" for R8A7794 (R-Car E2) compatible DU
|
||||
- "renesas,du-r8a7795" for R8A7795 (R-Car H3) compatible DU
|
||||
- "renesas,du-r8a7796" for R8A7796 (R-Car M3-W) compatible DU
|
||||
- "renesas,du-r8a77961" for R8A77961 (R-Car M3-W+) compatible DU
|
||||
- "renesas,du-r8a77965" for R8A77965 (R-Car M3-N) compatible DU
|
||||
- "renesas,du-r8a77970" for R8A77970 (R-Car V3M) compatible DU
|
||||
- "renesas,du-r8a77980" for R8A77980 (R-Car V3H) compatible DU
|
||||
- "renesas,du-r8a77990" for R8A77990 (R-Car E3) compatible DU
|
||||
- "renesas,du-r8a77995" for R8A77995 (R-Car D3) compatible DU
|
||||
|
||||
- reg: the memory-mapped I/O registers base address and length
|
||||
|
||||
- interrupts: Interrupt specifiers for the DU interrupts.
|
||||
|
||||
- clocks: A list of phandles + clock-specifier pairs, one for each entry in
|
||||
the clock-names property.
|
||||
- clock-names: Name of the clocks. This property is model-dependent.
|
||||
- R8A7779 uses a single functional clock. The clock doesn't need to be
|
||||
named.
|
||||
- All other DU instances use one functional clock per channel The
|
||||
functional clocks must be named "du.x" with "x" being the channel
|
||||
numerical index.
|
||||
- In addition to the functional clocks, all DU versions also support
|
||||
externally supplied pixel clocks. Those clocks are optional. When
|
||||
supplied they must be named "dclkin.x" with "x" being the input clock
|
||||
numerical index.
|
||||
|
||||
- renesas,cmms: A list of phandles to the CMM instances present in the SoC,
|
||||
one for each available DU channel. The property shall not be specified for
|
||||
SoCs that do not provide any CMM (such as V3M and V3H).
|
||||
|
||||
- renesas,vsps: A list of phandle and channel index tuples to the VSPs that
|
||||
handle the memory interfaces for the DU channels. The phandle identifies the
|
||||
VSP instance that serves the DU channel, and the channel index identifies
|
||||
the LIF instance in that VSP.
|
||||
|
||||
Optional properties:
|
||||
- resets: A list of phandle + reset-specifier pairs, one for each entry in
|
||||
the reset-names property.
|
||||
- reset-names: Names of the resets. This property is model-dependent.
|
||||
- All but R8A7779 use one reset for a group of one or more successive
|
||||
channels. The resets must be named "du.x" with "x" being the numerical
|
||||
index of the lowest channel in the group.
|
||||
|
||||
Required nodes:
|
||||
|
||||
The connections to the DU output video ports are modeled using the OF graph
|
||||
bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
|
||||
The following table lists for each supported model the port number
|
||||
corresponding to each DU output.
|
||||
|
||||
Port0 Port1 Port2 Port3
|
||||
-----------------------------------------------------------------------------
|
||||
R8A7742 (RZ/G1H) DPAD 0 LVDS 0 LVDS 1 -
|
||||
R8A7743 (RZ/G1M) DPAD 0 LVDS 0 - -
|
||||
R8A7744 (RZ/G1N) DPAD 0 LVDS 0 - -
|
||||
R8A7745 (RZ/G1E) DPAD 0 DPAD 1 - -
|
||||
R8A77470 (RZ/G1C) DPAD 0 DPAD 1 LVDS 0 -
|
||||
R8A774A1 (RZ/G2M) DPAD 0 HDMI 0 LVDS 0 -
|
||||
R8A774B1 (RZ/G2N) DPAD 0 HDMI 0 LVDS 0 -
|
||||
R8A774C0 (RZ/G2E) DPAD 0 LVDS 0 LVDS 1 -
|
||||
R8A774E1 (RZ/G2H) DPAD 0 HDMI 0 LVDS 0 -
|
||||
R8A7779 (R-Car H1) DPAD 0 DPAD 1 - -
|
||||
R8A7790 (R-Car H2) DPAD 0 LVDS 0 LVDS 1 -
|
||||
R8A7791 (R-Car M2-W) DPAD 0 LVDS 0 - -
|
||||
R8A7792 (R-Car V2H) DPAD 0 DPAD 1 - -
|
||||
R8A7793 (R-Car M2-N) DPAD 0 LVDS 0 - -
|
||||
R8A7794 (R-Car E2) DPAD 0 DPAD 1 - -
|
||||
R8A7795 (R-Car H3) DPAD 0 HDMI 0 HDMI 1 LVDS 0
|
||||
R8A7796 (R-Car M3-W) DPAD 0 HDMI 0 LVDS 0 -
|
||||
R8A77961 (R-Car M3-W+) DPAD 0 HDMI 0 LVDS 0 -
|
||||
R8A77965 (R-Car M3-N) DPAD 0 HDMI 0 LVDS 0 -
|
||||
R8A77970 (R-Car V3M) DPAD 0 LVDS 0 - -
|
||||
R8A77980 (R-Car V3H) DPAD 0 LVDS 0 - -
|
||||
R8A77990 (R-Car E3) DPAD 0 LVDS 0 LVDS 1 -
|
||||
R8A77995 (R-Car D3) DPAD 0 LVDS 0 LVDS 1 -
|
||||
|
||||
|
||||
Example: R8A7795 (R-Car H3) ES2.0 DU
|
||||
|
||||
du: display@feb00000 {
|
||||
compatible = "renesas,du-r8a7795";
|
||||
reg = <0 0xfeb00000 0 0x80000>;
|
||||
interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 724>,
|
||||
<&cpg CPG_MOD 723>,
|
||||
<&cpg CPG_MOD 722>,
|
||||
<&cpg CPG_MOD 721>;
|
||||
clock-names = "du.0", "du.1", "du.2", "du.3";
|
||||
resets = <&cpg 724>, <&cpg 722>;
|
||||
reset-names = "du.0", "du.2";
|
||||
renesas,cmms = <&cmm0>, <&cmm1>, <&cmm2>, <&cmm3>;
|
||||
renesas,vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
du_out_rgb: endpoint {
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
du_out_hdmi0: endpoint {
|
||||
remote-endpoint = <&dw_hdmi0_in>;
|
||||
};
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
du_out_hdmi1: endpoint {
|
||||
remote-endpoint = <&dw_hdmi1_in>;
|
||||
};
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
du_out_lvds0: endpoint {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,831 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/renesas,du.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car Display Unit (DU)
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
These DT bindings describe the Display Unit embedded in the Renesas R-Car
|
||||
Gen1, R-Car Gen2, R-Car Gen3, RZ/G1 and RZ/G2 SoCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- renesas,du-r8a7742 # for RZ/G1H compatible DU
|
||||
- renesas,du-r8a7743 # for RZ/G1M compatible DU
|
||||
- renesas,du-r8a7744 # for RZ/G1N compatible DU
|
||||
- renesas,du-r8a7745 # for RZ/G1E compatible DU
|
||||
- renesas,du-r8a77470 # for RZ/G1C compatible DU
|
||||
- renesas,du-r8a774a1 # for RZ/G2M compatible DU
|
||||
- renesas,du-r8a774b1 # for RZ/G2N compatible DU
|
||||
- renesas,du-r8a774c0 # for RZ/G2E compatible DU
|
||||
- renesas,du-r8a774e1 # for RZ/G2H compatible DU
|
||||
- renesas,du-r8a7779 # for R-Car H1 compatible DU
|
||||
- renesas,du-r8a7790 # for R-Car H2 compatible DU
|
||||
- renesas,du-r8a7791 # for R-Car M2-W compatible DU
|
||||
- renesas,du-r8a7792 # for R-Car V2H compatible DU
|
||||
- renesas,du-r8a7793 # for R-Car M2-N compatible DU
|
||||
- renesas,du-r8a7794 # for R-Car E2 compatible DU
|
||||
- renesas,du-r8a7795 # for R-Car H3 compatible DU
|
||||
- renesas,du-r8a7796 # for R-Car M3-W compatible DU
|
||||
- renesas,du-r8a77961 # for R-Car M3-W+ compatible DU
|
||||
- renesas,du-r8a77965 # for R-Car M3-N compatible DU
|
||||
- renesas,du-r8a77970 # for R-Car V3M compatible DU
|
||||
- renesas,du-r8a77980 # for R-Car V3H compatible DU
|
||||
- renesas,du-r8a77990 # for R-Car E3 compatible DU
|
||||
- renesas,du-r8a77995 # for R-Car D3 compatible DU
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
# See compatible-specific constraints below.
|
||||
clocks: true
|
||||
clock-names: true
|
||||
interrupts:
|
||||
description: Interrupt specifiers, one per DU channel
|
||||
resets: true
|
||||
reset-names: true
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: |
|
||||
The connections to the DU output video ports are modeled using the OF
|
||||
graph bindings specified in Documentation/devicetree/bindings/graph.txt.
|
||||
The number of ports and their assignment are model-dependent. Each port
|
||||
shall have a single endpoint.
|
||||
|
||||
patternProperties:
|
||||
"^port@[0-3]$":
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
renesas,cmms:
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle-array"
|
||||
description:
|
||||
A list of phandles to the CMM instances present in the SoC, one for each
|
||||
available DU channel.
|
||||
|
||||
renesas,vsps:
|
||||
$ref: "/schemas/types.yaml#/definitions/phandle-array"
|
||||
description:
|
||||
A list of phandle and channel index tuples to the VSPs that handle the
|
||||
memory interfaces for the DU channels. The phandle identifies the VSP
|
||||
instance that serves the DU channel, and the channel index identifies
|
||||
the LIF instance in that VSP.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
- resets
|
||||
- ports
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,du-r8a7779
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
- description: Functional clock
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
- const: du.0
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: DPAD 1
|
||||
# port@2 is TCON, not supported yet
|
||||
port@2: false
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- interrupts
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a7743
|
||||
- renesas,du-r8a7744
|
||||
- renesas,du-r8a7791
|
||||
- renesas,du-r8a7793
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: LVDS 0
|
||||
# port@2 is TCON, not supported yet
|
||||
port@2: false
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a7745
|
||||
- renesas,du-r8a7792
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: DPAD 1
|
||||
port@2: false
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a7794
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: DPAD 1
|
||||
# port@2 is TCON, not supported yet
|
||||
port@2: false
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a77470
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: DPAD 1
|
||||
port@2:
|
||||
description: LVDS 0
|
||||
# port@3 is DVENC, not supported yet
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a7742
|
||||
- renesas,du-r8a7790
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: Functional clock for DU2
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
- description: DU_DOTCLKIN2 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- const: du.2
|
||||
- pattern: '^dclkin\.[012]$'
|
||||
- pattern: '^dclkin\.[012]$'
|
||||
- pattern: '^dclkin\.[012]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 3
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: LVDS 0
|
||||
port@2:
|
||||
description: LVDS 1
|
||||
# port@3 is TCON, not supported yet
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a7795
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 4
|
||||
maxItems: 8
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: Functional clock for DU2
|
||||
- description: Functional clock for DU4
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
- description: DU_DOTCLKIN2 input clock
|
||||
- description: DU_DOTCLKIN3 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 4
|
||||
maxItems: 8
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- const: du.2
|
||||
- const: du.3
|
||||
- pattern: '^dclkin\.[0123]$'
|
||||
- pattern: '^dclkin\.[0123]$'
|
||||
- pattern: '^dclkin\.[0123]$'
|
||||
- pattern: '^dclkin\.[0123]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 4
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.2
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: HDMI 0
|
||||
port@2:
|
||||
description: HDMI 1
|
||||
port@3:
|
||||
description: LVDS 0
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
- port@3
|
||||
|
||||
renesas,cmms:
|
||||
minItems: 4
|
||||
|
||||
renesas,vsps:
|
||||
minItems: 4
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
- renesas,vsps
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a774a1
|
||||
- renesas,du-r8a7796
|
||||
- renesas,du-r8a77961
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: Functional clock for DU2
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
- description: DU_DOTCLKIN2 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- const: du.2
|
||||
- pattern: '^dclkin\.[012]$'
|
||||
- pattern: '^dclkin\.[012]$'
|
||||
- pattern: '^dclkin\.[012]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 3
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.2
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: HDMI 0
|
||||
port@2:
|
||||
description: LVDS 0
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
|
||||
renesas,cmms:
|
||||
minItems: 3
|
||||
|
||||
renesas,vsps:
|
||||
minItems: 3
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
- renesas,vsps
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a774b1
|
||||
- renesas,du-r8a774e1
|
||||
- renesas,du-r8a77965
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: Functional clock for DU3
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
- description: DU_DOTCLKIN3 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 6
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- const: du.3
|
||||
- pattern: '^dclkin\.[013]$'
|
||||
- pattern: '^dclkin\.[013]$'
|
||||
- pattern: '^dclkin\.[013]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 3
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.3
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: HDMI 0
|
||||
port@2:
|
||||
description: LVDS 0
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
|
||||
renesas,cmms:
|
||||
minItems: 3
|
||||
|
||||
renesas,vsps:
|
||||
minItems: 3
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
- renesas,vsps
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a77970
|
||||
- renesas,du-r8a77980
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: du.0
|
||||
- const: dclkin.0
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: LVDS 0
|
||||
port@2: false
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
renesas,vsps:
|
||||
minItems: 1
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
- renesas,vsps
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,du-r8a774c0
|
||||
- renesas,du-r8a77990
|
||||
- renesas,du-r8a77995
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: Functional clock for DU0
|
||||
- description: Functional clock for DU1
|
||||
- description: DU_DOTCLKIN0 input clock
|
||||
- description: DU_DOTCLKIN1 input clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: du.0
|
||||
- const: du.1
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
- pattern: '^dclkin\.[01]$'
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: du.0
|
||||
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPAD 0
|
||||
port@1:
|
||||
description: LVDS 0
|
||||
port@2:
|
||||
description: LVDS 1
|
||||
# port@3 is TCON, not supported yet
|
||||
port@3: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
- port@2
|
||||
|
||||
renesas,cmms:
|
||||
minItems: 2
|
||||
|
||||
renesas,vsps:
|
||||
minItems: 2
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
- reset-names
|
||||
- renesas,vsps
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# R-Car H3 ES2.0 DU
|
||||
- |
|
||||
#include <dt-bindings/clock/renesas-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
display@feb00000 {
|
||||
compatible = "renesas,du-r8a7795";
|
||||
reg = <0xfeb00000 0x80000>;
|
||||
interrupts = <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 724>,
|
||||
<&cpg CPG_MOD 723>,
|
||||
<&cpg CPG_MOD 722>,
|
||||
<&cpg CPG_MOD 721>;
|
||||
clock-names = "du.0", "du.1", "du.2", "du.3";
|
||||
resets = <&cpg 724>, <&cpg 722>;
|
||||
reset-names = "du.0", "du.2";
|
||||
|
||||
renesas,cmms = <&cmm0>, <&cmm1>, <&cmm2>, <&cmm3>;
|
||||
renesas,vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
endpoint {
|
||||
remote-endpoint = <&adv7123_in>;
|
||||
};
|
||||
};
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
endpoint {
|
||||
remote-endpoint = <&dw_hdmi0_in>;
|
||||
};
|
||||
};
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
endpoint {
|
||||
remote-endpoint = <&dw_hdmi1_in>;
|
||||
};
|
||||
};
|
||||
port@3 {
|
||||
reg = <3>;
|
||||
endpoint {
|
||||
remote-endpoint = <&lvds0_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -1,74 +0,0 @@
|
|||
Rockchip DWC HDMI TX Encoder
|
||||
============================
|
||||
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
|
||||
Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
|
||||
following device-specific properties.
|
||||
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be one of the following:
|
||||
"rockchip,rk3228-dw-hdmi"
|
||||
"rockchip,rk3288-dw-hdmi"
|
||||
"rockchip,rk3328-dw-hdmi"
|
||||
"rockchip,rk3399-dw-hdmi"
|
||||
- reg: See dw_hdmi.txt.
|
||||
- reg-io-width: See dw_hdmi.txt. Shall be 4.
|
||||
- interrupts: HDMI interrupt number
|
||||
- clocks: See dw_hdmi.txt.
|
||||
- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
|
||||
- ports: See dw_hdmi.txt. The DWC HDMI shall have a single port numbered 0
|
||||
corresponding to the video input of the controller. The port shall have two
|
||||
endpoints, numbered 0 and 1, connected respectively to the vopb and vopl.
|
||||
- rockchip,grf: Shall reference the GRF to mux vopl/vopb.
|
||||
|
||||
Optional properties
|
||||
|
||||
- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master
|
||||
or the functionally-reduced I2C master contained in the DWC HDMI. When
|
||||
connected to a system I2C master this property contains a phandle to that
|
||||
I2C master controller.
|
||||
- clock-names: See dw_hdmi.txt. The "cec" clock is optional.
|
||||
- clock-names: May contain "cec" as defined in dw_hdmi.txt.
|
||||
- clock-names: May contain "grf", power for grf io.
|
||||
- clock-names: May contain "vpll", external clock for some hdmi phy.
|
||||
- phys: from general PHY binding: the phandle for the PHY device.
|
||||
- phy-names: Should be "hdmi" if phys references an external phy.
|
||||
|
||||
Optional pinctrl entry:
|
||||
- If you have both a "unwedge" and "default" pinctrl entry, dw_hdmi
|
||||
will switch to the unwedge pinctrl state for 10ms if it ever gets an
|
||||
i2c timeout. It's intended that this unwedge pinctrl entry will
|
||||
cause the SDA line to be driven low to work around a hardware
|
||||
errata.
|
||||
|
||||
Example:
|
||||
|
||||
hdmi: hdmi@ff980000 {
|
||||
compatible = "rockchip,rk3288-dw-hdmi";
|
||||
reg = <0xff980000 0x20000>;
|
||||
reg-io-width = <4>;
|
||||
ddc-i2c-bus = <&i2c5>;
|
||||
rockchip,grf = <&grf>;
|
||||
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
|
||||
clock-names = "iahb", "isfr";
|
||||
ports {
|
||||
hdmi_in: port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
hdmi_in_vopb: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&vopb_out_hdmi>;
|
||||
};
|
||||
hdmi_in_vopl: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&vopl_out_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,156 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/rockchip/rockchip,dw-hdmi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip DWC HDMI TX Encoder
|
||||
|
||||
maintainers:
|
||||
- Mark Yao <markyao0591@gmail.com>
|
||||
|
||||
description: |
|
||||
The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
|
||||
with a companion PHY IP.
|
||||
|
||||
allOf:
|
||||
- $ref: ../bridge/synopsys,dw-hdmi.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3228-dw-hdmi
|
||||
- rockchip,rk3288-dw-hdmi
|
||||
- rockchip,rk3328-dw-hdmi
|
||||
- rockchip,rk3399-dw-hdmi
|
||||
|
||||
reg-io-width:
|
||||
const: 4
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
items:
|
||||
- {}
|
||||
- {}
|
||||
# The next three clocks are all optional, but shall be specified in this
|
||||
# order when present.
|
||||
- description: The HDMI CEC controller main clock
|
||||
- description: Power for GRF IO
|
||||
- description: External clock for some HDMI PHY
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
items:
|
||||
- {}
|
||||
- {}
|
||||
- enum:
|
||||
- cec
|
||||
- grf
|
||||
- vpll
|
||||
- enum:
|
||||
- grf
|
||||
- vpll
|
||||
- const: vpll
|
||||
|
||||
ddc-i2c-bus:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
The HDMI DDC bus can be connected to either a system I2C master or the
|
||||
functionally-reduced I2C master contained in the DWC HDMI. When connected
|
||||
to a system I2C master this property contains a phandle to that I2C
|
||||
master controller.
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
description: The HDMI PHY
|
||||
|
||||
phy-names:
|
||||
const: hdmi
|
||||
|
||||
pinctrl-names:
|
||||
description:
|
||||
The unwedge pinctrl entry shall drive the DDC SDA line low. This is
|
||||
intended to work around a hardware errata that can cause the DDC I2C
|
||||
bus to be wedged.
|
||||
items:
|
||||
- const: default
|
||||
- const: unwedge
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: Input of the DWC HDMI TX
|
||||
|
||||
properties:
|
||||
endpoint@0:
|
||||
$ref: /schemas/graph.yaml#/properties/endpoint
|
||||
description: Connection to the VOPB
|
||||
|
||||
endpoint@1:
|
||||
$ref: /schemas/graph.yaml#/properties/endpoint
|
||||
description: Connection to the VOPL
|
||||
|
||||
required:
|
||||
- endpoint@0
|
||||
- endpoint@1
|
||||
|
||||
required:
|
||||
- port
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to the GRF to mux vopl/vopb.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-io-width
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- ports
|
||||
- rockchip,grf
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3288-cru.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
hdmi: hdmi@ff980000 {
|
||||
compatible = "rockchip,rk3288-dw-hdmi";
|
||||
reg = <0xff980000 0x20000>;
|
||||
reg-io-width = <4>;
|
||||
ddc-i2c-bus = <&i2c5>;
|
||||
rockchip,grf = <&grf>;
|
||||
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
|
||||
clock-names = "iahb", "isfr";
|
||||
|
||||
ports {
|
||||
port {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hdmi_in_vopb: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&vopb_out_hdmi>;
|
||||
};
|
||||
hdmi_in_vopl: endpoint@1 {
|
||||
reg = <1>;
|
||||
remote-endpoint = <&vopl_out_hdmi>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -257,3 +257,79 @@ fences in the kernel. This means:
|
|||
userspace is allowed to use userspace fencing or long running compute
|
||||
workloads. This also means no implicit fencing for shared buffers in these
|
||||
cases.
|
||||
|
||||
Recoverable Hardware Page Faults Implications
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Modern hardware supports recoverable page faults, which has a lot of
|
||||
implications for DMA fences.
|
||||
|
||||
First, a pending page fault obviously holds up the work that's running on the
|
||||
accelerator and a memory allocation is usually required to resolve the fault.
|
||||
But memory allocations are not allowed to gate completion of DMA fences, which
|
||||
means any workload using recoverable page faults cannot use DMA fences for
|
||||
synchronization. Synchronization fences controlled by userspace must be used
|
||||
instead.
|
||||
|
||||
On GPUs this poses a problem, because current desktop compositor protocols on
|
||||
Linux rely on DMA fences, which means without an entirely new userspace stack
|
||||
built on top of userspace fences, they cannot benefit from recoverable page
|
||||
faults. Specifically this means implicit synchronization will not be possible.
|
||||
The exception is when page faults are only used as migration hints and never to
|
||||
on-demand fill a memory request. For now this means recoverable page
|
||||
faults on GPUs are limited to pure compute workloads.
|
||||
|
||||
Furthermore GPUs usually have shared resources between the 3D rendering and
|
||||
compute side, like compute units or command submission engines. If both a 3D
|
||||
job with a DMA fence and a compute workload using recoverable page faults are
|
||||
pending they could deadlock:
|
||||
|
||||
- The 3D workload might need to wait for the compute job to finish and release
|
||||
hardware resources first.
|
||||
|
||||
- The compute workload might be stuck in a page fault, because the memory
|
||||
allocation is waiting for the DMA fence of the 3D workload to complete.
|
||||
|
||||
There are a few options to prevent this problem, one of which drivers need to
|
||||
ensure:
|
||||
|
||||
- Compute workloads can always be preempted, even when a page fault is pending
|
||||
and not yet repaired. Not all hardware supports this.
|
||||
|
||||
- DMA fence workloads and workloads which need page fault handling have
|
||||
independent hardware resources to guarantee forward progress. This could be
|
||||
achieved through e.g. through dedicated engines and minimal compute unit
|
||||
reservations for DMA fence workloads.
|
||||
|
||||
- The reservation approach could be further refined by only reserving the
|
||||
hardware resources for DMA fence workloads when they are in-flight. This must
|
||||
cover the time from when the DMA fence is visible to other threads up to
|
||||
moment when fence is completed through dma_fence_signal().
|
||||
|
||||
- As a last resort, if the hardware provides no useful reservation mechanics,
|
||||
all workloads must be flushed from the GPU when switching between jobs
|
||||
requiring DMA fences or jobs requiring page fault handling: This means all DMA
|
||||
fences must complete before a compute job with page fault handling can be
|
||||
inserted into the scheduler queue. And vice versa, before a DMA fence can be
|
||||
made visible anywhere in the system, all compute workloads must be preempted
|
||||
to guarantee all pending GPU page faults are flushed.
|
||||
|
||||
- Only a fairly theoretical option would be to untangle these dependencies when
|
||||
allocating memory to repair hardware page faults, either through separate
|
||||
memory blocks or runtime tracking of the full dependency graph of all DMA
|
||||
fences. This results very wide impact on the kernel, since resolving the page
|
||||
on the CPU side can itself involve a page fault. It is much more feasible and
|
||||
robust to limit the impact of handling hardware page faults to the specific
|
||||
driver.
|
||||
|
||||
Note that workloads that run on independent hardware like copy engines or other
|
||||
GPUs do not have any impact. This allows us to keep using DMA fences internally
|
||||
in the kernel even for resolving hardware page faults, e.g. by using copy
|
||||
engines to clear or copy memory needed to resolve the page fault.
|
||||
|
||||
In some ways this page fault problem is a special case of the `Infinite DMA
|
||||
Fences` discussions: Infinite fences from compute workloads are allowed to
|
||||
depend on DMA fences, but not the other way around. And not even the page fault
|
||||
problem is new, because some other CPU thread in userspace might
|
||||
hit a page fault which holds up a userspace fence - supporting page faults on
|
||||
GPUs doesn't anything fundamentally new.
|
||||
|
|
|
@ -80,6 +80,18 @@ Atomic State Helper Reference
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c
|
||||
:export:
|
||||
|
||||
GEM Atomic Helper Reference
|
||||
---------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_atomic_helper.c
|
||||
:doc: overview
|
||||
|
||||
.. kernel-doc:: include/drm/drm_gem_atomic_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_gem_atomic_helper.c
|
||||
:export:
|
||||
|
||||
Simple KMS Helper Reference
|
||||
===========================
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ Linux GPU Driver Developer's Guide
|
|||
vga-switcheroo
|
||||
vgaarbiter
|
||||
todo
|
||||
rfc/index
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
===============
|
||||
GPU RFC Section
|
||||
===============
|
||||
|
||||
For complex work, especially new uapi, it is often good to nail the high level
|
||||
design issues before getting lost in the code details. This section is meant to
|
||||
host such documentation:
|
||||
|
||||
* Each RFC should be a section in this file, explaining the goal and main design
|
||||
considerations. Especially for uapi make sure you Cc: all relevant project
|
||||
mailing lists and involved people outside of dri-devel.
|
||||
|
||||
* For uapi structures add a file to this directory with and then pull the
|
||||
kerneldoc in like with real uapi headers.
|
||||
|
||||
* Once the code has landed move all the documentation to the right places in
|
||||
the main core, helper or driver sections.
|
|
@ -459,52 +459,6 @@ Contact: Emil Velikov, respective driver maintainers
|
|||
|
||||
Level: Intermediate
|
||||
|
||||
Plumb drm_atomic_state all over
|
||||
-------------------------------
|
||||
|
||||
Currently various atomic functions take just a single or a handful of
|
||||
object states (eg. plane state). While that single object state can
|
||||
suffice for some simple cases, we often have to dig out additional
|
||||
object states for dealing with various dependencies between the individual
|
||||
objects or the hardware they represent. The process of digging out the
|
||||
additional states is rather non-intuitive and error prone.
|
||||
|
||||
To fix that most functions should rather take the overall
|
||||
drm_atomic_state as one of their parameters. The other parameters
|
||||
would generally be the object(s) we mainly want to interact with.
|
||||
|
||||
For example, instead of
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int (*atomic_check)(struct drm_plane *plane, struct drm_plane_state *state);
|
||||
|
||||
we would have something like
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int (*atomic_check)(struct drm_plane *plane, struct drm_atomic_state *state);
|
||||
|
||||
The implementation can then trivially gain access to any required object
|
||||
state(s) via drm_atomic_get_plane_state(), drm_atomic_get_new_plane_state(),
|
||||
drm_atomic_get_old_plane_state(), and their equivalents for
|
||||
other object types.
|
||||
|
||||
Additionally many drivers currently access the object->state pointer
|
||||
directly in their commit functions. That is not going to work if we
|
||||
eg. want to allow deeper commit pipelines as those pointers could
|
||||
then point to the states corresponding to a future commit instead of
|
||||
the current commit we're trying to process. Also non-blocking commits
|
||||
execute locklessly so there are serious concerns with dereferencing
|
||||
the object->state pointers without holding the locks that protect them.
|
||||
Use of drm_atomic_get_new_plane_state(), drm_atomic_get_old_plane_state(),
|
||||
etc. avoids these problems as well since they relate to a specific
|
||||
commit via the passed in drm_atomic_state.
|
||||
|
||||
Contact: Ville Syrjälä, Daniel Vetter
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Use struct dma_buf_map throughout codebase
|
||||
------------------------------------------
|
||||
|
||||
|
@ -596,20 +550,24 @@ Contact: Daniel Vetter
|
|||
|
||||
Level: Intermediate
|
||||
|
||||
KMS cleanups
|
||||
------------
|
||||
Object lifetime fixes
|
||||
---------------------
|
||||
|
||||
Some of these date from the very introduction of KMS in 2008 ...
|
||||
There's two related issues here
|
||||
|
||||
- Make ->funcs and ->helper_private vtables optional. There's a bunch of empty
|
||||
function tables in drivers, but before we can remove them we need to make sure
|
||||
that all the users in helpers and drivers do correctly check for a NULL
|
||||
vtable.
|
||||
- Cleanup up the various ->destroy callbacks, which often are all the same
|
||||
simple code.
|
||||
|
||||
- Cleanup up the various ->destroy callbacks. A lot of them just wrapt the
|
||||
drm_*_cleanup implementations and can be removed. Some tack a kfree() at the
|
||||
end, for which we could add drm_*_cleanup_kfree(). And then there's the (for
|
||||
historical reasons) misnamed drm_primary_helper_destroy() function.
|
||||
- Lots of drivers erroneously allocate DRM modeset objects using devm_kzalloc,
|
||||
which results in use-after free issues on driver unload. This can be serious
|
||||
trouble even for drivers for hardware integrated on the SoC due to
|
||||
EPROBE_DEFERRED backoff.
|
||||
|
||||
Both these problems can be solved by switching over to drmm_kzalloc(), and the
|
||||
various convenience wrappers provided, e.g. drmm_crtc_alloc_with_planes(),
|
||||
drmm_universal_plane_alloc(), ... and so on.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
|
@ -666,8 +624,6 @@ See the documentation of :ref:`VKMS <vkms>` for more details. This is an ideal
|
|||
internship task, since it only requires a virtual machine and can be sized to
|
||||
fit the available time.
|
||||
|
||||
Contact: Daniel Vetter
|
||||
|
||||
Level: See details
|
||||
|
||||
Backlight Refactoring
|
||||
|
@ -721,7 +677,7 @@ Outside DRM
|
|||
Convert fbdev drivers to DRM
|
||||
----------------------------
|
||||
|
||||
There are plenty of fbdev drivers for older hardware. Some hwardware has
|
||||
There are plenty of fbdev drivers for older hardware. Some hardware has
|
||||
become obsolete, but some still provides good(-enough) framebuffers. The
|
||||
drivers that are still useful should be converted to DRM and afterwards
|
||||
removed from fbdev.
|
||||
|
|
30
MAINTAINERS
30
MAINTAINERS
|
@ -1326,7 +1326,7 @@ ARC PGU DRM DRIVER
|
|||
M: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/display/snps,arcpgu.txt
|
||||
F: drivers/gpu/drm/arc/
|
||||
F: drivers/gpu/drm/tiny/arcpgu.c
|
||||
|
||||
ARCNET NETWORK LAYER
|
||||
M: Michael Grzeschik <m.grzeschik@pengutronix.de>
|
||||
|
@ -5641,6 +5641,12 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/display/panel/boe,himax8279d.yaml
|
||||
F: drivers/gpu/drm/panel/panel-boe-himax8279d.c
|
||||
|
||||
DRM DRIVER FOR CHIPONE ICN6211 MIPI-DSI to RGB CONVERTER BRIDGE
|
||||
M: Jagan Teki <jagan@amarulasolutions.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/bridge/chipone,icn6211.yaml
|
||||
F: drivers/gpu/drm/bridge/chipone-icn6211.c
|
||||
|
||||
DRM DRIVER FOR FARADAY TVE200 TV ENCODER
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
S: Maintained
|
||||
|
@ -5659,6 +5665,14 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml
|
||||
F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
|
||||
|
||||
DRM DRIVER FOR GENERIC USB DISPLAY
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
S: Maintained
|
||||
W: https://github.com/notro/gud/wiki
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: drivers/gpu/drm/gud/
|
||||
F: include/drm/gud.h
|
||||
|
||||
DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
|
||||
M: Hans de Goede <hdegoede@redhat.com>
|
||||
S: Maintained
|
||||
|
@ -5967,6 +5981,7 @@ F: drivers/gpu/drm/atmel-hlcdc/
|
|||
DRM DRIVERS FOR BRIDGE CHIPS
|
||||
M: Andrzej Hajda <a.hajda@samsung.com>
|
||||
M: Neil Armstrong <narmstrong@baylibre.com>
|
||||
M: Robert Foss <robert.foss@linaro.org>
|
||||
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
|
||||
R: Jonas Karlman <jonas@kwiboo.se>
|
||||
R: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
|
@ -6036,6 +6051,7 @@ DRM DRIVERS FOR MEDIATEK
|
|||
M: Chun-Kuang Hu <chunkuang.hu@kernel.org>
|
||||
M: Philipp Zabel <p.zabel@pengutronix.de>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/display/mediatek/
|
||||
F: drivers/gpu/drm/mediatek/
|
||||
|
@ -6061,9 +6077,9 @@ L: dri-devel@lists.freedesktop.org
|
|||
L: linux-renesas-soc@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://linuxtv.org/pinchartl/media drm/du/next
|
||||
F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
|
||||
F: Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.yaml
|
||||
F: Documentation/devicetree/bindings/display/bridge/renesas,lvds.yaml
|
||||
F: Documentation/devicetree/bindings/display/renesas,du.txt
|
||||
F: Documentation/devicetree/bindings/display/renesas,du.yaml
|
||||
F: drivers/gpu/drm/rcar-du/
|
||||
F: drivers/gpu/drm/shmobile/
|
||||
F: include/linux/platform_data/shmob_drm.h
|
||||
|
@ -10572,6 +10588,12 @@ S: Maintained
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
|
||||
F: drivers/hid/hid-lg-g15.c
|
||||
|
||||
LONTIUM LT8912B MIPI TO HDMI BRIDGE
|
||||
M: Adrien Grassein <adrien.grassein@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml
|
||||
F: drivers/gpu/drm/bridge/lontium-lt8912b.c
|
||||
|
||||
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
|
||||
M: Sathya Prakash <sathya.prakash@broadcom.com>
|
||||
M: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
|
||||
|
@ -12394,7 +12416,7 @@ M: Stefan Agner <stefan@agner.ch>
|
|||
L: dri-devel@lists.freedesktop.org
|
||||
S: Supported
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/display/mxsfb.txt
|
||||
F: Documentation/devicetree/bindings/display/fsl,lcdif.yaml
|
||||
F: drivers/gpu/drm/mxsfb/
|
||||
|
||||
MYLEX DAC960 PCI RAID Controller
|
||||
|
|
|
@ -551,6 +551,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
|
|||
INTEL_EHL_IDS(&gen11_early_ops),
|
||||
INTEL_TGL_12_IDS(&gen11_early_ops),
|
||||
INTEL_RKL_IDS(&gen11_early_ops),
|
||||
INTEL_ADLS_IDS(&gen11_early_ops),
|
||||
};
|
||||
|
||||
struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -206,6 +207,40 @@ struct clk_hw *__clk_hw_register_mux(struct device *dev, struct device_node *np,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_hw_register_mux);
|
||||
|
||||
static void devm_clk_hw_release_mux(struct device *dev, void *res)
|
||||
{
|
||||
clk_hw_unregister_mux(*(struct clk_hw **)res);
|
||||
}
|
||||
|
||||
struct clk_hw *__devm_clk_hw_register_mux(struct device *dev, struct device_node *np,
|
||||
const char *name, u8 num_parents,
|
||||
const char * const *parent_names,
|
||||
const struct clk_hw **parent_hws,
|
||||
const struct clk_parent_data *parent_data,
|
||||
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
|
||||
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw **ptr, *hw;
|
||||
|
||||
ptr = devres_alloc(devm_clk_hw_release_mux, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hw = __clk_hw_register_mux(dev, np, name, num_parents, parent_names, parent_hws,
|
||||
parent_data, flags, reg, shift, mask,
|
||||
clk_mux_flags, table, lock);
|
||||
|
||||
if (!IS_ERR(hw)) {
|
||||
*ptr = hw;
|
||||
devres_add(dev, ptr);
|
||||
} else {
|
||||
devres_free(ptr);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__devm_clk_hw_register_mux);
|
||||
|
||||
struct clk *clk_register_mux_table(struct device *dev, const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
|
||||
|
|
|
@ -123,7 +123,9 @@ static const struct dma_fence_ops dma_fence_stub_ops = {
|
|||
/**
|
||||
* dma_fence_get_stub - return a signaled fence
|
||||
*
|
||||
* Return a stub fence which is already signaled.
|
||||
* Return a stub fence which is already signaled. The fence's
|
||||
* timestamp corresponds to the first time after boot this
|
||||
* function is called.
|
||||
*/
|
||||
struct dma_fence *dma_fence_get_stub(void)
|
||||
{
|
||||
|
@ -141,6 +143,29 @@ struct dma_fence *dma_fence_get_stub(void)
|
|||
}
|
||||
EXPORT_SYMBOL(dma_fence_get_stub);
|
||||
|
||||
/**
|
||||
* dma_fence_allocate_private_stub - return a private, signaled fence
|
||||
*
|
||||
* Return a newly allocated and signaled stub fence.
|
||||
*/
|
||||
struct dma_fence *dma_fence_allocate_private_stub(void)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
||||
if (fence == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dma_fence_init(fence,
|
||||
&dma_fence_stub_ops,
|
||||
&dma_fence_stub_lock,
|
||||
0, 0);
|
||||
dma_fence_signal(fence);
|
||||
|
||||
return fence;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_fence_allocate_private_stub);
|
||||
|
||||
/**
|
||||
* dma_fence_context_alloc - allocate an array of fence contexts
|
||||
* @num: amount of contexts to allocate
|
||||
|
|
|
@ -202,6 +202,18 @@ void *dma_heap_get_drvdata(struct dma_heap *heap)
|
|||
return heap->priv;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_heap_get_name() - get heap name
|
||||
* @heap: DMA-Heap to retrieve private data for
|
||||
*
|
||||
* Returns:
|
||||
* The char* for the heap name.
|
||||
*/
|
||||
const char *dma_heap_get_name(struct dma_heap *heap)
|
||||
{
|
||||
return heap->name;
|
||||
}
|
||||
|
||||
struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)
|
||||
{
|
||||
struct dma_heap *heap, *h, *err_ret;
|
||||
|
|
|
@ -339,6 +339,7 @@ static struct dma_buf *cma_heap_allocate(struct dma_heap *heap,
|
|||
buffer->pagecount = pagecount;
|
||||
|
||||
/* create the dmabuf */
|
||||
exp_info.exp_name = dma_heap_get_name(heap);
|
||||
exp_info.ops = &cma_heap_buf_ops;
|
||||
exp_info.size = buffer->len;
|
||||
exp_info.flags = fd_flags;
|
||||
|
|
|
@ -390,6 +390,7 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
|
|||
}
|
||||
|
||||
/* create the dmabuf */
|
||||
exp_info.exp_name = dma_heap_get_name(heap);
|
||||
exp_info.ops = &system_heap_buf_ops;
|
||||
exp_info.size = buffer->len;
|
||||
exp_info.flags = fd_flags;
|
||||
|
|
|
@ -352,8 +352,6 @@ source "drivers/gpu/drm/vc4/Kconfig"
|
|||
|
||||
source "drivers/gpu/drm/etnaviv/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/arc/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/hisilicon/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/mediatek/Kconfig"
|
||||
|
@ -386,6 +384,8 @@ source "drivers/gpu/drm/tidss/Kconfig"
|
|||
|
||||
source "drivers/gpu/drm/xlnx/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/gud/Kconfig"
|
||||
|
||||
# Keep legacy drivers last
|
||||
|
||||
menuconfig DRM_LEGACY
|
||||
|
|
|
@ -7,7 +7,7 @@ drm-y := 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 \
|
||||
drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \
|
||||
drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o drm_displayid.o \
|
||||
drm_encoder_slave.o \
|
||||
drm_trace_points.o drm_prime.o \
|
||||
drm_rect.o drm_vma_manager.o drm_flip_work.o \
|
||||
|
@ -44,7 +44,8 @@ drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o drm_dp_helper.o \
|
|||
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
|
||||
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
|
||||
drm_simple_kms_helper.o drm_modeset_helper.o \
|
||||
drm_scdc_helper.o drm_gem_framebuffer_helper.o \
|
||||
drm_scdc_helper.o drm_gem_atomic_helper.o \
|
||||
drm_gem_framebuffer_helper.o \
|
||||
drm_atomic_state_helper.o drm_damage_helper.o \
|
||||
drm_format_helper.o drm_self_refresh_helper.o
|
||||
|
||||
|
@ -110,7 +111,6 @@ obj-y += panel/
|
|||
obj-y += bridge/
|
||||
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
|
||||
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
|
||||
obj-$(CONFIG_DRM_ARCPGU)+= arc/
|
||||
obj-y += hisilicon/
|
||||
obj-$(CONFIG_DRM_ZTE) += zte/
|
||||
obj-$(CONFIG_DRM_MXSFB) += mxsfb/
|
||||
|
@ -125,3 +125,4 @@ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
|
|||
obj-$(CONFIG_DRM_MCDE) += mcde/
|
||||
obj-$(CONFIG_DRM_TIDSS) += tidss/
|
||||
obj-y += xlnx/
|
||||
obj-y += gud/
|
||||
|
|
|
@ -34,15 +34,6 @@ config DRM_AMDGPU_USERPTR
|
|||
This option selects CONFIG_HMM and CONFIG_HMM_MIRROR if it
|
||||
isn't already selected to enabled full userptr support.
|
||||
|
||||
config DRM_AMDGPU_GART_DEBUGFS
|
||||
bool "Allow GART access through debugfs"
|
||||
depends on DRM_AMDGPU
|
||||
depends on DEBUG_FS
|
||||
default n
|
||||
help
|
||||
Selecting this option creates a debugfs file to inspect the mapped
|
||||
pages. Uses more memory for housekeeping, enable only for debugging.
|
||||
|
||||
source "drivers/gpu/drm/amd/acp/Kconfig"
|
||||
source "drivers/gpu/drm/amd/display/Kconfig"
|
||||
source "drivers/gpu/drm/amd/amdkfd/Kconfig"
|
||||
|
|
|
@ -71,7 +71,7 @@ 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
|
||||
nbio_v7_2.o dimgrey_cavefish_reg_init.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o
|
||||
|
||||
# add DF block
|
||||
amdgpu-y += \
|
||||
|
@ -83,11 +83,12 @@ amdgpu-y += \
|
|||
gmc_v7_0.o \
|
||||
gmc_v8_0.o \
|
||||
gfxhub_v1_0.o mmhub_v1_0.o gmc_v9_0.o gfxhub_v1_1.o mmhub_v9_4.o \
|
||||
gfxhub_v2_0.o mmhub_v2_0.o gmc_v10_0.o gfxhub_v2_1.o mmhub_v2_3.o
|
||||
gfxhub_v2_0.o mmhub_v2_0.o gmc_v10_0.o gfxhub_v2_1.o mmhub_v2_3.o \
|
||||
mmhub_v1_7.o
|
||||
|
||||
# add UMC block
|
||||
amdgpu-y += \
|
||||
umc_v6_1.o umc_v6_0.o umc_v8_7.o
|
||||
umc_v6_0.o umc_v6_1.o umc_v6_7.o umc_v8_7.o
|
||||
|
||||
# add IH block
|
||||
amdgpu-y += \
|
||||
|
@ -106,7 +107,8 @@ amdgpu-y += \
|
|||
psp_v3_1.o \
|
||||
psp_v10_0.o \
|
||||
psp_v11_0.o \
|
||||
psp_v12_0.o
|
||||
psp_v12_0.o \
|
||||
psp_v13_0.o
|
||||
|
||||
# add DCE block
|
||||
amdgpu-y += \
|
||||
|
@ -121,6 +123,7 @@ amdgpu-y += \
|
|||
gfx_v8_0.o \
|
||||
gfx_v9_0.o \
|
||||
gfx_v9_4.o \
|
||||
gfx_v9_4_2.o \
|
||||
gfx_v10_0.o
|
||||
|
||||
# add async DMA block
|
||||
|
@ -129,6 +132,7 @@ amdgpu-y += \
|
|||
sdma_v2_4.o \
|
||||
sdma_v3_0.o \
|
||||
sdma_v4_0.o \
|
||||
sdma_v4_4.o \
|
||||
sdma_v5_0.o \
|
||||
sdma_v5_2.o
|
||||
|
||||
|
@ -172,11 +176,17 @@ amdgpu-y += \
|
|||
amdgpu-y += \
|
||||
smuio_v9_0.o \
|
||||
smuio_v11_0.o \
|
||||
smuio_v11_0_6.o
|
||||
smuio_v11_0_6.o \
|
||||
smuio_v13_0.o
|
||||
|
||||
# add reset block
|
||||
amdgpu-y += \
|
||||
amdgpu_reset.o
|
||||
|
||||
# add amdkfd interfaces
|
||||
amdgpu-y += amdgpu_amdkfd.o
|
||||
|
||||
|
||||
ifneq ($(CONFIG_HSA_AMD),)
|
||||
AMDKFD_PATH := ../amdkfd
|
||||
include $(FULL_AMD_PATH)/amdkfd/Makefile
|
||||
|
@ -187,6 +197,7 @@ amdgpu-y += \
|
|||
amdgpu_amdkfd_gfx_v8.o \
|
||||
amdgpu_amdkfd_gfx_v9.o \
|
||||
amdgpu_amdkfd_arcturus.o \
|
||||
amdgpu_amdkfd_aldebaran.o \
|
||||
amdgpu_amdkfd_gfx_v10.o \
|
||||
amdgpu_amdkfd_gfx_v10_3.o
|
||||
|
||||
|
|
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* 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 "aldebaran.h"
|
||||
#include "amdgpu_reset.h"
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_dpm.h"
|
||||
#include "amdgpu_job.h"
|
||||
#include "amdgpu_ring.h"
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_psp.h"
|
||||
#include "amdgpu_xgmi.h"
|
||||
|
||||
static struct amdgpu_reset_handler *
|
||||
aldebaran_get_reset_handler(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *reset_context)
|
||||
{
|
||||
struct amdgpu_reset_handler *handler;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
|
||||
|
||||
if (reset_context->method != AMD_RESET_METHOD_NONE) {
|
||||
dev_dbg(adev->dev, "Getting reset handler for method %d\n",
|
||||
reset_context->method);
|
||||
list_for_each_entry(handler, &reset_ctl->reset_handlers,
|
||||
handler_list) {
|
||||
if (handler->reset_method == reset_context->method)
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
if (adev->gmc.xgmi.connected_to_cpu) {
|
||||
list_for_each_entry(handler, &reset_ctl->reset_handlers,
|
||||
handler_list) {
|
||||
if (handler->reset_method == AMD_RESET_METHOD_MODE2) {
|
||||
reset_context->method = AMD_RESET_METHOD_MODE2;
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(adev->dev, "Reset handler not found!\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int aldebaran_mode2_suspend_ip(struct amdgpu_device *adev)
|
||||
{
|
||||
int r, i;
|
||||
|
||||
amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
|
||||
amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
|
||||
|
||||
for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
|
||||
if (!(adev->ip_blocks[i].version->type ==
|
||||
AMD_IP_BLOCK_TYPE_GFX ||
|
||||
adev->ip_blocks[i].version->type ==
|
||||
AMD_IP_BLOCK_TYPE_SDMA))
|
||||
continue;
|
||||
|
||||
r = adev->ip_blocks[i].version->funcs->suspend(adev);
|
||||
|
||||
if (r) {
|
||||
dev_err(adev->dev,
|
||||
"suspend of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
adev->ip_blocks[i].status.hw = false;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
aldebaran_mode2_prepare_hwcontext(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *reset_context)
|
||||
{
|
||||
int r = 0;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
|
||||
|
||||
dev_dbg(adev->dev, "Aldebaran prepare hw context\n");
|
||||
/* Don't suspend on bare metal if we are not going to HW reset the ASIC */
|
||||
if (!amdgpu_sriov_vf(adev))
|
||||
r = aldebaran_mode2_suspend_ip(adev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void aldebaran_async_reset(struct work_struct *work)
|
||||
{
|
||||
struct amdgpu_reset_handler *handler;
|
||||
struct amdgpu_reset_control *reset_ctl =
|
||||
container_of(work, struct amdgpu_reset_control, reset_work);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
|
||||
|
||||
list_for_each_entry(handler, &reset_ctl->reset_handlers,
|
||||
handler_list) {
|
||||
if (handler->reset_method == reset_ctl->active_reset) {
|
||||
dev_dbg(adev->dev, "Resetting device\n");
|
||||
handler->do_reset(adev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int aldebaran_mode2_reset(struct amdgpu_device *adev)
|
||||
{
|
||||
/* disable BM */
|
||||
pci_clear_master(adev->pdev);
|
||||
adev->asic_reset_res = amdgpu_dpm_mode2_reset(adev);
|
||||
return adev->asic_reset_res;
|
||||
}
|
||||
|
||||
static int
|
||||
aldebaran_mode2_perform_reset(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *reset_context)
|
||||
{
|
||||
struct amdgpu_device *tmp_adev = NULL;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(adev->dev, "aldebaran perform hw reset\n");
|
||||
if (reset_context->hive == NULL) {
|
||||
/* Wrong context, return error */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(tmp_adev, &reset_context->hive->device_list,
|
||||
gmc.xgmi.head) {
|
||||
mutex_lock(&tmp_adev->reset_cntl->reset_lock);
|
||||
tmp_adev->reset_cntl->active_reset = AMD_RESET_METHOD_MODE2;
|
||||
}
|
||||
/*
|
||||
* Mode2 reset doesn't need any sync between nodes in XGMI hive, instead launch
|
||||
* them together so that they can be completed asynchronously on multiple nodes
|
||||
*/
|
||||
list_for_each_entry(tmp_adev, &reset_context->hive->device_list,
|
||||
gmc.xgmi.head) {
|
||||
/* For XGMI run all resets in parallel to speed up the process */
|
||||
if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
|
||||
if (!queue_work(system_unbound_wq,
|
||||
&tmp_adev->reset_cntl->reset_work))
|
||||
r = -EALREADY;
|
||||
} else
|
||||
r = aldebaran_mode2_reset(tmp_adev);
|
||||
if (r) {
|
||||
dev_err(tmp_adev->dev,
|
||||
"ASIC reset failed with error, %d for drm dev, %s",
|
||||
r, adev_to_drm(tmp_adev)->unique);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* For XGMI wait for all resets to complete before proceed */
|
||||
if (!r) {
|
||||
list_for_each_entry(tmp_adev,
|
||||
&reset_context->hive->device_list,
|
||||
gmc.xgmi.head) {
|
||||
if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
|
||||
flush_work(&tmp_adev->reset_cntl->reset_work);
|
||||
r = tmp_adev->asic_reset_res;
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(tmp_adev, &reset_context->hive->device_list,
|
||||
gmc.xgmi.head) {
|
||||
mutex_unlock(&tmp_adev->reset_cntl->reset_lock);
|
||||
tmp_adev->reset_cntl->active_reset = AMD_RESET_METHOD_NONE;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int aldebaran_mode2_restore_ip(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_firmware_info *ucode_list[AMDGPU_UCODE_ID_MAXIMUM];
|
||||
struct amdgpu_firmware_info *ucode;
|
||||
struct amdgpu_ip_block *cmn_block;
|
||||
int ucode_count = 0;
|
||||
int i, r;
|
||||
|
||||
dev_dbg(adev->dev, "Reloading ucodes after reset\n");
|
||||
for (i = 0; i < adev->firmware.max_ucodes; i++) {
|
||||
ucode = &adev->firmware.ucode[i];
|
||||
if (!ucode->fw)
|
||||
continue;
|
||||
switch (ucode->ucode_id) {
|
||||
case AMDGPU_UCODE_ID_SDMA0:
|
||||
case AMDGPU_UCODE_ID_SDMA1:
|
||||
case AMDGPU_UCODE_ID_SDMA2:
|
||||
case AMDGPU_UCODE_ID_SDMA3:
|
||||
case AMDGPU_UCODE_ID_SDMA4:
|
||||
case AMDGPU_UCODE_ID_SDMA5:
|
||||
case AMDGPU_UCODE_ID_SDMA6:
|
||||
case AMDGPU_UCODE_ID_SDMA7:
|
||||
case AMDGPU_UCODE_ID_CP_MEC1:
|
||||
case AMDGPU_UCODE_ID_CP_MEC1_JT:
|
||||
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_CNTL:
|
||||
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_GPM_MEM:
|
||||
case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM:
|
||||
case AMDGPU_UCODE_ID_RLC_G:
|
||||
ucode_list[ucode_count++] = ucode;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
/* Reinit NBIF block */
|
||||
cmn_block =
|
||||
amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_COMMON);
|
||||
if (unlikely(!cmn_block)) {
|
||||
dev_err(adev->dev, "Failed to get BIF handle\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
r = cmn_block->version->funcs->resume(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Reinit GFXHUB */
|
||||
adev->gfxhub.funcs->init(adev);
|
||||
r = adev->gfxhub.funcs->gart_enable(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "GFXHUB gart reenable failed after reset\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Reload GFX firmware */
|
||||
r = psp_load_fw_list(&adev->psp, ucode_list, ucode_count);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "GFX ucode load failed after reset\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Resume RLC, FW needs RLC alive to complete reset process */
|
||||
adev->gfx.rlc.funcs->resume(adev);
|
||||
|
||||
/* Wait for FW reset event complete */
|
||||
r = smu_wait_for_event(adev, SMU_EVENT_RESET_COMPLETE, 0);
|
||||
if (r) {
|
||||
dev_err(adev->dev,
|
||||
"Failed to get response from firmware after reset\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!(adev->ip_blocks[i].version->type ==
|
||||
AMD_IP_BLOCK_TYPE_GFX ||
|
||||
adev->ip_blocks[i].version->type ==
|
||||
AMD_IP_BLOCK_TYPE_SDMA))
|
||||
continue;
|
||||
r = adev->ip_blocks[i].version->funcs->resume(adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev,
|
||||
"resume of IP block <%s> failed %d\n",
|
||||
adev->ip_blocks[i].version->funcs->name, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
adev->ip_blocks[i].status.hw = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->num_ip_blocks; i++) {
|
||||
if (!(adev->ip_blocks[i].version->type ==
|
||||
AMD_IP_BLOCK_TYPE_GFX ||
|
||||
adev->ip_blocks[i].version->type ==
|
||||
AMD_IP_BLOCK_TYPE_SDMA ||
|
||||
adev->ip_blocks[i].version->type ==
|
||||
AMD_IP_BLOCK_TYPE_COMMON))
|
||||
continue;
|
||||
|
||||
if (adev->ip_blocks[i].version->funcs->late_init) {
|
||||
r = adev->ip_blocks[i].version->funcs->late_init(
|
||||
(void *)adev);
|
||||
if (r) {
|
||||
dev_err(adev->dev,
|
||||
"late_init of IP block <%s> failed %d after reset\n",
|
||||
adev->ip_blocks[i].version->funcs->name,
|
||||
r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
adev->ip_blocks[i].status.late_initialized = true;
|
||||
}
|
||||
|
||||
amdgpu_device_set_cg_state(adev, AMD_CG_STATE_GATE);
|
||||
amdgpu_device_set_pg_state(adev, AMD_PG_STATE_GATE);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *reset_context)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_device *tmp_adev = NULL;
|
||||
|
||||
if (reset_context->hive == NULL) {
|
||||
/* Wrong context, return error */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(tmp_adev, &reset_context->hive->device_list,
|
||||
gmc.xgmi.head) {
|
||||
dev_info(tmp_adev->dev,
|
||||
"GPU reset succeeded, trying to resume\n");
|
||||
r = aldebaran_mode2_restore_ip(tmp_adev);
|
||||
if (r)
|
||||
goto end;
|
||||
|
||||
/*
|
||||
* Add this ASIC as tracked as reset was already
|
||||
* complete successfully.
|
||||
*/
|
||||
amdgpu_register_gpu_instance(tmp_adev);
|
||||
|
||||
/* Resume RAS */
|
||||
amdgpu_ras_resume(tmp_adev);
|
||||
|
||||
/* Update PSP FW topology after reset */
|
||||
if (reset_context->hive &&
|
||||
tmp_adev->gmc.xgmi.num_physical_nodes > 1)
|
||||
r = amdgpu_xgmi_update_topology(reset_context->hive,
|
||||
tmp_adev);
|
||||
|
||||
if (!r) {
|
||||
amdgpu_irq_gpu_reset_resume_helper(tmp_adev);
|
||||
|
||||
r = amdgpu_ib_ring_tests(tmp_adev);
|
||||
if (r) {
|
||||
dev_err(tmp_adev->dev,
|
||||
"ib ring test failed (%d).\n", r);
|
||||
r = -EAGAIN;
|
||||
tmp_adev->asic_reset_res = r;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct amdgpu_reset_handler aldebaran_mode2_handler = {
|
||||
.reset_method = AMD_RESET_METHOD_MODE2,
|
||||
.prepare_env = NULL,
|
||||
.prepare_hwcontext = aldebaran_mode2_prepare_hwcontext,
|
||||
.perform_reset = aldebaran_mode2_perform_reset,
|
||||
.restore_hwcontext = aldebaran_mode2_restore_hwcontext,
|
||||
.restore_env = NULL,
|
||||
.do_reset = aldebaran_mode2_reset,
|
||||
};
|
||||
|
||||
int aldebaran_reset_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_reset_control *reset_ctl;
|
||||
|
||||
reset_ctl = kzalloc(sizeof(*reset_ctl), GFP_KERNEL);
|
||||
if (!reset_ctl)
|
||||
return -ENOMEM;
|
||||
|
||||
reset_ctl->handle = adev;
|
||||
reset_ctl->async_reset = aldebaran_async_reset;
|
||||
reset_ctl->active_reset = AMD_RESET_METHOD_NONE;
|
||||
reset_ctl->get_reset_handler = aldebaran_get_reset_handler;
|
||||
|
||||
INIT_LIST_HEAD(&reset_ctl->reset_handlers);
|
||||
INIT_WORK(&reset_ctl->reset_work, reset_ctl->async_reset);
|
||||
/* Only mode2 is handled through reset control now */
|
||||
amdgpu_reset_add_handler(reset_ctl, &aldebaran_mode2_handler);
|
||||
|
||||
adev->reset_cntl = reset_ctl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aldebaran_reset_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
kfree(adev->reset_cntl);
|
||||
adev->reset_cntl = NULL;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ALDEBARAN_H__
|
||||
#define __ALDEBARAN_H__
|
||||
|
||||
#include "amdgpu.h"
|
||||
|
||||
int aldebaran_reset_init(struct amdgpu_device *adev);
|
||||
int aldebaran_reset_fini(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2020 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 "soc15.h"
|
||||
|
||||
#include "soc15_common.h"
|
||||
#include "aldebaran_ip_offset.h"
|
||||
|
||||
int aldebaran_reg_base_init(struct amdgpu_device *adev)
|
||||
{
|
||||
/* HW has more IP blocks, only initialized the block needed by our driver */
|
||||
uint32_t i;
|
||||
for (i = 0 ; i < MAX_INSTANCE ; ++i) {
|
||||
adev->reg_offset[GC_HWIP][i] = (uint32_t *)(&(GC_BASE.instance[i]));
|
||||
adev->reg_offset[HDP_HWIP][i] = (uint32_t *)(&(HDP_BASE.instance[i]));
|
||||
adev->reg_offset[MMHUB_HWIP][i] = (uint32_t *)(&(MMHUB_BASE.instance[i]));
|
||||
adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i]));
|
||||
adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i]));
|
||||
adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i]));
|
||||
adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i]));
|
||||
adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i]));
|
||||
adev->reg_offset[OSSSYS_HWIP][i] = (uint32_t *)(&(OSSSYS_BASE.instance[i]));
|
||||
adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(SDMA0_BASE.instance[i]));
|
||||
adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(SDMA1_BASE.instance[i]));
|
||||
adev->reg_offset[SDMA2_HWIP][i] = (uint32_t *)(&(SDMA2_BASE.instance[i]));
|
||||
adev->reg_offset[SDMA3_HWIP][i] = (uint32_t *)(&(SDMA3_BASE.instance[i]));
|
||||
adev->reg_offset[SDMA4_HWIP][i] = (uint32_t *)(&(SDMA4_BASE.instance[i]));
|
||||
adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i]));
|
||||
adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i]));
|
||||
adev->reg_offset[UMC_HWIP][i] = (uint32_t *)(&(UMC_BASE.instance[i]));
|
||||
adev->reg_offset[VCN_HWIP][i] = (uint32_t *)(&(VCN_BASE.instance[i]));
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -107,7 +107,6 @@
|
|||
#include "amdgpu_gfxhub.h"
|
||||
#include "amdgpu_df.h"
|
||||
#include "amdgpu_smuio.h"
|
||||
#include "amdgpu_hdp.h"
|
||||
|
||||
#define MAX_GPU_INSTANCE 16
|
||||
|
||||
|
@ -124,6 +123,16 @@ struct amdgpu_mgpu_info
|
|||
uint32_t num_gpu;
|
||||
uint32_t num_dgpu;
|
||||
uint32_t num_apu;
|
||||
|
||||
/* delayed reset_func for XGMI configuration if necessary */
|
||||
struct delayed_work delayed_reset_work;
|
||||
bool pending_reset;
|
||||
};
|
||||
|
||||
struct amdgpu_watchdog_timer
|
||||
{
|
||||
bool timeout_fatal_disable;
|
||||
uint32_t period; /* maxCycles = (1 << period), the number of cycles before a timeout */
|
||||
};
|
||||
|
||||
#define AMDGPU_MAX_TIMEOUT_PARAM_LENGTH 256
|
||||
|
@ -177,7 +186,9 @@ extern int amdgpu_compute_multipipe;
|
|||
extern int amdgpu_gpu_recovery;
|
||||
extern int amdgpu_emu_mode;
|
||||
extern uint amdgpu_smu_memory_pool_size;
|
||||
extern int amdgpu_smu_pptable_id;
|
||||
extern uint amdgpu_dc_feature_mask;
|
||||
extern uint amdgpu_freesync_vid_mode;
|
||||
extern uint amdgpu_dc_debug_mask;
|
||||
extern uint amdgpu_dm_abm_level;
|
||||
extern int amdgpu_backlight;
|
||||
|
@ -185,6 +196,7 @@ extern struct amdgpu_mgpu_info mgpu_info;
|
|||
extern int amdgpu_ras_enable;
|
||||
extern uint amdgpu_ras_mask;
|
||||
extern int amdgpu_bad_page_threshold;
|
||||
extern struct amdgpu_watchdog_timer amdgpu_watchdog_timer;
|
||||
extern int amdgpu_async_gfx_ring;
|
||||
extern int amdgpu_mcbp;
|
||||
extern int amdgpu_discovery;
|
||||
|
@ -258,6 +270,8 @@ struct amdgpu_bo_va_mapping;
|
|||
struct amdgpu_atif;
|
||||
struct kfd_vm_fault_info;
|
||||
struct amdgpu_hive_info;
|
||||
struct amdgpu_reset_context;
|
||||
struct amdgpu_reset_control;
|
||||
|
||||
enum amdgpu_cp_irq {
|
||||
AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0,
|
||||
|
@ -576,6 +590,7 @@ struct amdgpu_allowed_register_entry {
|
|||
};
|
||||
|
||||
enum amd_reset_method {
|
||||
AMD_RESET_METHOD_NONE = -1,
|
||||
AMD_RESET_METHOD_LEGACY = 0,
|
||||
AMD_RESET_METHOD_MODE0,
|
||||
AMD_RESET_METHOD_MODE1,
|
||||
|
@ -584,6 +599,19 @@ enum amd_reset_method {
|
|||
AMD_RESET_METHOD_PCI,
|
||||
};
|
||||
|
||||
struct amdgpu_video_codec_info {
|
||||
u32 codec_type;
|
||||
u32 max_width;
|
||||
u32 max_height;
|
||||
u32 max_pixels_per_frame;
|
||||
u32 max_level;
|
||||
};
|
||||
|
||||
struct amdgpu_video_codecs {
|
||||
const u32 codec_count;
|
||||
const struct amdgpu_video_codec_info *codec_array;
|
||||
};
|
||||
|
||||
/*
|
||||
* ASIC specific functions.
|
||||
*/
|
||||
|
@ -628,6 +656,9 @@ struct amdgpu_asic_funcs {
|
|||
void (*pre_asic_init)(struct amdgpu_device *adev);
|
||||
/* enter/exit umd stable pstate */
|
||||
int (*update_umd_stable_pstate)(struct amdgpu_device *adev, bool enter);
|
||||
/* query video codecs */
|
||||
int (*query_video_codecs)(struct amdgpu_device *adev, bool encode,
|
||||
const struct amdgpu_video_codecs **codecs);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -792,12 +823,7 @@ struct amdgpu_device {
|
|||
bool accel_working;
|
||||
struct notifier_block acpi_nb;
|
||||
struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
|
||||
struct amdgpu_debugfs debugfs[AMDGPU_DEBUGFS_MAX_COMPONENTS];
|
||||
unsigned debugfs_count;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
struct dentry *debugfs_preempt;
|
||||
struct dentry *debugfs_regs[AMDGPU_DEBUGFS_MAX_COMPONENTS];
|
||||
#endif
|
||||
struct debugfs_blob_wrapper debugfs_vbios_blob;
|
||||
struct amdgpu_atif *atif;
|
||||
struct amdgpu_atcs atcs;
|
||||
struct mutex srbm_mutex;
|
||||
|
@ -853,8 +879,6 @@ struct amdgpu_device {
|
|||
spinlock_t audio_endpt_idx_lock;
|
||||
amdgpu_block_rreg_t audio_endpt_rreg;
|
||||
amdgpu_block_wreg_t audio_endpt_wreg;
|
||||
void __iomem *rio_mem;
|
||||
resource_size_t rio_mem_size;
|
||||
struct amdgpu_doorbell doorbell;
|
||||
|
||||
/* clock/pll info */
|
||||
|
@ -897,6 +921,8 @@ struct amdgpu_device {
|
|||
struct amdgpu_irq_src vupdate_irq;
|
||||
struct amdgpu_irq_src pageflip_irq;
|
||||
struct amdgpu_irq_src hpd_irq;
|
||||
struct amdgpu_irq_src dmub_trace_irq;
|
||||
struct amdgpu_irq_src dmub_outbox_irq;
|
||||
|
||||
/* rings */
|
||||
u64 fence_context;
|
||||
|
@ -1020,6 +1046,7 @@ struct amdgpu_device {
|
|||
|
||||
int asic_reset_res;
|
||||
struct work_struct xgmi_reset_work;
|
||||
struct list_head reset_list;
|
||||
|
||||
long gfx_timeout;
|
||||
long sdma_timeout;
|
||||
|
@ -1050,6 +1077,8 @@ struct amdgpu_device {
|
|||
|
||||
bool in_pci_err_recovery;
|
||||
struct pci_saved_state *pci_state;
|
||||
|
||||
struct amdgpu_reset_control *reset_cntl;
|
||||
};
|
||||
|
||||
static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev)
|
||||
|
@ -1062,7 +1091,7 @@ static inline struct drm_device *adev_to_drm(struct amdgpu_device *adev)
|
|||
return &adev->ddev;
|
||||
}
|
||||
|
||||
static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev)
|
||||
static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_device *bdev)
|
||||
{
|
||||
return container_of(bdev, struct amdgpu_device, mman.bdev);
|
||||
}
|
||||
|
@ -1084,9 +1113,6 @@ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
|
|||
void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value);
|
||||
uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset);
|
||||
|
||||
u32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg);
|
||||
void amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v);
|
||||
|
||||
u32 amdgpu_device_indirect_rreg(struct amdgpu_device *adev,
|
||||
u32 pcie_index, u32 pcie_data,
|
||||
u32 reg_addr);
|
||||
|
@ -1103,6 +1129,12 @@ void amdgpu_device_indirect_wreg64(struct amdgpu_device *adev,
|
|||
bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type);
|
||||
bool amdgpu_device_has_dc_support(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
|
||||
struct amdgpu_reset_context *reset_context);
|
||||
|
||||
int amdgpu_do_asic_reset(struct list_head *device_list_handle,
|
||||
struct amdgpu_reset_context *reset_context);
|
||||
|
||||
int emu_soc_asic_init(struct amdgpu_device *adev);
|
||||
|
||||
/*
|
||||
|
@ -1168,8 +1200,6 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
|
|||
} while (0)
|
||||
|
||||
#define DREG32_SYS(sqf, adev, reg) seq_printf((sqf), #reg " : 0x%08X\n", amdgpu_device_rreg((adev), (reg), false))
|
||||
#define RREG32_IO(reg) amdgpu_io_rreg(adev, (reg))
|
||||
#define WREG32_IO(reg, v) amdgpu_io_wreg(adev, (reg), (v))
|
||||
|
||||
#define REG_FIELD_SHIFT(reg, field) reg##__##field##__SHIFT
|
||||
#define REG_FIELD_MASK(reg, field) reg##__##field##_MASK
|
||||
|
@ -1223,6 +1253,7 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
|
|||
#define amdgpu_asic_pre_asic_init(adev) (adev)->asic_funcs->pre_asic_init((adev))
|
||||
#define amdgpu_asic_update_umd_stable_pstate(adev, enter) \
|
||||
((adev)->asic_funcs->update_umd_stable_pstate ? (adev)->asic_funcs->update_umd_stable_pstate((adev), (enter)) : 0)
|
||||
#define amdgpu_asic_query_video_codecs(adev, e, c) (adev)->asic_funcs->query_video_codecs((adev), (e), (c))
|
||||
|
||||
#define amdgpu_inc_vram_lost(adev) atomic_inc(&((adev)->vram_lost_counter));
|
||||
|
||||
|
@ -1242,7 +1273,9 @@ void amdgpu_device_program_register_sequence(struct amdgpu_device *adev,
|
|||
const u32 *registers,
|
||||
const u32 array_size);
|
||||
|
||||
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_baco(struct drm_device *dev);
|
||||
bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev,
|
||||
|
@ -1356,6 +1389,13 @@ void amdgpu_pci_resume(struct pci_dev *pdev);
|
|||
bool amdgpu_device_cache_pci_state(struct pci_dev *pdev);
|
||||
bool amdgpu_device_load_pci_state(struct pci_dev *pdev);
|
||||
|
||||
bool amdgpu_device_skip_hw_access(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_device_set_cg_state(struct amdgpu_device *adev,
|
||||
enum amd_clockgating_state state);
|
||||
int amdgpu_device_set_pg_state(struct amdgpu_device *adev,
|
||||
enum amd_powergating_state state);
|
||||
|
||||
#include "amdgpu_object.h"
|
||||
|
||||
static inline bool amdgpu_is_tmz(struct amdgpu_device *adev)
|
||||
|
|
|
@ -44,7 +44,7 @@ int amdgpu_amdkfd_init(void)
|
|||
int ret;
|
||||
|
||||
si_meminfo(&si);
|
||||
amdgpu_amdkfd_total_mem_size = si.totalram - si.totalhigh;
|
||||
amdgpu_amdkfd_total_mem_size = si.freeram - si.freehigh;
|
||||
amdgpu_amdkfd_total_mem_size *= si.mem_unit;
|
||||
|
||||
ret = kgd2kfd_init();
|
||||
|
@ -165,7 +165,8 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
|
|||
adev->doorbell_index.last_non_cp;
|
||||
}
|
||||
|
||||
kgd2kfd_device_init(adev->kfd.dev, adev_to_drm(adev), &gpu_resources);
|
||||
adev->kfd.init_complete = kgd2kfd_device_init(adev->kfd.dev,
|
||||
adev_to_drm(adev), &gpu_resources);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,6 +246,7 @@ int amdgpu_amdkfd_alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
|
|||
bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
if (cp_mqd_gfx9)
|
||||
bp.flags |= AMDGPU_GEM_CREATE_CP_MQD_GFX9;
|
||||
|
@ -316,6 +318,7 @@ int amdgpu_amdkfd_alloc_gws(struct kgd_dev *kgd, size_t size,
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
struct amdgpu_bo *bo = NULL;
|
||||
struct amdgpu_bo_user *ubo;
|
||||
struct amdgpu_bo_param bp;
|
||||
int r;
|
||||
|
||||
|
@ -326,14 +329,16 @@ int amdgpu_amdkfd_alloc_gws(struct kgd_dev *kgd, size_t size,
|
|||
bp.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
|
||||
bp.type = ttm_bo_type_device;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
r = amdgpu_bo_create(adev, &bp, &bo);
|
||||
r = amdgpu_bo_create_user(adev, &bp, &ubo);
|
||||
if (r) {
|
||||
dev_err(adev->dev,
|
||||
"failed to allocate gws BO for amdkfd (%d)\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
bo = &ubo->bo;
|
||||
*mem_obj = bo;
|
||||
return 0;
|
||||
}
|
||||
|
@ -494,8 +499,6 @@ int amdgpu_amdkfd_get_dmabuf_info(struct kgd_dev *kgd, int dma_buf_fd,
|
|||
*dma_buf_kgd = (struct kgd_dev *)adev;
|
||||
if (bo_size)
|
||||
*bo_size = amdgpu_bo_size(bo);
|
||||
if (metadata_size)
|
||||
*metadata_size = bo->metadata_size;
|
||||
if (metadata_buffer)
|
||||
r = amdgpu_bo_get_metadata(bo, metadata_buffer, buffer_size,
|
||||
metadata_size, &metadata_flags);
|
||||
|
@ -638,13 +641,6 @@ void amdgpu_amdkfd_set_compute_idle(struct kgd_dev *kgd, bool idle)
|
|||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)kgd;
|
||||
|
||||
/* Temp workaround to fix the soft hang observed in certain compute
|
||||
* applications if GFXOFF is enabled.
|
||||
*/
|
||||
if (adev->asic_type == CHIP_SIENNA_CICHLID) {
|
||||
pr_debug("GFXOFF is %s\n", idle ? "enabled" : "disabled");
|
||||
amdgpu_gfx_off_ctrl(adev, idle);
|
||||
}
|
||||
amdgpu_dpm_switch_power_profile(adev,
|
||||
PP_SMC_POWER_PROFILE_COMPUTE,
|
||||
!idle);
|
||||
|
|
|
@ -80,6 +80,7 @@ struct amdgpu_amdkfd_fence {
|
|||
struct amdgpu_kfd_dev {
|
||||
struct kfd_dev *dev;
|
||||
uint64_t vram_used;
|
||||
bool init_complete;
|
||||
};
|
||||
|
||||
enum kgd_engine_type {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2020 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_amdkfd.h"
|
||||
#include "amdgpu_amdkfd_arcturus.h"
|
||||
#include "amdgpu_amdkfd_gfx_v9.h"
|
||||
|
||||
const struct kfd2kgd_calls aldebaran_kfd2kgd = {
|
||||
.program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings,
|
||||
.set_pasid_vmid_mapping = kgd_gfx_v9_set_pasid_vmid_mapping,
|
||||
.init_interrupts = kgd_gfx_v9_init_interrupts,
|
||||
.hqd_load = kgd_gfx_v9_hqd_load,
|
||||
.hiq_mqd_load = kgd_gfx_v9_hiq_mqd_load,
|
||||
.hqd_sdma_load = kgd_arcturus_hqd_sdma_load,
|
||||
.hqd_dump = kgd_gfx_v9_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_arcturus_hqd_sdma_dump,
|
||||
.hqd_is_occupied = kgd_gfx_v9_hqd_is_occupied,
|
||||
.hqd_sdma_is_occupied = kgd_arcturus_hqd_sdma_is_occupied,
|
||||
.hqd_destroy = kgd_gfx_v9_hqd_destroy,
|
||||
.hqd_sdma_destroy = kgd_arcturus_hqd_sdma_destroy,
|
||||
.address_watch_disable = kgd_gfx_v9_address_watch_disable,
|
||||
.address_watch_execute = kgd_gfx_v9_address_watch_execute,
|
||||
.wave_control_execute = kgd_gfx_v9_wave_control_execute,
|
||||
.address_watch_get_offset = kgd_gfx_v9_address_watch_get_offset,
|
||||
.get_atc_vmid_pasid_mapping_info =
|
||||
kgd_gfx_v9_get_atc_vmid_pasid_mapping_info,
|
||||
.set_vm_context_page_table_base = kgd_gfx_v9_set_vm_context_page_table_base,
|
||||
};
|
|
@ -122,7 +122,7 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
|
|||
return sdma_rlc_reg_offset;
|
||||
}
|
||||
|
||||
static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd,
|
||||
int kgd_arcturus_hqd_sdma_load(struct kgd_dev *kgd, void *mqd,
|
||||
uint32_t __user *wptr, struct mm_struct *mm)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
|
@ -192,7 +192,7 @@ static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kgd_hqd_sdma_dump(struct kgd_dev *kgd,
|
||||
int kgd_arcturus_hqd_sdma_dump(struct kgd_dev *kgd,
|
||||
uint32_t engine_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs)
|
||||
{
|
||||
|
@ -224,7 +224,7 @@ static int kgd_hqd_sdma_dump(struct kgd_dev *kgd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
|
||||
bool kgd_arcturus_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
struct v9_sdma_mqd *m;
|
||||
|
@ -243,7 +243,7 @@ static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
int kgd_arcturus_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
unsigned int utimeout)
|
||||
{
|
||||
struct amdgpu_device *adev = get_amdgpu_device(kgd);
|
||||
|
@ -289,13 +289,13 @@ const struct kfd2kgd_calls arcturus_kfd2kgd = {
|
|||
.init_interrupts = kgd_gfx_v9_init_interrupts,
|
||||
.hqd_load = kgd_gfx_v9_hqd_load,
|
||||
.hiq_mqd_load = kgd_gfx_v9_hiq_mqd_load,
|
||||
.hqd_sdma_load = kgd_hqd_sdma_load,
|
||||
.hqd_sdma_load = kgd_arcturus_hqd_sdma_load,
|
||||
.hqd_dump = kgd_gfx_v9_hqd_dump,
|
||||
.hqd_sdma_dump = kgd_hqd_sdma_dump,
|
||||
.hqd_sdma_dump = kgd_arcturus_hqd_sdma_dump,
|
||||
.hqd_is_occupied = kgd_gfx_v9_hqd_is_occupied,
|
||||
.hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied,
|
||||
.hqd_sdma_is_occupied = kgd_arcturus_hqd_sdma_is_occupied,
|
||||
.hqd_destroy = kgd_gfx_v9_hqd_destroy,
|
||||
.hqd_sdma_destroy = kgd_hqd_sdma_destroy,
|
||||
.hqd_sdma_destroy = kgd_arcturus_hqd_sdma_destroy,
|
||||
.address_watch_disable = kgd_gfx_v9_address_watch_disable,
|
||||
.address_watch_execute = kgd_gfx_v9_address_watch_execute,
|
||||
.wave_control_execute = kgd_gfx_v9_wave_control_execute,
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
int kgd_arcturus_hqd_sdma_load(struct kgd_dev *kgd, void *mqd,
|
||||
uint32_t __user *wptr, struct mm_struct *mm);
|
||||
int kgd_arcturus_hqd_sdma_dump(struct kgd_dev *kgd,
|
||||
uint32_t engine_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs);
|
||||
bool kgd_arcturus_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd);
|
||||
int kgd_arcturus_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
|
||||
unsigned int utimeout);
|
|
@ -40,13 +40,13 @@ static atomic_t fence_seq = ATOMIC_INIT(0);
|
|||
* All the BOs in a process share an eviction fence. When process X wants
|
||||
* to map VRAM memory but TTM can't find enough space, TTM will attempt to
|
||||
* evict BOs from its LRU list. TTM checks if the BO is valuable to evict
|
||||
* by calling ttm_bo_driver->eviction_valuable().
|
||||
* by calling ttm_device_funcs->eviction_valuable().
|
||||
*
|
||||
* ttm_bo_driver->eviction_valuable() - will return false if the BO belongs
|
||||
* ttm_device_funcs->eviction_valuable() - will return false if the BO belongs
|
||||
* to process X. Otherwise, it will return true to indicate BO can be
|
||||
* evicted by TTM.
|
||||
*
|
||||
* If ttm_bo_driver->eviction_valuable returns true, then TTM will continue
|
||||
* If ttm_device_funcs->eviction_valuable returns true, then TTM will continue
|
||||
* the evcition process for that BO by calling ttm_bo_evict --> amdgpu_bo_move
|
||||
* --> amdgpu_copy_buffer(). This sets up job in GPU scheduler.
|
||||
*
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "amdgpu_amdkfd.h"
|
||||
#include "amdgpu_dma_buf.h"
|
||||
#include <uapi/linux/kfd_ioctl.h>
|
||||
#include "amdgpu_xgmi.h"
|
||||
|
||||
/* BO flag to indicate a KFD userptr BO */
|
||||
#define AMDGPU_AMDKFD_USERPTR_BO (1ULL << 63)
|
||||
|
@ -96,7 +97,7 @@ void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
|
|||
uint64_t mem;
|
||||
|
||||
si_meminfo(&si);
|
||||
mem = si.totalram - si.totalhigh;
|
||||
mem = si.freeram - si.freehigh;
|
||||
mem *= si.mem_unit;
|
||||
|
||||
spin_lock_init(&kfd_mem_limit.mem_limit_lock);
|
||||
|
@ -119,6 +120,16 @@ void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
|
|||
*/
|
||||
#define ESTIMATE_PT_SIZE(mem_size) ((mem_size) >> 14)
|
||||
|
||||
static size_t amdgpu_amdkfd_acc_size(uint64_t size)
|
||||
{
|
||||
size >>= PAGE_SHIFT;
|
||||
size *= sizeof(dma_addr_t) + sizeof(void *);
|
||||
|
||||
return __roundup_pow_of_two(sizeof(struct amdgpu_bo)) +
|
||||
__roundup_pow_of_two(sizeof(struct ttm_tt)) +
|
||||
PAGE_ALIGN(size);
|
||||
}
|
||||
|
||||
static int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
|
||||
uint64_t size, u32 domain, bool sg)
|
||||
{
|
||||
|
@ -127,8 +138,7 @@ static int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
|
|||
size_t acc_size, system_mem_needed, ttm_mem_needed, vram_needed;
|
||||
int ret = 0;
|
||||
|
||||
acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size,
|
||||
sizeof(struct amdgpu_bo));
|
||||
acc_size = amdgpu_amdkfd_acc_size(size);
|
||||
|
||||
vram_needed = 0;
|
||||
if (domain == AMDGPU_GEM_DOMAIN_GTT) {
|
||||
|
@ -175,8 +185,7 @@ static void unreserve_mem_limit(struct amdgpu_device *adev,
|
|||
{
|
||||
size_t acc_size;
|
||||
|
||||
acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size,
|
||||
sizeof(struct amdgpu_bo));
|
||||
acc_size = amdgpu_amdkfd_acc_size(size);
|
||||
|
||||
spin_lock(&kfd_mem_limit.mem_limit_lock);
|
||||
if (domain == AMDGPU_GEM_DOMAIN_GTT) {
|
||||
|
@ -404,7 +413,10 @@ static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem)
|
|||
{
|
||||
struct amdgpu_device *bo_adev = amdgpu_ttm_adev(mem->bo->tbo.bdev);
|
||||
bool coherent = mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_COHERENT;
|
||||
bool uncached = mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_UNCACHED;
|
||||
uint32_t mapping_flags;
|
||||
uint64_t pte_flags;
|
||||
bool snoop = false;
|
||||
|
||||
mapping_flags = AMDGPU_VM_PAGE_READABLE;
|
||||
if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE)
|
||||
|
@ -425,12 +437,41 @@ static uint64_t get_pte_flags(struct amdgpu_device *adev, struct kgd_mem *mem)
|
|||
AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_NC;
|
||||
}
|
||||
break;
|
||||
case CHIP_ALDEBARAN:
|
||||
if (coherent && uncached) {
|
||||
if (adev->gmc.xgmi.connected_to_cpu ||
|
||||
!(mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM))
|
||||
snoop = true;
|
||||
mapping_flags |= AMDGPU_VM_MTYPE_UC;
|
||||
} else if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) {
|
||||
if (bo_adev == adev) {
|
||||
mapping_flags |= AMDGPU_VM_MTYPE_RW;
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
snoop = true;
|
||||
} else {
|
||||
mapping_flags |= AMDGPU_VM_MTYPE_NC;
|
||||
if (amdgpu_xgmi_same_hive(adev, bo_adev))
|
||||
snoop = true;
|
||||
}
|
||||
} else {
|
||||
snoop = true;
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
/* system memory uses NC on A+A */
|
||||
mapping_flags |= AMDGPU_VM_MTYPE_NC;
|
||||
else
|
||||
mapping_flags |= coherent ?
|
||||
AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_NC;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mapping_flags |= coherent ?
|
||||
AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_NC;
|
||||
}
|
||||
|
||||
return amdgpu_gem_va_map_flags(adev, mapping_flags);
|
||||
pte_flags = amdgpu_gem_va_map_flags(adev, mapping_flags);
|
||||
pte_flags |= snoop ? AMDGPU_PTE_SNOOPED : 0;
|
||||
|
||||
return pte_flags;
|
||||
}
|
||||
|
||||
/* add_bo_to_vm - Add a BO to a VM
|
||||
|
|
|
@ -1232,157 +1232,6 @@ int amdgpu_atombios_get_leakage_vddc_based_on_leakage_idx(struct amdgpu_device *
|
|||
return amdgpu_atombios_get_max_vddc(adev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);
|
||||
}
|
||||
|
||||
int amdgpu_atombios_get_leakage_id_from_vbios(struct amdgpu_device *adev,
|
||||
u16 *leakage_id)
|
||||
{
|
||||
union set_voltage args;
|
||||
int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
|
||||
u8 frev, crev;
|
||||
|
||||
if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
|
||||
return -EINVAL;
|
||||
|
||||
switch (crev) {
|
||||
case 3:
|
||||
case 4:
|
||||
args.v3.ucVoltageType = 0;
|
||||
args.v3.ucVoltageMode = ATOM_GET_LEAKAGE_ID;
|
||||
args.v3.usVoltageLevel = 0;
|
||||
|
||||
amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
|
||||
*leakage_id = le16_to_cpu(args.v3.usVoltageLevel);
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_atombios_get_leakage_vddc_based_on_leakage_params(struct amdgpu_device *adev,
|
||||
u16 *vddc, u16 *vddci,
|
||||
u16 virtual_voltage_id,
|
||||
u16 vbios_voltage_id)
|
||||
{
|
||||
int index = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo);
|
||||
u8 frev, crev;
|
||||
u16 data_offset, size;
|
||||
int i, j;
|
||||
ATOM_ASIC_PROFILING_INFO_V2_1 *profile;
|
||||
u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf;
|
||||
|
||||
*vddc = 0;
|
||||
*vddci = 0;
|
||||
|
||||
if (!amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, &size,
|
||||
&frev, &crev, &data_offset))
|
||||
return -EINVAL;
|
||||
|
||||
profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *)
|
||||
(adev->mode_info.atom_context->bios + data_offset);
|
||||
|
||||
switch (frev) {
|
||||
case 1:
|
||||
return -EINVAL;
|
||||
case 2:
|
||||
switch (crev) {
|
||||
case 1:
|
||||
if (size < sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))
|
||||
return -EINVAL;
|
||||
leakage_bin = (u16 *)
|
||||
(adev->mode_info.atom_context->bios + data_offset +
|
||||
le16_to_cpu(profile->usLeakageBinArrayOffset));
|
||||
vddc_id_buf = (u16 *)
|
||||
(adev->mode_info.atom_context->bios + data_offset +
|
||||
le16_to_cpu(profile->usElbVDDC_IdArrayOffset));
|
||||
vddc_buf = (u16 *)
|
||||
(adev->mode_info.atom_context->bios + data_offset +
|
||||
le16_to_cpu(profile->usElbVDDC_LevelArrayOffset));
|
||||
vddci_id_buf = (u16 *)
|
||||
(adev->mode_info.atom_context->bios + data_offset +
|
||||
le16_to_cpu(profile->usElbVDDCI_IdArrayOffset));
|
||||
vddci_buf = (u16 *)
|
||||
(adev->mode_info.atom_context->bios + data_offset +
|
||||
le16_to_cpu(profile->usElbVDDCI_LevelArrayOffset));
|
||||
|
||||
if (profile->ucElbVDDC_Num > 0) {
|
||||
for (i = 0; i < profile->ucElbVDDC_Num; i++) {
|
||||
if (vddc_id_buf[i] == virtual_voltage_id) {
|
||||
for (j = 0; j < profile->ucLeakageBinNum; j++) {
|
||||
if (vbios_voltage_id <= leakage_bin[j]) {
|
||||
*vddc = vddc_buf[j * profile->ucElbVDDC_Num + i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (profile->ucElbVDDCI_Num > 0) {
|
||||
for (i = 0; i < profile->ucElbVDDCI_Num; i++) {
|
||||
if (vddci_id_buf[i] == virtual_voltage_id) {
|
||||
for (j = 0; j < profile->ucLeakageBinNum; j++) {
|
||||
if (vbios_voltage_id <= leakage_bin[j]) {
|
||||
*vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
union get_voltage_info {
|
||||
struct _GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 in;
|
||||
struct _GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 evv_out;
|
||||
};
|
||||
|
||||
int amdgpu_atombios_get_voltage_evv(struct amdgpu_device *adev,
|
||||
u16 virtual_voltage_id,
|
||||
u16 *voltage)
|
||||
{
|
||||
int index = GetIndexIntoMasterTable(COMMAND, GetVoltageInfo);
|
||||
u32 entry_id;
|
||||
u32 count = adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count;
|
||||
union get_voltage_info args;
|
||||
|
||||
for (entry_id = 0; entry_id < count; entry_id++) {
|
||||
if (adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].v ==
|
||||
virtual_voltage_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry_id >= count)
|
||||
return -EINVAL;
|
||||
|
||||
args.in.ucVoltageType = VOLTAGE_TYPE_VDDC;
|
||||
args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
|
||||
args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id);
|
||||
args.in.ulSCLKFreq =
|
||||
cpu_to_le32(adev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk);
|
||||
|
||||
amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
|
||||
|
||||
*voltage = le16_to_cpu(args.evv_out.usVoltageLevel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
union voltage_object_info {
|
||||
struct _ATOM_VOLTAGE_OBJECT_INFO v1;
|
||||
struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
|
||||
|
@ -1905,40 +1754,6 @@ static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)
|
|||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* cail_ioreg_write - write IO register
|
||||
*
|
||||
* @info: atom card_info pointer
|
||||
* @reg: IO register offset
|
||||
* @val: value to write to the pll register
|
||||
*
|
||||
* Provides a IO register accessor for the atom interpreter (r4xx+).
|
||||
*/
|
||||
static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(info->dev);
|
||||
|
||||
WREG32_IO(reg, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* cail_ioreg_read - read IO register
|
||||
*
|
||||
* @info: atom card_info pointer
|
||||
* @reg: IO register offset
|
||||
*
|
||||
* Provides an IO register accessor for the atom interpreter (r4xx+).
|
||||
* Returns the value of the IO register.
|
||||
*/
|
||||
static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(info->dev);
|
||||
uint32_t r;
|
||||
|
||||
r = RREG32_IO(reg);
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -1947,7 +1762,7 @@ static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev,
|
|||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
struct atom_context *ctx = adev->mode_info.atom_context;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", ctx->vbios_version);
|
||||
return sysfs_emit(buf, "%s\n", ctx->vbios_version);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version,
|
||||
|
@ -1998,15 +1813,6 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
|
|||
atom_card_info->dev = adev_to_drm(adev);
|
||||
atom_card_info->reg_read = cail_reg_read;
|
||||
atom_card_info->reg_write = cail_reg_write;
|
||||
/* needed for iio ops */
|
||||
if (adev->rio_mem) {
|
||||
atom_card_info->ioreg_read = cail_ioreg_read;
|
||||
atom_card_info->ioreg_write = cail_ioreg_write;
|
||||
} else {
|
||||
DRM_DEBUG("PCI I/O BAR is not found. Using MMIO to access ATOM BIOS\n");
|
||||
atom_card_info->ioreg_read = cail_reg_read;
|
||||
atom_card_info->ioreg_write = cail_reg_write;
|
||||
}
|
||||
atom_card_info->mc_read = cail_mc_read;
|
||||
atom_card_info->mc_write = cail_mc_write;
|
||||
atom_card_info->pll_read = cail_pll_read;
|
||||
|
|
|
@ -168,18 +168,6 @@ int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev,
|
|||
void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,
|
||||
u32 eng_clock, u32 mem_clock);
|
||||
|
||||
int amdgpu_atombios_get_leakage_id_from_vbios(struct amdgpu_device *adev,
|
||||
u16 *leakage_id);
|
||||
|
||||
int amdgpu_atombios_get_leakage_vddc_based_on_leakage_params(struct amdgpu_device *adev,
|
||||
u16 *vddc, u16 *vddci,
|
||||
u16 virtual_voltage_id,
|
||||
u16 vbios_voltage_id);
|
||||
|
||||
int amdgpu_atombios_get_voltage_evv(struct amdgpu_device *adev,
|
||||
u16 virtual_voltage_id,
|
||||
u16 *voltage);
|
||||
|
||||
bool
|
||||
amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,
|
||||
u8 voltage_type, u8 voltage_mode);
|
||||
|
|
|
@ -117,12 +117,15 @@ union igp_info {
|
|||
|
||||
union umc_info {
|
||||
struct atom_umc_info_v3_1 v31;
|
||||
struct atom_umc_info_v3_2 v32;
|
||||
struct atom_umc_info_v3_3 v33;
|
||||
};
|
||||
|
||||
union vram_info {
|
||||
struct atom_vram_info_header_v2_3 v23;
|
||||
struct atom_vram_info_header_v2_4 v24;
|
||||
struct atom_vram_info_header_v2_5 v25;
|
||||
struct atom_vram_info_header_v2_6 v26;
|
||||
};
|
||||
|
||||
union vram_module {
|
||||
|
@ -164,6 +167,7 @@ static int convert_atom_mem_type_to_vram_type(struct amdgpu_device *adev,
|
|||
vram_type = AMDGPU_VRAM_TYPE_GDDR5;
|
||||
break;
|
||||
case ATOM_DGPU_VRAM_TYPE_HBM2:
|
||||
case ATOM_DGPU_VRAM_TYPE_HBM2E:
|
||||
vram_type = AMDGPU_VRAM_TYPE_HBM;
|
||||
break;
|
||||
case ATOM_DGPU_VRAM_TYPE_GDDR6:
|
||||
|
@ -315,6 +319,26 @@ amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
|
|||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
case 6:
|
||||
if (module_id > vram_info->v26.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v26.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v9.vram_module_size);
|
||||
i++;
|
||||
}
|
||||
mem_type = vram_module->v9.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v9.channel_num;
|
||||
mem_channel_width = vram_module->v9.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -337,19 +361,39 @@ bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev)
|
|||
union umc_info *umc_info;
|
||||
u8 frev, crev;
|
||||
bool ecc_default_enabled = false;
|
||||
u8 umc_config;
|
||||
u32 umc_config1;
|
||||
|
||||
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
umc_info);
|
||||
|
||||
if (amdgpu_atom_parse_data_header(mode_info->atom_context,
|
||||
index, &size, &frev, &crev, &data_offset)) {
|
||||
/* support umc_info 3.1+ */
|
||||
if ((frev == 3 && crev >= 1) || (frev > 3)) {
|
||||
if (frev == 3) {
|
||||
umc_info = (union umc_info *)
|
||||
(mode_info->atom_context->bios + data_offset);
|
||||
ecc_default_enabled =
|
||||
(le32_to_cpu(umc_info->v31.umc_config) &
|
||||
UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false;
|
||||
switch (crev) {
|
||||
case 1:
|
||||
umc_config = le32_to_cpu(umc_info->v31.umc_config);
|
||||
ecc_default_enabled =
|
||||
(umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false;
|
||||
break;
|
||||
case 2:
|
||||
umc_config = le32_to_cpu(umc_info->v32.umc_config);
|
||||
ecc_default_enabled =
|
||||
(umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false;
|
||||
break;
|
||||
case 3:
|
||||
umc_config = le32_to_cpu(umc_info->v33.umc_config);
|
||||
umc_config1 = le32_to_cpu(umc_info->v33.umc_config1);
|
||||
ecc_default_enabled =
|
||||
((umc_config & UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ||
|
||||
(umc_config1 & UMC_CONFIG1__ENABLE_ECC_CAPABLE)) ? true : false;
|
||||
break;
|
||||
default:
|
||||
/* unsupported crev */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,7 +523,8 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
|
|||
}
|
||||
|
||||
union gfx_info {
|
||||
struct atom_gfx_info_v2_4 v24;
|
||||
struct atom_gfx_info_v2_4 v24;
|
||||
struct atom_gfx_info_v2_7 v27;
|
||||
};
|
||||
|
||||
int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev)
|
||||
|
@ -514,6 +559,22 @@ int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev)
|
|||
adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v24.gc_max_scratch_slots_per_cu;
|
||||
adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v24.gc_lds_size);
|
||||
return 0;
|
||||
case 7:
|
||||
adev->gfx.config.max_shader_engines = gfx_info->v27.max_shader_engines;
|
||||
adev->gfx.config.max_cu_per_sh = gfx_info->v27.max_cu_per_sh;
|
||||
adev->gfx.config.max_sh_per_se = gfx_info->v27.max_sh_per_se;
|
||||
adev->gfx.config.max_backends_per_se = gfx_info->v27.max_backends_per_se;
|
||||
adev->gfx.config.max_texture_channel_caches = gfx_info->v27.max_texture_channel_caches;
|
||||
adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v27.gc_num_gprs);
|
||||
adev->gfx.config.max_gs_threads = gfx_info->v27.gc_num_max_gs_thds;
|
||||
adev->gfx.config.gs_vgt_table_depth = gfx_info->v27.gc_gs_table_depth;
|
||||
adev->gfx.config.gs_prim_buffer_depth = le16_to_cpu(gfx_info->v27.gc_gsprim_buff_depth);
|
||||
adev->gfx.config.double_offchip_lds_buf = gfx_info->v27.gc_double_offchip_lds_buffer;
|
||||
adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v27.gc_wave_size);
|
||||
adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v27.gc_max_waves_per_simd);
|
||||
adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v27.gc_max_scratch_slots_per_cu;
|
||||
adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v27.gc_lds_size);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size,
|
|||
bp.flags = 0;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
n = AMDGPU_BENCHMARK_ITERATIONS;
|
||||
r = amdgpu_bo_create(adev, &bp, &sobj);
|
||||
if (r) {
|
||||
|
|
|
@ -97,6 +97,10 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
|
|||
if (amdgpu_device_need_post(adev))
|
||||
return false;
|
||||
|
||||
/* FB BAR not enabled */
|
||||
if (pci_resource_len(adev->pdev, 0) == 0)
|
||||
return false;
|
||||
|
||||
adev->bios = NULL;
|
||||
vram_base = pci_resource_start(adev->pdev, 0);
|
||||
bios = ioremap_wc(vram_base, size);
|
||||
|
@ -316,7 +320,7 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
|||
|
||||
adev->bios = kmalloc(size, GFP_KERNEL);
|
||||
if (!adev->bios) {
|
||||
DRM_ERROR("Unable to allocate bios\n");
|
||||
dev_err(adev->dev, "Unable to allocate bios\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -364,7 +368,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
|||
return false;
|
||||
tbl_size = hdr->length;
|
||||
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
|
||||
DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
|
||||
dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -377,13 +381,13 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
|||
|
||||
offset += sizeof(VFCT_IMAGE_HEADER);
|
||||
if (offset > tbl_size) {
|
||||
DRM_ERROR("ACPI VFCT image header truncated\n");
|
||||
dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += vhdr->ImageLength;
|
||||
if (offset > tbl_size) {
|
||||
DRM_ERROR("ACPI VFCT image truncated\n");
|
||||
dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -406,7 +410,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
|
|||
}
|
||||
}
|
||||
|
||||
DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
|
||||
dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
|
@ -453,7 +457,7 @@ bool amdgpu_get_bios(struct amdgpu_device *adev)
|
|||
goto success;
|
||||
}
|
||||
|
||||
DRM_ERROR("Unable to locate a BIOS ROM\n");
|
||||
dev_err(adev->dev, "Unable to locate a BIOS ROM\n");
|
||||
return false;
|
||||
|
||||
success:
|
||||
|
|
|
@ -117,7 +117,7 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs
|
|||
if (cs->in.num_chunks == 0)
|
||||
return 0;
|
||||
|
||||
chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL);
|
||||
chunk_array = kvmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL);
|
||||
if (!chunk_array)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -144,7 +144,7 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs
|
|||
}
|
||||
|
||||
p->nchunks = cs->in.num_chunks;
|
||||
p->chunks = kmalloc_array(p->nchunks, sizeof(struct amdgpu_cs_chunk),
|
||||
p->chunks = kvmalloc_array(p->nchunks, sizeof(struct amdgpu_cs_chunk),
|
||||
GFP_KERNEL);
|
||||
if (!p->chunks) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -238,7 +238,7 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, union drm_amdgpu_cs
|
|||
|
||||
if (p->uf_entry.tv.bo)
|
||||
p->job->uf_addr = uf_offset;
|
||||
kfree(chunk_array);
|
||||
kvfree(chunk_array);
|
||||
|
||||
/* Use this opportunity to fill in task info for the vm */
|
||||
amdgpu_vm_set_task_info(vm);
|
||||
|
@ -250,11 +250,11 @@ free_all_kdata:
|
|||
free_partial_kdata:
|
||||
for (; i >= 0; i--)
|
||||
kvfree(p->chunks[i].kdata);
|
||||
kfree(p->chunks);
|
||||
kvfree(p->chunks);
|
||||
p->chunks = NULL;
|
||||
p->nchunks = 0;
|
||||
free_chunk:
|
||||
kfree(chunk_array);
|
||||
kvfree(chunk_array);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -559,7 +559,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
|||
sizeof(struct page *),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!e->user_pages) {
|
||||
DRM_ERROR("calloc failure\n");
|
||||
DRM_ERROR("kvmalloc_array failure\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -706,7 +706,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error,
|
|||
|
||||
for (i = 0; i < parser->nchunks; i++)
|
||||
kvfree(parser->chunks[i].kdata);
|
||||
kfree(parser->chunks);
|
||||
kvfree(parser->chunks);
|
||||
if (parser->job)
|
||||
amdgpu_job_free(parser->job);
|
||||
if (parser->uf_entry.tv.bo) {
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/poll.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_pm.h"
|
||||
|
@ -38,45 +37,6 @@
|
|||
#include "amdgpu_securedisplay.h"
|
||||
#include "amdgpu_fw_attestation.h"
|
||||
|
||||
/**
|
||||
* amdgpu_debugfs_add_files - Add simple debugfs entries
|
||||
*
|
||||
* @adev: Device to attach debugfs entries to
|
||||
* @files: Array of function callbacks that respond to reads
|
||||
* @nfiles: Number of callbacks to register
|
||||
*
|
||||
*/
|
||||
int amdgpu_debugfs_add_files(struct amdgpu_device *adev,
|
||||
const struct drm_info_list *files,
|
||||
unsigned nfiles)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < adev->debugfs_count; i++) {
|
||||
if (adev->debugfs[i].files == files) {
|
||||
/* Already registered */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
i = adev->debugfs_count + 1;
|
||||
if (i > AMDGPU_DEBUGFS_MAX_COMPONENTS) {
|
||||
DRM_ERROR("Reached maximum number of debugfs components.\n");
|
||||
DRM_ERROR("Report so we increase "
|
||||
"AMDGPU_DEBUGFS_MAX_COMPONENTS.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
adev->debugfs[adev->debugfs_count].files = files;
|
||||
adev->debugfs[adev->debugfs_count].num_files = nfiles;
|
||||
adev->debugfs_count = i;
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
drm_debugfs_create_files(files, nfiles,
|
||||
adev_to_drm(adev)->primary->debugfs_root,
|
||||
adev_to_drm(adev)->primary);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
@ -1228,22 +1188,20 @@ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
|
|||
adev, debugfs_regs[i]);
|
||||
if (!i && !IS_ERR_OR_NULL(ent))
|
||||
i_size_write(ent->d_inode, adev->rmmio_size);
|
||||
adev->debugfs_regs[i] = ent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data)
|
||||
static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
int r = 0, i;
|
||||
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (r < 0) {
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1285,30 +1243,19 @@ static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_debugfs_get_vbios_dump(struct seq_file *m, void *data)
|
||||
static int amdgpu_debugfs_evict_vram(void *data, u64 *val)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
|
||||
seq_write(m, adev->bios, adev->bios_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_debugfs_evict_vram(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)data;
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
int r;
|
||||
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
if (r < 0) {
|
||||
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
return r;
|
||||
}
|
||||
|
||||
seq_printf(m, "(%d)\n", amdgpu_bo_evict_vram(adev));
|
||||
*val = amdgpu_bo_evict_vram(adev);
|
||||
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
@ -1316,11 +1263,11 @@ static int amdgpu_debugfs_evict_vram(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data)
|
||||
|
||||
static int amdgpu_debugfs_evict_gtt(void *data, u64 *val)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)data;
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
struct ttm_resource_manager *man;
|
||||
int r;
|
||||
|
||||
|
@ -1331,8 +1278,7 @@ static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data)
|
|||
}
|
||||
|
||||
man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
|
||||
r = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
|
||||
seq_printf(m, "(%d)\n", r);
|
||||
*val = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
|
||||
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
@ -1340,10 +1286,11 @@ static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_debugfs_vm_info(struct seq_file *m, void *data)
|
||||
|
||||
static int amdgpu_debugfs_vm_info_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
struct drm_file *file;
|
||||
int r;
|
||||
|
||||
|
@ -1369,13 +1316,12 @@ static int amdgpu_debugfs_vm_info(struct seq_file *m, void *data)
|
|||
return r;
|
||||
}
|
||||
|
||||
static const struct drm_info_list amdgpu_debugfs_list[] = {
|
||||
{"amdgpu_vbios", amdgpu_debugfs_get_vbios_dump},
|
||||
{"amdgpu_test_ib", &amdgpu_debugfs_test_ib},
|
||||
{"amdgpu_evict_vram", &amdgpu_debugfs_evict_vram},
|
||||
{"amdgpu_evict_gtt", &amdgpu_debugfs_evict_gtt},
|
||||
{"amdgpu_vm_info", &amdgpu_debugfs_vm_info},
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_test_ib);
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_vm_info);
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_evict_vram_fops, amdgpu_debugfs_evict_vram,
|
||||
NULL, "%lld\n");
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_evict_gtt_fops, amdgpu_debugfs_evict_gtt,
|
||||
NULL, "%lld\n");
|
||||
|
||||
static void amdgpu_ib_preempt_fences_swap(struct amdgpu_ring *ring,
|
||||
struct dma_fence **fences)
|
||||
|
@ -1586,71 +1532,50 @@ static int amdgpu_debugfs_sclk_set(void *data, u64 val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(fops_ib_preempt, NULL,
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_ib_preempt, NULL,
|
||||
amdgpu_debugfs_ib_preempt, "%llu\n");
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(fops_sclk_set, NULL,
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_sclk_set, NULL,
|
||||
amdgpu_debugfs_sclk_set, "%llu\n");
|
||||
|
||||
int amdgpu_debugfs_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct dentry *root = adev_to_drm(adev)->primary->debugfs_root;
|
||||
struct dentry *ent;
|
||||
int r, i;
|
||||
|
||||
adev->debugfs_preempt =
|
||||
debugfs_create_file("amdgpu_preempt_ib", 0600,
|
||||
adev_to_drm(adev)->primary->debugfs_root, adev,
|
||||
&fops_ib_preempt);
|
||||
if (!(adev->debugfs_preempt)) {
|
||||
|
||||
|
||||
ent = debugfs_create_file("amdgpu_preempt_ib", 0600, root, adev,
|
||||
&fops_ib_preempt);
|
||||
if (!ent) {
|
||||
DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
adev->smu.debugfs_sclk =
|
||||
debugfs_create_file("amdgpu_force_sclk", 0200,
|
||||
adev_to_drm(adev)->primary->debugfs_root, adev,
|
||||
&fops_sclk_set);
|
||||
if (!(adev->smu.debugfs_sclk)) {
|
||||
ent = debugfs_create_file("amdgpu_force_sclk", 0200, root, adev,
|
||||
&fops_sclk_set);
|
||||
if (!ent) {
|
||||
DRM_ERROR("unable to create amdgpu_set_sclk debugsfs file\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Register debugfs entries for amdgpu_ttm */
|
||||
r = amdgpu_ttm_debugfs_init(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to init debugfs\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = amdgpu_debugfs_pm_init(adev);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to register debugfs file for dpm!\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
if (amdgpu_debugfs_sa_init(adev)) {
|
||||
dev_err(adev->dev, "failed to register debugfs file for SA\n");
|
||||
}
|
||||
|
||||
if (amdgpu_debugfs_fence_init(adev))
|
||||
dev_err(adev->dev, "fence debugfs file creation failed\n");
|
||||
|
||||
r = amdgpu_debugfs_gem_init(adev);
|
||||
if (r)
|
||||
DRM_ERROR("registering gem debugfs failed (%d).\n", r);
|
||||
amdgpu_ttm_debugfs_init(adev);
|
||||
amdgpu_debugfs_pm_init(adev);
|
||||
amdgpu_debugfs_sa_init(adev);
|
||||
amdgpu_debugfs_fence_init(adev);
|
||||
amdgpu_debugfs_gem_init(adev);
|
||||
|
||||
r = amdgpu_debugfs_regs_init(adev);
|
||||
if (r)
|
||||
DRM_ERROR("registering register debugfs failed (%d).\n", r);
|
||||
|
||||
r = amdgpu_debugfs_firmware_init(adev);
|
||||
if (r)
|
||||
DRM_ERROR("registering firmware debugfs failed (%d).\n", r);
|
||||
amdgpu_debugfs_firmware_init(adev);
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC)
|
||||
if (amdgpu_device_has_dc_support(adev)) {
|
||||
if (dtn_debugfs_init(adev))
|
||||
DRM_ERROR("amdgpu: failed initialize dtn debugfs support.\n");
|
||||
}
|
||||
if (amdgpu_device_has_dc_support(adev))
|
||||
dtn_debugfs_init(adev);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
|
@ -1665,17 +1590,26 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
|
|||
}
|
||||
|
||||
amdgpu_ras_debugfs_create_all(adev);
|
||||
|
||||
amdgpu_debugfs_autodump_init(adev);
|
||||
|
||||
amdgpu_rap_debugfs_init(adev);
|
||||
|
||||
amdgpu_securedisplay_debugfs_init(adev);
|
||||
|
||||
amdgpu_fw_attestation_debugfs_init(adev);
|
||||
|
||||
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list,
|
||||
ARRAY_SIZE(amdgpu_debugfs_list));
|
||||
debugfs_create_file("amdgpu_evict_vram", 0444, root, adev,
|
||||
&amdgpu_evict_vram_fops);
|
||||
debugfs_create_file("amdgpu_evict_gtt", 0444, root, adev,
|
||||
&amdgpu_evict_gtt_fops);
|
||||
debugfs_create_file("amdgpu_test_ib", 0444, root, adev,
|
||||
&amdgpu_debugfs_test_ib_fops);
|
||||
debugfs_create_file("amdgpu_vm_info", 0444, root, adev,
|
||||
&amdgpu_debugfs_vm_info_fops);
|
||||
|
||||
adev->debugfs_vbios_blob.data = adev->bios;
|
||||
adev->debugfs_vbios_blob.size = adev->bios_size;
|
||||
debugfs_create_blob("amdgpu_vbios", 0444, root,
|
||||
&adev->debugfs_vbios_blob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -26,11 +26,6 @@
|
|||
/*
|
||||
* Debugfs
|
||||
*/
|
||||
struct amdgpu_debugfs {
|
||||
const struct drm_info_list *files;
|
||||
unsigned num_files;
|
||||
};
|
||||
|
||||
struct amdgpu_autodump {
|
||||
struct completion dumping;
|
||||
struct wait_queue_head gpu_hang;
|
||||
|
@ -39,10 +34,7 @@ struct amdgpu_autodump {
|
|||
int amdgpu_debugfs_regs_init(struct amdgpu_device *adev);
|
||||
int amdgpu_debugfs_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_debugfs_add_files(struct amdgpu_device *adev,
|
||||
const struct drm_info_list *files,
|
||||
unsigned nfiles);
|
||||
int amdgpu_debugfs_fence_init(struct amdgpu_device *adev);
|
||||
int amdgpu_debugfs_firmware_init(struct amdgpu_device *adev);
|
||||
int amdgpu_debugfs_gem_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_fence_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_gem_init(struct amdgpu_device *adev);
|
||||
int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -870,17 +870,62 @@ static int amdgpu_display_get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb
|
|||
return r;
|
||||
}
|
||||
|
||||
int amdgpu_display_gem_fb_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rfb->base.obj[0] = obj;
|
||||
drm_helper_mode_fill_fb_struct(dev, &rfb->base, mode_cmd);
|
||||
ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = amdgpu_display_framebuffer_init(dev, rfb, mode_cmd, obj);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
drm_err(dev, "Failed to init gem fb: %d\n", ret);
|
||||
rfb->base.obj[0] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_display_gem_fb_verify_and_init(
|
||||
struct drm_device *dev, struct amdgpu_framebuffer *rfb,
|
||||
struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rfb->base.obj[0] = obj;
|
||||
|
||||
/* Verify that bo size can fit the fb size. */
|
||||
ret = drm_gem_fb_init_with_funcs(dev, &rfb->base, file_priv, mode_cmd,
|
||||
&amdgpu_fb_funcs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = amdgpu_display_framebuffer_init(dev, rfb, mode_cmd, obj);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
drm_err(dev, "Failed to verify and init gem fb: %d\n", ret);
|
||||
rfb->base.obj[0] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
int ret, i;
|
||||
rfb->base.obj[0] = obj;
|
||||
drm_helper_mode_fill_fb_struct(dev, &rfb->base, mode_cmd);
|
||||
ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* This needs to happen before modifier conversion as that might change
|
||||
|
@ -891,13 +936,13 @@ int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
|||
drm_dbg_kms(dev, "Plane 0 and %d have different BOs: %u vs. %u\n",
|
||||
i, mode_cmd->handles[0], mode_cmd->handles[i]);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = amdgpu_display_get_fb_info(rfb, &rfb->tiling_flags, &rfb->tmz_surface);
|
||||
if (ret)
|
||||
goto fail;
|
||||
return ret;
|
||||
|
||||
if (dev->mode_config.allow_fb_modifiers &&
|
||||
!(rfb->base.flags & DRM_MODE_FB_MODIFIERS)) {
|
||||
|
@ -905,20 +950,17 @@ int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
|||
if (ret) {
|
||||
drm_dbg_kms(dev, "Failed to convert tiling flags 0x%llX to a modifier",
|
||||
rfb->tiling_flags);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < rfb->base.format->num_planes; ++i) {
|
||||
drm_gem_object_get(rfb->base.obj[0]);
|
||||
drm_gem_object_put(rfb->base.obj[i]);
|
||||
rfb->base.obj[i] = rfb->base.obj[0];
|
||||
drm_gem_object_get(rfb->base.obj[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
rfb->base.obj[0] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct drm_framebuffer *
|
||||
|
@ -953,13 +995,15 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev,
|
|||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ret = amdgpu_display_framebuffer_init(dev, amdgpu_fb, mode_cmd, obj);
|
||||
ret = amdgpu_display_gem_fb_verify_and_init(dev, amdgpu_fb, file_priv,
|
||||
mode_cmd, obj);
|
||||
if (ret) {
|
||||
kfree(amdgpu_fb);
|
||||
drm_gem_object_put(obj);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
drm_gem_object_put(obj);
|
||||
return &amdgpu_fb->base;
|
||||
}
|
||||
|
||||
|
|
|
@ -321,17 +321,12 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach,
|
|||
struct sg_table *sgt,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct dma_buf *dma_buf = attach->dmabuf;
|
||||
struct drm_gem_object *obj = dma_buf->priv;
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
|
||||
if (sgt->sgl->page_link) {
|
||||
dma_unmap_sgtable(attach->dev, sgt, dir, 0);
|
||||
sg_free_table(sgt);
|
||||
kfree(sgt);
|
||||
} else {
|
||||
amdgpu_vram_mgr_free_sgt(adev, attach->dev, dir, sgt);
|
||||
amdgpu_vram_mgr_free_sgt(attach->dev, dir, sgt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,22 +429,22 @@ amdgpu_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf)
|
|||
{
|
||||
struct dma_resv *resv = dma_buf->resv;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_bo *bo;
|
||||
struct amdgpu_bo_param bp;
|
||||
struct drm_gem_object *gobj;
|
||||
struct amdgpu_bo *bo;
|
||||
uint64_t flags = 0;
|
||||
int ret;
|
||||
|
||||
memset(&bp, 0, sizeof(bp));
|
||||
bp.size = dma_buf->size;
|
||||
bp.byte_align = PAGE_SIZE;
|
||||
bp.domain = AMDGPU_GEM_DOMAIN_CPU;
|
||||
bp.flags = 0;
|
||||
bp.type = ttm_bo_type_sg;
|
||||
bp.resv = resv;
|
||||
dma_resv_lock(resv, NULL);
|
||||
|
||||
if (dma_buf->ops == &amdgpu_dmabuf_ops) {
|
||||
struct amdgpu_bo *other = gem_to_amdgpu_bo(dma_buf->priv);
|
||||
|
||||
flags |= other->flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC;
|
||||
}
|
||||
|
||||
ret = amdgpu_gem_object_create(adev, dma_buf->size, PAGE_SIZE,
|
||||
AMDGPU_GEM_DOMAIN_CPU,
|
||||
0, ttm_bo_type_sg, resv, &gobj);
|
||||
AMDGPU_GEM_DOMAIN_CPU, flags,
|
||||
ttm_bo_type_sg, resv, &gobj);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/vga_switcheroo.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <linux/mmu_notifier.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_irq.h"
|
||||
|
@ -45,6 +46,8 @@
|
|||
#include "amdgpu_amdkfd.h"
|
||||
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_xgmi.h"
|
||||
#include "amdgpu_reset.h"
|
||||
|
||||
/*
|
||||
* KMS wrapper.
|
||||
|
@ -90,9 +93,10 @@
|
|||
* - 3.38.0 - Add AMDGPU_IB_FLAG_EMIT_MEM_SYNC
|
||||
* - 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
|
||||
*/
|
||||
#define KMS_DRIVER_MAJOR 3
|
||||
#define KMS_DRIVER_MINOR 40
|
||||
#define KMS_DRIVER_MINOR 41
|
||||
#define KMS_DRIVER_PATCHLEVEL 0
|
||||
|
||||
int amdgpu_vram_limit;
|
||||
|
@ -145,6 +149,7 @@ int amdgpu_compute_multipipe = -1;
|
|||
int amdgpu_gpu_recovery = -1; /* auto */
|
||||
int amdgpu_emu_mode;
|
||||
uint amdgpu_smu_memory_pool_size;
|
||||
int amdgpu_smu_pptable_id = -1;
|
||||
/*
|
||||
* FBC (bit 0) disabled by default
|
||||
* MULTI_MON_PP_MCLK_SWITCH (bit 1) enabled by default
|
||||
|
@ -162,16 +167,26 @@ int amdgpu_discovery = -1;
|
|||
int amdgpu_mes;
|
||||
int amdgpu_noretry = -1;
|
||||
int amdgpu_force_asic_type = -1;
|
||||
int amdgpu_tmz;
|
||||
int amdgpu_tmz = -1; /* auto */
|
||||
uint amdgpu_freesync_vid_mode;
|
||||
int amdgpu_reset_method = -1; /* auto */
|
||||
int amdgpu_num_kcq = -1;
|
||||
|
||||
static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
|
||||
|
||||
struct amdgpu_mgpu_info mgpu_info = {
|
||||
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex),
|
||||
.delayed_reset_work = __DELAYED_WORK_INITIALIZER(
|
||||
mgpu_info.delayed_reset_work,
|
||||
amdgpu_drv_delayed_reset_work_handler, 0),
|
||||
};
|
||||
int amdgpu_ras_enable = -1;
|
||||
uint amdgpu_ras_mask = 0xffffffff;
|
||||
int amdgpu_bad_page_threshold = -1;
|
||||
struct amdgpu_watchdog_timer amdgpu_watchdog_timer = {
|
||||
.timeout_fatal_disable = false,
|
||||
.period = 0x23, /* default to max. timeout = 1 << 0x23 cycles */
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: vramlimit (int)
|
||||
|
@ -502,7 +517,7 @@ module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444);
|
|||
* DOC: gpu_recovery (int)
|
||||
* Set to enable GPU recovery mechanism (1 = enable, 0 = disable). The default is -1 (auto, disabled except SRIOV).
|
||||
*/
|
||||
MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (1 = enable, 0 = disable, -1 = auto)");
|
||||
MODULE_PARM_DESC(gpu_recovery, "Enable GPU recovery mechanism, (2 = advanced tdr mode, 1 = enable, 0 = disable, -1 = auto)");
|
||||
module_param_named(gpu_recovery, amdgpu_gpu_recovery, int, 0444);
|
||||
|
||||
/**
|
||||
|
@ -527,6 +542,20 @@ module_param_named(ras_enable, amdgpu_ras_enable, int, 0444);
|
|||
MODULE_PARM_DESC(ras_mask, "Mask of RAS features to enable (default 0xffffffff), only valid when ras_enable == 1");
|
||||
module_param_named(ras_mask, amdgpu_ras_mask, uint, 0444);
|
||||
|
||||
/**
|
||||
* DOC: timeout_fatal_disable (bool)
|
||||
* Disable Watchdog timeout fatal error event
|
||||
*/
|
||||
MODULE_PARM_DESC(timeout_fatal_disable, "disable watchdog timeout fatal error (false = default)");
|
||||
module_param_named(timeout_fatal_disable, amdgpu_watchdog_timer.timeout_fatal_disable, bool, 0644);
|
||||
|
||||
/**
|
||||
* DOC: timeout_period (uint)
|
||||
* Modify the watchdog timeout max_cycles as (1 << period)
|
||||
*/
|
||||
MODULE_PARM_DESC(timeout_period, "watchdog timeout period (1 to 0x23(default), timeout maxCycles = (1 << period)");
|
||||
module_param_named(timeout_period, amdgpu_watchdog_timer.period, uint, 0644);
|
||||
|
||||
/**
|
||||
* DOC: si_support (int)
|
||||
* Set SI support driver. This parameter works after set config CONFIG_DRM_AMDGPU_SI. For SI asic, when radeon driver is enabled,
|
||||
|
@ -748,6 +777,13 @@ bool no_system_mem_limit;
|
|||
module_param(no_system_mem_limit, bool, 0644);
|
||||
MODULE_PARM_DESC(no_system_mem_limit, "disable system memory limit (false = default)");
|
||||
|
||||
/**
|
||||
* DOC: no_queue_eviction_on_vm_fault (int)
|
||||
* If set, process queues will not be evicted on gpuvm fault. This is to keep the wavefront context for debugging (0 = queue eviction, 1 = no queue eviction). The default is 0 (queue eviction).
|
||||
*/
|
||||
int amdgpu_no_queue_eviction_on_vm_fault = 0;
|
||||
MODULE_PARM_DESC(no_queue_eviction_on_vm_fault, "No queue eviction on VM fault (0 = queue eviction, 1 = no queue eviction)");
|
||||
module_param_named(no_queue_eviction_on_vm_fault, amdgpu_no_queue_eviction_on_vm_fault, int, 0444);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -792,9 +828,20 @@ module_param_named(backlight, amdgpu_backlight, bint, 0444);
|
|||
*
|
||||
* The default value: 0 (off). TODO: change to auto till it is completed.
|
||||
*/
|
||||
MODULE_PARM_DESC(tmz, "Enable TMZ feature (-1 = auto, 0 = off (default), 1 = on)");
|
||||
MODULE_PARM_DESC(tmz, "Enable TMZ feature (-1 = auto (default), 0 = off, 1 = on)");
|
||||
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.
|
||||
* The default value: 0 (off).
|
||||
*/
|
||||
MODULE_PARM_DESC(
|
||||
freesync_video,
|
||||
"Enable freesync modesetting optimization feature (0 = off (default), 1 = on)");
|
||||
module_param_named(freesync_video, amdgpu_freesync_vid_mode, uint, 0444);
|
||||
|
||||
/**
|
||||
* DOC: reset_method (int)
|
||||
* GPU reset method (-1 = auto (default), 0 = legacy, 1 = mode0, 2 = mode1, 3 = mode2, 4 = baco, 5 = pci)
|
||||
|
@ -815,6 +862,15 @@ module_param_named(bad_page_threshold, amdgpu_bad_page_threshold, int, 0444);
|
|||
MODULE_PARM_DESC(num_kcq, "number of kernel compute queue user want to setup (8 if set to greater than 8 or less than 0, only affect gfx 8+)");
|
||||
module_param_named(num_kcq, amdgpu_num_kcq, int, 0444);
|
||||
|
||||
/**
|
||||
* DOC: smu_pptable_id (int)
|
||||
* Used to override pptable id. id = 0 use VBIOS pptable.
|
||||
* id > 0 use the soft pptable with specicfied id.
|
||||
*/
|
||||
MODULE_PARM_DESC(smu_pptable_id,
|
||||
"specify pptable id to be used (-1 = auto(default) value, 0 = use pptable from vbios, > 0 = soft pptable id)");
|
||||
module_param_named(smu_pptable_id, amdgpu_smu_pptable_id, int, 0444);
|
||||
|
||||
static const struct pci_device_id pciidlist[] = {
|
||||
#ifdef CONFIG_DRM_AMDGPU_SI
|
||||
{0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI},
|
||||
|
@ -1125,6 +1181,11 @@ static const struct pci_device_id pciidlist[] = {
|
|||
{0x1002, 0x73E2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},
|
||||
{0x1002, 0x73FF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_DIMGREY_CAVEFISH},
|
||||
|
||||
/* Aldebaran */
|
||||
{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},
|
||||
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
|
@ -1279,6 +1340,98 @@ amdgpu_pci_shutdown(struct pci_dev *pdev)
|
|||
adev->mp1_state = PP_MP1_STATE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_drv_delayed_reset_work_handler - work handler for reset
|
||||
*
|
||||
* @work: work_struct.
|
||||
*/
|
||||
static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work)
|
||||
{
|
||||
struct list_head device_list;
|
||||
struct amdgpu_device *adev;
|
||||
int i, r;
|
||||
struct amdgpu_reset_context reset_context;
|
||||
|
||||
memset(&reset_context, 0, sizeof(reset_context));
|
||||
|
||||
mutex_lock(&mgpu_info.mutex);
|
||||
if (mgpu_info.pending_reset == true) {
|
||||
mutex_unlock(&mgpu_info.mutex);
|
||||
return;
|
||||
}
|
||||
mgpu_info.pending_reset = true;
|
||||
mutex_unlock(&mgpu_info.mutex);
|
||||
|
||||
/* Use a common context, just need to make sure full reset is done */
|
||||
reset_context.method = AMD_RESET_METHOD_NONE;
|
||||
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
|
||||
|
||||
for (i = 0; i < mgpu_info.num_dgpu; i++) {
|
||||
adev = mgpu_info.gpu_ins[i].adev;
|
||||
reset_context.reset_req_dev = adev;
|
||||
r = amdgpu_device_pre_asic_reset(adev, &reset_context);
|
||||
if (r) {
|
||||
dev_err(adev->dev, "GPU pre asic reset failed with err, %d for drm dev, %s ",
|
||||
r, adev_to_drm(adev)->unique);
|
||||
}
|
||||
if (!queue_work(system_unbound_wq, &adev->xgmi_reset_work))
|
||||
r = -EALREADY;
|
||||
}
|
||||
for (i = 0; i < mgpu_info.num_dgpu; i++) {
|
||||
adev = mgpu_info.gpu_ins[i].adev;
|
||||
flush_work(&adev->xgmi_reset_work);
|
||||
adev->gmc.xgmi.pending_reset = false;
|
||||
}
|
||||
|
||||
/* reset function will rebuild the xgmi hive info , clear it now */
|
||||
for (i = 0; i < mgpu_info.num_dgpu; i++)
|
||||
amdgpu_xgmi_remove_device(mgpu_info.gpu_ins[i].adev);
|
||||
|
||||
INIT_LIST_HEAD(&device_list);
|
||||
|
||||
for (i = 0; i < mgpu_info.num_dgpu; i++)
|
||||
list_add_tail(&mgpu_info.gpu_ins[i].adev->reset_list, &device_list);
|
||||
|
||||
/* unregister the GPU first, reset function will add them back */
|
||||
list_for_each_entry(adev, &device_list, reset_list)
|
||||
amdgpu_unregister_gpu_instance(adev);
|
||||
|
||||
/* Use a common context, just need to make sure full reset is done */
|
||||
set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags);
|
||||
r = amdgpu_do_asic_reset(&device_list, &reset_context);
|
||||
|
||||
if (r) {
|
||||
DRM_ERROR("reinit gpus failure");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < mgpu_info.num_dgpu; i++) {
|
||||
adev = mgpu_info.gpu_ins[i].adev;
|
||||
if (!adev->kfd.init_complete)
|
||||
amdgpu_amdkfd_device_init(adev);
|
||||
amdgpu_ttm_set_buffer_funcs_status(adev, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_prepare(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
||||
/* Return a positive number here so
|
||||
* DPM_FLAG_SMART_SUSPEND works properly
|
||||
*/
|
||||
if (amdgpu_device_supports_boco(drm_dev))
|
||||
return pm_runtime_suspended(dev) &&
|
||||
pm_suspend_via_firmware();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_pmops_complete(struct device *dev)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
static int amdgpu_pmops_suspend(struct device *dev)
|
||||
{
|
||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||
|
@ -1364,7 +1517,7 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
|
|||
}
|
||||
|
||||
adev->in_runpm = true;
|
||||
if (amdgpu_device_supports_atpx(drm_dev))
|
||||
if (amdgpu_device_supports_px(drm_dev))
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
|
||||
ret = amdgpu_device_suspend(drm_dev, false);
|
||||
|
@ -1373,16 +1526,14 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (amdgpu_device_supports_atpx(drm_dev)) {
|
||||
if (amdgpu_device_supports_px(drm_dev)) {
|
||||
/* Only need to handle PCI state in the driver for ATPX
|
||||
* PCI core handles it for _PR3.
|
||||
*/
|
||||
if (!amdgpu_is_atpx_hybrid()) {
|
||||
amdgpu_device_cache_pci_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_ignore_hotplug(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3cold);
|
||||
}
|
||||
amdgpu_device_cache_pci_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_ignore_hotplug(pdev);
|
||||
pci_set_power_state(pdev, PCI_D3cold);
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
|
||||
} else if (amdgpu_device_supports_baco(drm_dev)) {
|
||||
amdgpu_device_baco_enter(drm_dev);
|
||||
|
@ -1401,19 +1552,17 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
|
|||
if (!adev->runpm)
|
||||
return -EINVAL;
|
||||
|
||||
if (amdgpu_device_supports_atpx(drm_dev)) {
|
||||
if (amdgpu_device_supports_px(drm_dev)) {
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
|
||||
/* Only need to handle PCI state in the driver for ATPX
|
||||
* PCI core handles it for _PR3.
|
||||
*/
|
||||
if (!amdgpu_is_atpx_hybrid()) {
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
amdgpu_device_load_pci_state(pdev);
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
amdgpu_device_load_pci_state(pdev);
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
pci_set_master(pdev);
|
||||
} else if (amdgpu_device_supports_boco(drm_dev)) {
|
||||
/* Only need to handle PCI state in the driver for ATPX
|
||||
|
@ -1424,7 +1573,7 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
|
|||
amdgpu_device_baco_exit(drm_dev);
|
||||
}
|
||||
ret = amdgpu_device_resume(drm_dev, false);
|
||||
if (amdgpu_device_supports_atpx(drm_dev))
|
||||
if (amdgpu_device_supports_px(drm_dev))
|
||||
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
||||
adev->in_runpm = false;
|
||||
return 0;
|
||||
|
@ -1505,6 +1654,8 @@ out:
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops amdgpu_pm_ops = {
|
||||
.prepare = amdgpu_pmops_prepare,
|
||||
.complete = amdgpu_pmops_complete,
|
||||
.suspend = amdgpu_pmops_suspend,
|
||||
.resume = amdgpu_pmops_resume,
|
||||
.freeze = amdgpu_pmops_freeze,
|
||||
|
|
|
@ -232,8 +232,8 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = amdgpu_display_framebuffer_init(adev_to_drm(adev), &rfbdev->rfb,
|
||||
&mode_cmd, gobj);
|
||||
ret = amdgpu_display_gem_fb_init(adev_to_drm(adev), &rfbdev->rfb,
|
||||
&mode_cmd, gobj);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize framebuffer %d\n", ret);
|
||||
goto out;
|
||||
|
|
|
@ -36,8 +36,6 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_debugfs.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_trace.h"
|
||||
|
||||
|
@ -441,7 +439,8 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
|
|||
* Helper function for amdgpu_fence_driver_init().
|
||||
*/
|
||||
int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring,
|
||||
unsigned num_hw_submission)
|
||||
unsigned num_hw_submission,
|
||||
atomic_t *sched_score)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
long timeout;
|
||||
|
@ -469,30 +468,31 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring,
|
|||
return -ENOMEM;
|
||||
|
||||
/* No need to setup the GPU scheduler for rings that don't need it */
|
||||
if (!ring->no_scheduler) {
|
||||
switch (ring->funcs->type) {
|
||||
case AMDGPU_RING_TYPE_GFX:
|
||||
timeout = adev->gfx_timeout;
|
||||
break;
|
||||
case AMDGPU_RING_TYPE_COMPUTE:
|
||||
timeout = adev->compute_timeout;
|
||||
break;
|
||||
case AMDGPU_RING_TYPE_SDMA:
|
||||
timeout = adev->sdma_timeout;
|
||||
break;
|
||||
default:
|
||||
timeout = adev->video_timeout;
|
||||
break;
|
||||
}
|
||||
if (ring->no_scheduler)
|
||||
return 0;
|
||||
|
||||
r = drm_sched_init(&ring->sched, &amdgpu_sched_ops,
|
||||
num_hw_submission, amdgpu_job_hang_limit,
|
||||
timeout, ring->name);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to create scheduler on ring %s.\n",
|
||||
ring->name);
|
||||
return r;
|
||||
}
|
||||
switch (ring->funcs->type) {
|
||||
case AMDGPU_RING_TYPE_GFX:
|
||||
timeout = adev->gfx_timeout;
|
||||
break;
|
||||
case AMDGPU_RING_TYPE_COMPUTE:
|
||||
timeout = adev->compute_timeout;
|
||||
break;
|
||||
case AMDGPU_RING_TYPE_SDMA:
|
||||
timeout = adev->sdma_timeout;
|
||||
break;
|
||||
default:
|
||||
timeout = adev->video_timeout;
|
||||
break;
|
||||
}
|
||||
|
||||
r = drm_sched_init(&ring->sched, &amdgpu_sched_ops,
|
||||
num_hw_submission, amdgpu_job_hang_limit,
|
||||
timeout, sched_score, ring->name);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to create scheduler on ring %s.\n",
|
||||
ring->name);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -533,6 +533,8 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
|
|||
|
||||
if (!ring || !ring->fence_drv.initialized)
|
||||
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 */
|
||||
|
@ -541,8 +543,7 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
|
|||
if (ring->fence_drv.irq_src)
|
||||
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
|
||||
ring->fence_drv.irq_type);
|
||||
if (!ring->no_scheduler)
|
||||
drm_sched_fini(&ring->sched);
|
||||
|
||||
del_timer_sync(&ring->fence_drv.fallback_timer);
|
||||
for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
|
||||
dma_fence_put(ring->fence_drv.fences[j]);
|
||||
|
@ -697,11 +698,9 @@ static const struct dma_fence_ops amdgpu_fence_ops = {
|
|||
* Fence debugfs
|
||||
*/
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data)
|
||||
static int amdgpu_debugfs_fence_info_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
|
||||
|
@ -746,11 +745,10 @@ static int amdgpu_debugfs_fence_info(struct seq_file *m, void *data)
|
|||
*
|
||||
* Manually trigger a gpu reset at the next fence wait.
|
||||
*/
|
||||
static int amdgpu_debugfs_gpu_recover(struct seq_file *m, void *data)
|
||||
static int gpu_recover_get(void *data, u64 *val)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)data;
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
int r;
|
||||
|
||||
r = pm_runtime_get_sync(dev->dev);
|
||||
|
@ -759,8 +757,7 @@ static int amdgpu_debugfs_gpu_recover(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
seq_printf(m, "gpu recover\n");
|
||||
amdgpu_device_gpu_recover(adev, NULL);
|
||||
*val = amdgpu_device_gpu_recover(adev, NULL);
|
||||
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
pm_runtime_put_autosuspend(dev->dev);
|
||||
|
@ -768,26 +765,24 @@ static int amdgpu_debugfs_gpu_recover(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_info_list amdgpu_debugfs_fence_list[] = {
|
||||
{"amdgpu_fence_info", &amdgpu_debugfs_fence_info, 0, NULL},
|
||||
{"amdgpu_gpu_recover", &amdgpu_debugfs_gpu_recover, 0, NULL}
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_fence_info);
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gpu_recover_fops, gpu_recover_get, NULL,
|
||||
"%lld\n");
|
||||
|
||||
static const struct drm_info_list amdgpu_debugfs_fence_list_sriov[] = {
|
||||
{"amdgpu_fence_info", &amdgpu_debugfs_fence_info, 0, NULL},
|
||||
};
|
||||
#endif
|
||||
|
||||
int amdgpu_debugfs_fence_init(struct amdgpu_device *adev)
|
||||
void amdgpu_debugfs_fence_init(struct amdgpu_device *adev)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_fence_list_sriov,
|
||||
ARRAY_SIZE(amdgpu_debugfs_fence_list_sriov));
|
||||
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_fence_list,
|
||||
ARRAY_SIZE(amdgpu_debugfs_fence_list));
|
||||
#else
|
||||
return 0;
|
||||
struct drm_minor *minor = adev_to_drm(adev)->primary;
|
||||
struct dentry *root = minor->debugfs_root;
|
||||
|
||||
debugfs_create_file("amdgpu_fence_info", 0444, root, adev,
|
||||
&amdgpu_debugfs_fence_info_fops);
|
||||
|
||||
if (!amdgpu_sriov_vf(adev))
|
||||
debugfs_create_file("amdgpu_gpu_recover", 0444, root, adev,
|
||||
&amdgpu_debugfs_gpu_recover_fops);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
*/
|
||||
static int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct page *dummy_page = ttm_bo_glob.dummy_read_page;
|
||||
struct page *dummy_page = ttm_glob.dummy_read_page;
|
||||
|
||||
if (adev->dummy_page_addr)
|
||||
return 0;
|
||||
|
@ -126,6 +126,8 @@ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
|
|||
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
r = amdgpu_bo_create(adev, &bp, &adev->gart.bo);
|
||||
if (r) {
|
||||
return r;
|
||||
|
@ -202,6 +204,7 @@ void amdgpu_gart_table_vram_free(struct amdgpu_device *adev)
|
|||
return;
|
||||
}
|
||||
amdgpu_bo_unref(&adev->gart.bo);
|
||||
adev->gart.ptr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -236,9 +239,6 @@ int amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset,
|
|||
t = offset / AMDGPU_GPU_PAGE_SIZE;
|
||||
p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
|
||||
for (i = 0; i < pages; i++, p++) {
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
adev->gart.pages[p] = NULL;
|
||||
#endif
|
||||
page_base = adev->dummy_page_addr;
|
||||
if (!adev->gart.ptr)
|
||||
continue;
|
||||
|
@ -312,9 +312,6 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
|
|||
int pages, struct page **pagelist, dma_addr_t *dma_addr,
|
||||
uint64_t flags)
|
||||
{
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
unsigned t,p;
|
||||
#endif
|
||||
int r, i;
|
||||
|
||||
if (!adev->gart.ready) {
|
||||
|
@ -322,13 +319,6 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
t = offset / AMDGPU_GPU_PAGE_SIZE;
|
||||
p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
|
||||
for (i = 0; i < pages; i++, p++)
|
||||
adev->gart.pages[p] = pagelist ? pagelist[i] : NULL;
|
||||
#endif
|
||||
|
||||
if (!adev->gart.ptr)
|
||||
return 0;
|
||||
|
||||
|
@ -373,14 +363,6 @@ int amdgpu_gart_init(struct amdgpu_device *adev)
|
|||
DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
|
||||
adev->gart.num_cpu_pages, adev->gart.num_gpu_pages);
|
||||
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
/* Allocate pages table */
|
||||
adev->gart.pages = vzalloc(array_size(sizeof(void *),
|
||||
adev->gart.num_cpu_pages));
|
||||
if (adev->gart.pages == NULL)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -393,9 +375,5 @@ int amdgpu_gart_init(struct amdgpu_device *adev)
|
|||
*/
|
||||
void amdgpu_gart_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
vfree(adev->gart.pages);
|
||||
adev->gart.pages = NULL;
|
||||
#endif
|
||||
amdgpu_gart_dummy_page_fini(adev);
|
||||
}
|
||||
|
|
|
@ -46,9 +46,6 @@ struct amdgpu_gart {
|
|||
unsigned num_gpu_pages;
|
||||
unsigned num_cpu_pages;
|
||||
unsigned table_size;
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
struct page **pages;
|
||||
#endif
|
||||
bool ready;
|
||||
|
||||
/* Asic default pte flags */
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include <linux/dma-buf.h>
|
||||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/drm_gem_ttm_helper.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
|
@ -59,6 +58,7 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
|
|||
struct drm_gem_object **obj)
|
||||
{
|
||||
struct amdgpu_bo *bo;
|
||||
struct amdgpu_bo_user *ubo;
|
||||
struct amdgpu_bo_param bp;
|
||||
int r;
|
||||
|
||||
|
@ -72,10 +72,13 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
|
|||
bp.preferred_domain = initial_domain;
|
||||
bp.flags = flags;
|
||||
bp.domain = initial_domain;
|
||||
r = amdgpu_bo_create(adev, &bp, &bo);
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
r = amdgpu_bo_create_user(adev, &bp, &ubo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
bo = &ubo->bo;
|
||||
*obj = &bo->tbo.base;
|
||||
(*obj)->funcs = &amdgpu_gem_object_funcs;
|
||||
|
||||
|
@ -855,10 +858,10 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv,
|
|||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
static int amdgpu_debugfs_gem_info(struct seq_file *m, void *data)
|
||||
static int amdgpu_debugfs_gem_info_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
struct drm_file *file;
|
||||
int r;
|
||||
|
||||
|
@ -896,16 +899,17 @@ static int amdgpu_debugfs_gem_info(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_info_list amdgpu_debugfs_gem_list[] = {
|
||||
{"amdgpu_gem_info", &amdgpu_debugfs_gem_info, 0, NULL},
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_gem_info);
|
||||
|
||||
#endif
|
||||
|
||||
int amdgpu_debugfs_gem_init(struct amdgpu_device *adev)
|
||||
void amdgpu_debugfs_gem_init(struct amdgpu_device *adev)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_gem_list,
|
||||
ARRAY_SIZE(amdgpu_debugfs_gem_list));
|
||||
struct drm_minor *minor = adev_to_drm(adev)->primary;
|
||||
struct dentry *root = minor->debugfs_root;
|
||||
|
||||
debugfs_create_file("amdgpu_gem_info", 0444, root, adev,
|
||||
&amdgpu_debugfs_gem_info_fops);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -310,9 +310,8 @@ int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev,
|
|||
ring->eop_gpu_addr = kiq->eop_gpu_addr;
|
||||
ring->no_scheduler = true;
|
||||
sprintf(ring->name, "kiq_%d.%d.%d", ring->me, ring->pipe, ring->queue);
|
||||
r = amdgpu_ring_init(adev, ring, 1024,
|
||||
irq, AMDGPU_CP_KIQ_IRQ_DRIVER0,
|
||||
AMDGPU_RING_PRIO_DEFAULT);
|
||||
r = amdgpu_ring_init(adev, ring, 1024, irq, AMDGPU_CP_KIQ_IRQ_DRIVER0,
|
||||
AMDGPU_RING_PRIO_DEFAULT, NULL);
|
||||
if (r)
|
||||
dev_warn(adev->dev, "(%d) failed to init kiq ring\n", r);
|
||||
|
||||
|
@ -463,20 +462,25 @@ int amdgpu_gfx_disable_kcq(struct amdgpu_device *adev)
|
|||
{
|
||||
struct amdgpu_kiq *kiq = &adev->gfx.kiq;
|
||||
struct amdgpu_ring *kiq_ring = &kiq->ring;
|
||||
int i;
|
||||
int i, r;
|
||||
|
||||
if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&adev->gfx.kiq.ring_lock);
|
||||
if (amdgpu_ring_alloc(kiq_ring, kiq->pmf->unmap_queues_size *
|
||||
adev->gfx.num_compute_rings))
|
||||
adev->gfx.num_compute_rings)) {
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < adev->gfx.num_compute_rings; i++)
|
||||
kiq->pmf->kiq_unmap_queues(kiq_ring, &adev->gfx.compute_ring[i],
|
||||
RESET_QUEUES, 0, 0);
|
||||
r = amdgpu_ring_test_helper(kiq_ring);
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
|
||||
return amdgpu_ring_test_helper(kiq_ring);
|
||||
return r;
|
||||
}
|
||||
|
||||
int amdgpu_queue_mask_bit_to_set_resource_bit(struct amdgpu_device *adev,
|
||||
|
@ -519,12 +523,13 @@ int amdgpu_gfx_enable_kcq(struct amdgpu_device *adev)
|
|||
|
||||
DRM_INFO("kiq ring mec %d pipe %d q %d\n", kiq_ring->me, kiq_ring->pipe,
|
||||
kiq_ring->queue);
|
||||
|
||||
spin_lock(&adev->gfx.kiq.ring_lock);
|
||||
r = amdgpu_ring_alloc(kiq_ring, kiq->pmf->map_queues_size *
|
||||
adev->gfx.num_compute_rings +
|
||||
kiq->pmf->set_resources_size);
|
||||
if (r) {
|
||||
DRM_ERROR("Failed to lock KIQ (%d).\n", r);
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -533,6 +538,7 @@ int amdgpu_gfx_enable_kcq(struct amdgpu_device *adev)
|
|||
kiq->pmf->kiq_map_queues(kiq_ring, &adev->gfx.compute_ring[i]);
|
||||
|
||||
r = amdgpu_ring_test_helper(kiq_ring);
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
if (r)
|
||||
DRM_ERROR("KCQ enable failed\n");
|
||||
|
||||
|
@ -601,6 +607,7 @@ 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);
|
||||
|
@ -612,13 +619,19 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev)
|
|||
strcpy(adev->gfx.ras_if->name, "gfx");
|
||||
}
|
||||
fs_info.head = ih_info.head = *adev->gfx.ras_if;
|
||||
|
||||
r = amdgpu_ras_late_init(adev, adev->gfx.ras_if,
|
||||
&fs_info, &ih_info);
|
||||
if (r)
|
||||
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 {
|
||||
amdgpu_ras_reset_error_status(adev, AMDGPU_RAS_BLOCK__GFX);
|
||||
}
|
||||
|
||||
r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
|
||||
if (r)
|
||||
goto late_fini;
|
||||
|
@ -664,8 +677,9 @@ int amdgpu_gfx_process_ras_data_cb(struct amdgpu_device *adev,
|
|||
*/
|
||||
if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) {
|
||||
kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
|
||||
if (adev->gfx.funcs->query_ras_error_count)
|
||||
adev->gfx.funcs->query_ras_error_count(adev, err_data);
|
||||
if (adev->gfx.ras_funcs &&
|
||||
adev->gfx.ras_funcs->query_ras_error_count)
|
||||
adev->gfx.ras_funcs->query_ras_error_count(adev, err_data);
|
||||
amdgpu_ras_reset_gpu(adev);
|
||||
}
|
||||
return AMDGPU_RAS_SUCCESS;
|
||||
|
@ -698,7 +712,7 @@ uint32_t amdgpu_kiq_rreg(struct amdgpu_device *adev, uint32_t reg)
|
|||
struct amdgpu_kiq *kiq = &adev->gfx.kiq;
|
||||
struct amdgpu_ring *ring = &kiq->ring;
|
||||
|
||||
if (adev->in_pci_err_recovery)
|
||||
if (amdgpu_device_skip_hw_access(adev))
|
||||
return 0;
|
||||
|
||||
BUG_ON(!ring->funcs->emit_rreg);
|
||||
|
@ -765,7 +779,7 @@ void amdgpu_kiq_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
|
|||
|
||||
BUG_ON(!ring->funcs->emit_wreg);
|
||||
|
||||
if (adev->in_pci_err_recovery)
|
||||
if (amdgpu_device_skip_hw_access(adev))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&kiq->ring_lock, flags);
|
||||
|
@ -829,14 +843,10 @@ int amdgpu_gfx_get_num_kcq(struct amdgpu_device *adev)
|
|||
|
||||
void amdgpu_gfx_state_change_set(struct amdgpu_device *adev, enum gfx_change_state state)
|
||||
{
|
||||
if (is_support_sw_smu(adev)) {
|
||||
smu_gfx_state_change_set(&adev->smu, state);
|
||||
} else {
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->gfx_state_change_set)
|
||||
((adev)->powerplay.pp_funcs->gfx_state_change_set(
|
||||
(adev)->powerplay.pp_handle, state));
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
mutex_lock(&adev->pm.mutex);
|
||||
if (adev->powerplay.pp_funcs &&
|
||||
adev->powerplay.pp_funcs->gfx_state_change_set)
|
||||
((adev)->powerplay.pp_funcs->gfx_state_change_set(
|
||||
(adev)->powerplay.pp_handle, state));
|
||||
mutex_unlock(&adev->pm.mutex);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "clearstate_defs.h"
|
||||
#include "amdgpu_ring.h"
|
||||
#include "amdgpu_rlc.h"
|
||||
#include "soc15.h"
|
||||
|
||||
/* GFX current status */
|
||||
#define AMDGPU_GFX_NORMAL_MODE 0x00000000L
|
||||
|
@ -204,6 +205,19 @@ struct amdgpu_cu_info {
|
|||
uint32_t bitmap[4][4];
|
||||
};
|
||||
|
||||
struct amdgpu_gfx_ras_funcs {
|
||||
int (*ras_late_init)(struct amdgpu_device *adev);
|
||||
void (*ras_fini)(struct amdgpu_device *adev);
|
||||
int (*ras_error_inject)(struct amdgpu_device *adev,
|
||||
void *inject_if);
|
||||
int (*query_ras_error_count)(struct amdgpu_device *adev,
|
||||
void *ras_error_status);
|
||||
void (*reset_ras_error_count)(struct amdgpu_device *adev);
|
||||
void (*query_ras_error_status)(struct amdgpu_device *adev);
|
||||
void (*reset_ras_error_status)(struct amdgpu_device *adev);
|
||||
void (*enable_watchdog_timer)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_gfx_funcs {
|
||||
/* get the gpu clock counter */
|
||||
uint64_t (*get_gpu_clock_counter)(struct amdgpu_device *adev);
|
||||
|
@ -219,11 +233,7 @@ struct amdgpu_gfx_funcs {
|
|||
uint32_t *dst);
|
||||
void (*select_me_pipe_q)(struct amdgpu_device *adev, u32 me, u32 pipe,
|
||||
u32 queue, u32 vmid);
|
||||
int (*ras_error_inject)(struct amdgpu_device *adev, void *inject_if);
|
||||
int (*query_ras_error_count) (struct amdgpu_device *adev, void *ras_error_status);
|
||||
void (*reset_ras_error_count) (struct amdgpu_device *adev);
|
||||
void (*init_spm_golden)(struct amdgpu_device *adev);
|
||||
void (*query_ras_error_status) (struct amdgpu_device *adev);
|
||||
void (*update_perfmon_mgcg)(struct amdgpu_device *adev, bool enable);
|
||||
};
|
||||
|
||||
|
@ -327,7 +337,8 @@ struct amdgpu_gfx {
|
|||
DECLARE_BITMAP (pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES);
|
||||
|
||||
/*ras */
|
||||
struct ras_common_if *ras_if;
|
||||
struct ras_common_if *ras_if;
|
||||
const struct amdgpu_gfx_ras_funcs *ras_funcs;
|
||||
};
|
||||
|
||||
#define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))
|
||||
|
|
|
@ -31,6 +31,59 @@
|
|||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_xgmi.h"
|
||||
|
||||
/**
|
||||
* amdgpu_gmc_pdb0_alloc - allocate vram for pdb0
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* Allocate video memory for pdb0 and map it for CPU access
|
||||
* Returns 0 for success, error for failure.
|
||||
*/
|
||||
int amdgpu_gmc_pdb0_alloc(struct amdgpu_device *adev)
|
||||
{
|
||||
int r;
|
||||
struct amdgpu_bo_param bp;
|
||||
u64 vram_size = adev->gmc.xgmi.node_segment_size * adev->gmc.xgmi.num_physical_nodes;
|
||||
uint32_t pde0_page_shift = adev->gmc.vmid0_page_table_block_size + 21;
|
||||
uint32_t npdes = (vram_size + (1ULL << pde0_page_shift) -1) >> pde0_page_shift;
|
||||
|
||||
memset(&bp, 0, sizeof(bp));
|
||||
bp.size = PAGE_ALIGN((npdes + 1) * 8);
|
||||
bp.byte_align = PAGE_SIZE;
|
||||
bp.domain = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
bp.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
|
||||
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
r = amdgpu_bo_create(adev, &bp, &adev->gmc.pdb0_bo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_bo_reserve(adev->gmc.pdb0_bo, false);
|
||||
if (unlikely(r != 0))
|
||||
goto bo_reserve_failure;
|
||||
|
||||
r = amdgpu_bo_pin(adev->gmc.pdb0_bo, AMDGPU_GEM_DOMAIN_VRAM);
|
||||
if (r)
|
||||
goto bo_pin_failure;
|
||||
r = amdgpu_bo_kmap(adev->gmc.pdb0_bo, &adev->gmc.ptr_pdb0);
|
||||
if (r)
|
||||
goto bo_kmap_failure;
|
||||
|
||||
amdgpu_bo_unreserve(adev->gmc.pdb0_bo);
|
||||
return 0;
|
||||
|
||||
bo_kmap_failure:
|
||||
amdgpu_bo_unpin(adev->gmc.pdb0_bo);
|
||||
bo_pin_failure:
|
||||
amdgpu_bo_unreserve(adev->gmc.pdb0_bo);
|
||||
bo_reserve_failure:
|
||||
amdgpu_bo_unref(&adev->gmc.pdb0_bo);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gmc_get_pde_for_bo - get the PDE for a BO
|
||||
*
|
||||
|
@ -158,6 +211,39 @@ void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
|
|||
mc->vram_end, mc->real_vram_size >> 20);
|
||||
}
|
||||
|
||||
/** amdgpu_gmc_sysvm_location - place vram and gart in sysvm aperture
|
||||
*
|
||||
* @adev: amdgpu device structure holding all necessary information
|
||||
* @mc: memory controller structure holding memory information
|
||||
*
|
||||
* This function is only used if use GART for FB translation. In such
|
||||
* case, we use sysvm aperture (vmid0 page tables) for both vram
|
||||
* and gart (aka system memory) access.
|
||||
*
|
||||
* GPUVM (and our organization of vmid0 page tables) require sysvm
|
||||
* aperture to be placed at a location aligned with 8 times of native
|
||||
* page size. For example, if vm_context0_cntl.page_table_block_size
|
||||
* is 12, then native page size is 8G (2M*2^12), sysvm should start
|
||||
* with a 64G aligned address. For simplicity, we just put sysvm at
|
||||
* address 0. So vram start at address 0 and gart is right after vram.
|
||||
*/
|
||||
void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc)
|
||||
{
|
||||
u64 hive_vram_start = 0;
|
||||
u64 hive_vram_end = mc->xgmi.node_segment_size * mc->xgmi.num_physical_nodes - 1;
|
||||
mc->vram_start = mc->xgmi.node_segment_size * mc->xgmi.physical_node_id;
|
||||
mc->vram_end = mc->vram_start + mc->xgmi.node_segment_size - 1;
|
||||
mc->gart_start = hive_vram_end + 1;
|
||||
mc->gart_end = mc->gart_start + mc->gart_size - 1;
|
||||
mc->fb_start = hive_vram_start;
|
||||
mc->fb_end = hive_vram_end;
|
||||
dev_info(adev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
|
||||
mc->mc_vram_size >> 20, mc->vram_start,
|
||||
mc->vram_end, mc->real_vram_size >> 20);
|
||||
dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n",
|
||||
mc->gart_size >> 20, mc->gart_start, mc->gart_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gmc_gart_location - try to find GART location
|
||||
*
|
||||
|
@ -165,7 +251,6 @@ void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
|
|||
* @mc: memory controller structure holding memory information
|
||||
*
|
||||
* Function will place try to place GART before or after VRAM.
|
||||
*
|
||||
* If GART size is bigger than space left then we ajust GART size.
|
||||
* Thus function will never fails.
|
||||
*/
|
||||
|
@ -176,8 +261,6 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc)
|
|||
/*To avoid the hole, limit the max mc address to AMDGPU_GMC_HOLE_START*/
|
||||
u64 max_mc_address = min(adev->gmc.mc_mask, AMDGPU_GMC_HOLE_START - 1);
|
||||
|
||||
mc->gart_size += adev->pm.smu_prv_buffer_size;
|
||||
|
||||
/* VCE doesn't like it when BOs cross a 4GB segment, so align
|
||||
* the GART base on a 4GB boundary as well.
|
||||
*/
|
||||
|
@ -308,26 +391,46 @@ int amdgpu_gmc_ras_late_init(struct amdgpu_device *adev)
|
|||
{
|
||||
int r;
|
||||
|
||||
if (adev->umc.funcs && adev->umc.funcs->ras_late_init) {
|
||||
r = adev->umc.funcs->ras_late_init(adev);
|
||||
if (adev->umc.ras_funcs &&
|
||||
adev->umc.ras_funcs->ras_late_init) {
|
||||
r = adev->umc.ras_funcs->ras_late_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (adev->mmhub.funcs && adev->mmhub.funcs->ras_late_init) {
|
||||
r = adev->mmhub.funcs->ras_late_init(adev);
|
||||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->ras_late_init) {
|
||||
r = adev->mmhub.ras_funcs->ras_late_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return amdgpu_xgmi_ras_late_init(adev);
|
||||
if (!adev->gmc.xgmi.connected_to_cpu)
|
||||
adev->gmc.xgmi.ras_funcs = &xgmi_ras_funcs;
|
||||
|
||||
if (adev->gmc.xgmi.ras_funcs &&
|
||||
adev->gmc.xgmi.ras_funcs->ras_late_init) {
|
||||
r = adev->gmc.xgmi.ras_funcs->ras_late_init(adev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amdgpu_gmc_ras_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_umc_ras_fini(adev);
|
||||
amdgpu_mmhub_ras_fini(adev);
|
||||
amdgpu_xgmi_ras_fini(adev);
|
||||
if (adev->umc.ras_funcs &&
|
||||
adev->umc.ras_funcs->ras_fini)
|
||||
adev->umc.ras_funcs->ras_fini(adev);
|
||||
|
||||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->ras_fini)
|
||||
amdgpu_mmhub_ras_fini(adev);
|
||||
|
||||
if (adev->gmc.xgmi.ras_funcs &&
|
||||
adev->gmc.xgmi.ras_funcs->ras_fini)
|
||||
adev->gmc.xgmi.ras_funcs->ras_fini(adev);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -384,6 +487,16 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
|
|||
{
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_RAVEN:
|
||||
if (amdgpu_tmz == 0) {
|
||||
adev->gmc.tmz_enabled = false;
|
||||
dev_info(adev->dev,
|
||||
"Trusted Memory Zone (TMZ) feature disabled (cmd line)\n");
|
||||
} else {
|
||||
adev->gmc.tmz_enabled = true;
|
||||
dev_info(adev->dev,
|
||||
"Trusted Memory Zone (TMZ) feature enabled\n");
|
||||
}
|
||||
break;
|
||||
case CHIP_RENOIR:
|
||||
case CHIP_NAVI10:
|
||||
case CHIP_NAVI14:
|
||||
|
@ -423,6 +536,8 @@ void amdgpu_gmc_noretry_set(struct amdgpu_device *adev)
|
|||
switch (adev->asic_type) {
|
||||
case CHIP_VEGA10:
|
||||
case CHIP_VEGA20:
|
||||
case CHIP_ARCTURUS:
|
||||
case CHIP_ALDEBARAN:
|
||||
/*
|
||||
* noretry = 0 will cause kfd page fault tests fail
|
||||
* for some ASICs, so set default to 1 for these ASICs.
|
||||
|
@ -518,3 +633,55 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev)
|
|||
adev->mman.stolen_extended_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gmc_init_pdb0 - initialize PDB0
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
*
|
||||
* This function is only used when GART page table is used
|
||||
* for FB address translatioin. In such a case, we construct
|
||||
* a 2-level system VM page table: PDB0->PTB, to cover both
|
||||
* VRAM of the hive and system memory.
|
||||
*
|
||||
* PDB0 is static, initialized once on driver initialization.
|
||||
* The first n entries of PDB0 are used as PTE by setting
|
||||
* P bit to 1, pointing to VRAM. The n+1'th entry points
|
||||
* to a big PTB covering system memory.
|
||||
*
|
||||
*/
|
||||
void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev)
|
||||
{
|
||||
int i;
|
||||
uint64_t flags = adev->gart.gart_pte_flags; //TODO it is UC. explore NC/RW?
|
||||
/* Each PDE0 (used as PTE) covers (2^vmid0_page_table_block_size)*2M
|
||||
*/
|
||||
u64 vram_size = adev->gmc.xgmi.node_segment_size * adev->gmc.xgmi.num_physical_nodes;
|
||||
u64 pde0_page_size = (1ULL<<adev->gmc.vmid0_page_table_block_size)<<21;
|
||||
u64 vram_addr = adev->vm_manager.vram_base_offset -
|
||||
adev->gmc.xgmi.physical_node_id * adev->gmc.xgmi.node_segment_size;
|
||||
u64 vram_end = vram_addr + vram_size;
|
||||
u64 gart_ptb_gpu_pa = amdgpu_bo_gpu_offset(adev->gart.bo) +
|
||||
adev->vm_manager.vram_base_offset - adev->gmc.vram_start;
|
||||
|
||||
flags |= AMDGPU_PTE_VALID | AMDGPU_PTE_READABLE;
|
||||
flags |= AMDGPU_PTE_WRITEABLE;
|
||||
flags |= AMDGPU_PTE_SNOOPED;
|
||||
flags |= AMDGPU_PTE_FRAG((adev->gmc.vmid0_page_table_block_size + 9*1));
|
||||
flags |= AMDGPU_PDE_PTE;
|
||||
|
||||
/* The first n PDE0 entries are used as PTE,
|
||||
* pointing to vram
|
||||
*/
|
||||
for (i = 0; vram_addr < vram_end; i++, vram_addr += pde0_page_size)
|
||||
amdgpu_gmc_set_pte_pde(adev, adev->gmc.ptr_pdb0, i, vram_addr, flags);
|
||||
|
||||
/* The n+1'th PDE0 entry points to a huge
|
||||
* PTB who has more than 512 entries each
|
||||
* pointing to a 4K system page
|
||||
*/
|
||||
flags = AMDGPU_PTE_VALID;
|
||||
flags |= AMDGPU_PDE_BFS(0) | AMDGPU_PTE_SNOOPED;
|
||||
/* Requires gart_ptb_gpu_pa to be 4K aligned */
|
||||
amdgpu_gmc_set_pte_pde(adev, adev->gmc.ptr_pdb0, i, gart_ptb_gpu_pa, flags);
|
||||
}
|
||||
|
|
|
@ -135,6 +135,14 @@ struct amdgpu_gmc_funcs {
|
|||
unsigned int (*get_vbios_fb_size)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_xgmi_ras_funcs {
|
||||
int (*ras_late_init)(struct amdgpu_device *adev);
|
||||
void (*ras_fini)(struct amdgpu_device *adev);
|
||||
int (*query_ras_error_count)(struct amdgpu_device *adev,
|
||||
void *ras_error_status);
|
||||
void (*reset_ras_error_count)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_xgmi {
|
||||
/* from psp */
|
||||
u64 node_id;
|
||||
|
@ -149,6 +157,9 @@ struct amdgpu_xgmi {
|
|||
struct list_head head;
|
||||
bool supported;
|
||||
struct ras_common_if *ras_if;
|
||||
bool connected_to_cpu;
|
||||
bool pending_reset;
|
||||
const struct amdgpu_xgmi_ras_funcs *ras_funcs;
|
||||
};
|
||||
|
||||
struct amdgpu_gmc {
|
||||
|
@ -189,10 +200,13 @@ struct amdgpu_gmc {
|
|||
u64 gart_end;
|
||||
/* Frame buffer aperture of this GPU device. Different from
|
||||
* fb_start (see below), this only covers the local GPU device.
|
||||
* Driver get fb_start from MC_VM_FB_LOCATION_BASE (set by vbios)
|
||||
* and calculate vram_start of this local device by adding an
|
||||
* offset inside the XGMI hive.
|
||||
* Under VMID0, logical address == MC address
|
||||
* If driver uses FB aperture to access FB, driver get fb_start from
|
||||
* MC_VM_FB_LOCATION_BASE (set by vbios) and calculate vram_start
|
||||
* of this local device by adding an offset inside the XGMI hive.
|
||||
* If driver uses GART table for VMID0 FB access, driver finds a hole in
|
||||
* VMID0's virtual address space to place the SYSVM aperture inside
|
||||
* which the first part is vram and the second part is gart (covering
|
||||
* system ram).
|
||||
*/
|
||||
u64 vram_start;
|
||||
u64 vram_end;
|
||||
|
@ -204,6 +218,15 @@ struct amdgpu_gmc {
|
|||
*/
|
||||
u64 fb_start;
|
||||
u64 fb_end;
|
||||
/* In the case of use GART table for vmid0 FB access, [fb_start, fb_end]
|
||||
* will be squeezed to GART aperture. But we have a PSP FW issue to fix
|
||||
* for now. To temporarily workaround the PSP FW issue, added below two
|
||||
* variables to remember the original fb_start/end to re-enable FB
|
||||
* aperture to workaround the PSP FW issue. Will delete it after we
|
||||
* get a proper PSP FW fix.
|
||||
*/
|
||||
u64 fb_start_original;
|
||||
u64 fb_end_original;
|
||||
unsigned vram_width;
|
||||
u64 real_vram_size;
|
||||
int vram_mtrr;
|
||||
|
@ -240,6 +263,12 @@ struct amdgpu_gmc {
|
|||
struct amdgpu_xgmi xgmi;
|
||||
struct amdgpu_irq_src ecc_irq;
|
||||
int noretry;
|
||||
|
||||
uint32_t vmid0_page_table_block_size;
|
||||
uint32_t vmid0_page_table_depth;
|
||||
struct amdgpu_bo *pdb0_bo;
|
||||
/* CPU kmapped address of pdb0*/
|
||||
void *ptr_pdb0;
|
||||
};
|
||||
|
||||
#define amdgpu_gmc_flush_gpu_tlb(adev, vmid, vmhub, type) ((adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid), (vmhub), (type)))
|
||||
|
@ -281,6 +310,7 @@ static inline uint64_t amdgpu_gmc_sign_extend(uint64_t addr)
|
|||
return addr;
|
||||
}
|
||||
|
||||
int amdgpu_gmc_pdb0_alloc(struct amdgpu_device *adev);
|
||||
void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level,
|
||||
uint64_t *addr, uint64_t *flags);
|
||||
int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
|
||||
|
@ -288,6 +318,7 @@ int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr,
|
|||
uint64_t flags);
|
||||
uint64_t amdgpu_gmc_pd_addr(struct amdgpu_bo *bo);
|
||||
uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo);
|
||||
void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc);
|
||||
void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
|
||||
u64 base);
|
||||
void amdgpu_gmc_gart_location(struct amdgpu_device *adev,
|
||||
|
@ -309,4 +340,5 @@ amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type,
|
|||
|
||||
void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev);
|
||||
|
||||
void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev);
|
||||
#endif
|
||||
|
|
|
@ -49,8 +49,7 @@ static ssize_t amdgpu_mem_info_gtt_total_show(struct device *dev,
|
|||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%llu\n",
|
||||
man->size * PAGE_SIZE);
|
||||
return sysfs_emit(buf, "%llu\n", man->size * PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,8 +67,7 @@ static ssize_t amdgpu_mem_info_gtt_used_show(struct device *dev,
|
|||
struct amdgpu_device *adev = drm_to_adev(ddev);
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%llu\n",
|
||||
amdgpu_gtt_mgr_usage(man));
|
||||
return sysfs_emit(buf, "%llu\n", amdgpu_gtt_mgr_usage(man));
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include <drm/drm_debugfs.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "atom.h"
|
||||
|
@ -453,11 +452,9 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
|
|||
*/
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
static int amdgpu_debugfs_sa_info(struct seq_file *m, void *data)
|
||||
static int amdgpu_debugfs_sa_info_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
|
||||
seq_printf(m, "--------------------- DELAYED --------------------- \n");
|
||||
amdgpu_sa_bo_dump_debug_info(&adev->ib_pools[AMDGPU_IB_POOL_DELAYED],
|
||||
|
@ -471,18 +468,18 @@ static int amdgpu_debugfs_sa_info(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_info_list amdgpu_debugfs_sa_list[] = {
|
||||
{"amdgpu_sa_info", &amdgpu_debugfs_sa_info, 0, NULL},
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_sa_info);
|
||||
|
||||
#endif
|
||||
|
||||
int amdgpu_debugfs_sa_init(struct amdgpu_device *adev)
|
||||
void amdgpu_debugfs_sa_init(struct amdgpu_device *adev)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_sa_list,
|
||||
ARRAY_SIZE(amdgpu_debugfs_sa_list));
|
||||
#else
|
||||
return 0;
|
||||
struct drm_minor *minor = adev_to_drm(adev)->primary;
|
||||
struct dentry *root = minor->debugfs_root;
|
||||
|
||||
debugfs_create_file("amdgpu_sa_info", 0444, root, adev,
|
||||
&amdgpu_debugfs_sa_info_fops);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -99,6 +99,8 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
|
|||
ih->rptr_addr = adev->wb.gpu_addr + rptr_offs * 4;
|
||||
ih->rptr_cpu = &adev->wb.wb[rptr_offs];
|
||||
}
|
||||
|
||||
init_waitqueue_head(&ih->wait_process);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -160,6 +162,52 @@ void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
|
|||
}
|
||||
}
|
||||
|
||||
/* Waiter helper that checks current rptr matches or passes checkpoint wptr */
|
||||
static bool amdgpu_ih_has_checkpoint_processed(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
uint32_t checkpoint_wptr,
|
||||
uint32_t *prev_rptr)
|
||||
{
|
||||
uint32_t cur_rptr = ih->rptr | (*prev_rptr & ~ih->ptr_mask);
|
||||
|
||||
/* rptr has wrapped. */
|
||||
if (cur_rptr < *prev_rptr)
|
||||
cur_rptr += ih->ptr_mask + 1;
|
||||
*prev_rptr = cur_rptr;
|
||||
|
||||
return cur_rptr >= checkpoint_wptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_ih_wait_on_checkpoint_process - wait to process IVs up to checkpoint
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @ih: ih ring to process
|
||||
*
|
||||
* Used to ensure ring has processed IVs up to the checkpoint write pointer.
|
||||
*/
|
||||
int amdgpu_ih_wait_on_checkpoint_process(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih)
|
||||
{
|
||||
uint32_t checkpoint_wptr, rptr;
|
||||
|
||||
if (!ih->enabled || adev->shutdown)
|
||||
return -ENODEV;
|
||||
|
||||
checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
|
||||
/* Order wptr with rptr. */
|
||||
rmb();
|
||||
rptr = READ_ONCE(ih->rptr);
|
||||
|
||||
/* wptr has wrapped. */
|
||||
if (rptr > checkpoint_wptr)
|
||||
checkpoint_wptr += ih->ptr_mask + 1;
|
||||
|
||||
return wait_event_interruptible(ih->wait_process,
|
||||
amdgpu_ih_has_checkpoint_processed(adev, ih,
|
||||
checkpoint_wptr, &rptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_ih_process - interrupt handler
|
||||
*
|
||||
|
@ -180,10 +228,6 @@ int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih)
|
|||
wptr = amdgpu_ih_get_wptr(adev, ih);
|
||||
|
||||
restart_ih:
|
||||
/* is somebody else already processing irqs? */
|
||||
if (atomic_xchg(&ih->lock, 1))
|
||||
return IRQ_NONE;
|
||||
|
||||
DRM_DEBUG("%s: rptr %d, wptr %d\n", __func__, ih->rptr, wptr);
|
||||
|
||||
/* Order reading of wptr vs. reading of IH ring data */
|
||||
|
@ -195,7 +239,7 @@ restart_ih:
|
|||
}
|
||||
|
||||
amdgpu_ih_set_rptr(adev, ih);
|
||||
atomic_set(&ih->lock, 0);
|
||||
wake_up_all(&ih->wait_process);
|
||||
|
||||
/* make sure wptr hasn't changed while processing */
|
||||
wptr = amdgpu_ih_get_wptr(adev, ih);
|
||||
|
|
|
@ -64,8 +64,10 @@ struct amdgpu_ih_ring {
|
|||
|
||||
bool enabled;
|
||||
unsigned rptr;
|
||||
atomic_t lock;
|
||||
struct amdgpu_ih_regs ih_regs;
|
||||
|
||||
/* For waiting on IH processing at checkpoint. */
|
||||
wait_queue_head_t wait_process;
|
||||
};
|
||||
|
||||
/* provided by the ih block */
|
||||
|
@ -87,6 +89,8 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
|
|||
void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
|
||||
void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
|
||||
unsigned int num_dw);
|
||||
int amdgpu_ih_wait_on_checkpoint_process(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih);
|
||||
int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
|
||||
void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
|
||||
struct amdgpu_ih_ring *ih,
|
||||
|
|
|
@ -65,6 +65,41 @@
|
|||
|
||||
#define AMDGPU_WAIT_IDLE_TIMEOUT 200
|
||||
|
||||
const char *soc15_ih_clientid_name[] = {
|
||||
"IH",
|
||||
"SDMA2 or ACP",
|
||||
"ATHUB",
|
||||
"BIF",
|
||||
"SDMA3 or DCE",
|
||||
"SDMA4 or ISP",
|
||||
"VMC1 or PCIE0",
|
||||
"RLC",
|
||||
"SDMA0",
|
||||
"SDMA1",
|
||||
"SE0SH",
|
||||
"SE1SH",
|
||||
"SE2SH",
|
||||
"SE3SH",
|
||||
"VCN1 or UVD1",
|
||||
"THM",
|
||||
"VCN or UVD",
|
||||
"SDMA5 or VCE0",
|
||||
"VMC",
|
||||
"SDMA6 or XDMA",
|
||||
"GRBM_CP",
|
||||
"ATS",
|
||||
"ROM_SMUIO",
|
||||
"DF",
|
||||
"SDMA7 or VCE1",
|
||||
"PWR",
|
||||
"reserved",
|
||||
"UTCL2",
|
||||
"EA",
|
||||
"UTCL2LOG",
|
||||
"MP0",
|
||||
"MP1"
|
||||
};
|
||||
|
||||
/**
|
||||
* amdgpu_hotplug_work_func - work handler for display hotplug event
|
||||
*
|
||||
|
@ -164,13 +199,13 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg)
|
|||
* ack the interrupt if it is there
|
||||
*/
|
||||
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__PCIE_BIF)) {
|
||||
if (adev->nbio.funcs &&
|
||||
adev->nbio.funcs->handle_ras_controller_intr_no_bifring)
|
||||
adev->nbio.funcs->handle_ras_controller_intr_no_bifring(adev);
|
||||
if (adev->nbio.ras_funcs &&
|
||||
adev->nbio.ras_funcs->handle_ras_controller_intr_no_bifring)
|
||||
adev->nbio.ras_funcs->handle_ras_controller_intr_no_bifring(adev);
|
||||
|
||||
if (adev->nbio.funcs &&
|
||||
adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring)
|
||||
adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring(adev);
|
||||
if (adev->nbio.ras_funcs &&
|
||||
adev->nbio.ras_funcs->handle_ras_err_event_athub_intr_no_bifring)
|
||||
adev->nbio.ras_funcs->handle_ras_err_event_athub_intr_no_bifring(adev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -347,11 +382,6 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
|
|||
|
||||
kfree(src->enabled_types);
|
||||
src->enabled_types = NULL;
|
||||
if (src->data) {
|
||||
kfree(src->data);
|
||||
kfree(src);
|
||||
adev->irq.client[i].sources[j] = NULL;
|
||||
}
|
||||
}
|
||||
kfree(adev->irq.client[i].sources);
|
||||
adev->irq.client[i].sources = NULL;
|
||||
|
@ -535,7 +565,7 @@ void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
|
|||
for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
|
||||
struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
|
||||
|
||||
if (!src)
|
||||
if (!src || !src->funcs || !src->funcs->set)
|
||||
continue;
|
||||
for (k = 0; k < src->num_types; k++)
|
||||
amdgpu_irq_update(adev, src, k);
|
||||
|
|
|
@ -62,7 +62,6 @@ struct amdgpu_irq_src {
|
|||
unsigned num_types;
|
||||
atomic_t *enabled_types;
|
||||
const struct amdgpu_irq_src_funcs *funcs;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct amdgpu_irq_client {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "amdgpu.h"
|
||||
#include "amdgpu_trace.h"
|
||||
|
||||
static void amdgpu_job_timedout(struct drm_sched_job *s_job)
|
||||
static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job)
|
||||
{
|
||||
struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
|
||||
struct amdgpu_job *job = to_amdgpu_job(s_job);
|
||||
|
@ -41,7 +41,7 @@ static void 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;
|
||||
return DRM_GPU_SCHED_STAT_NOMINAL;
|
||||
}
|
||||
|
||||
amdgpu_vm_get_task_info(ring->adev, job->pasid, &ti);
|
||||
|
@ -53,10 +53,12 @@ static void 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
*/
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include "amdgpu_uvd.h"
|
||||
#include "amdgpu_vce.h"
|
||||
|
@ -160,7 +159,7 @@ int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (amdgpu_device_supports_atpx(dev) &&
|
||||
if (amdgpu_device_supports_px(dev) &&
|
||||
(amdgpu_runtime_pm != 0)) { /* enable runpm by default for atpx */
|
||||
adev->runpm = true;
|
||||
dev_info(adev->dev, "Using ATPX for runtime pm\n");
|
||||
|
@ -201,9 +200,13 @@ int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags)
|
|||
|
||||
if (adev->runpm) {
|
||||
/* only need to skip on ATPX */
|
||||
if (amdgpu_device_supports_atpx(dev) &&
|
||||
!amdgpu_is_atpx_hybrid())
|
||||
if (amdgpu_device_supports_px(dev))
|
||||
dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
|
||||
/* we want direct complete for BOCO */
|
||||
if (amdgpu_device_supports_boco(dev))
|
||||
dev_pm_set_driver_flags(dev->dev, DPM_FLAG_SMART_PREPARE |
|
||||
DPM_FLAG_SMART_SUSPEND |
|
||||
DPM_FLAG_MAY_SKIP_RESUME);
|
||||
pm_runtime_use_autosuspend(dev->dev);
|
||||
pm_runtime_set_autosuspend_delay(dev->dev, 5000);
|
||||
pm_runtime_allow(dev->dev);
|
||||
|
@ -287,22 +290,30 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info,
|
|||
break;
|
||||
case AMDGPU_INFO_FW_TA:
|
||||
switch (query_fw->index) {
|
||||
case 0:
|
||||
case TA_FW_TYPE_PSP_XGMI:
|
||||
fw_info->ver = adev->psp.ta_fw_version;
|
||||
fw_info->feature = adev->psp.ta_xgmi_ucode_version;
|
||||
break;
|
||||
case 1:
|
||||
case TA_FW_TYPE_PSP_RAS:
|
||||
fw_info->ver = adev->psp.ta_fw_version;
|
||||
fw_info->feature = adev->psp.ta_ras_ucode_version;
|
||||
break;
|
||||
case 2:
|
||||
case TA_FW_TYPE_PSP_HDCP:
|
||||
fw_info->ver = adev->psp.ta_fw_version;
|
||||
fw_info->feature = adev->psp.ta_hdcp_ucode_version;
|
||||
break;
|
||||
case 3:
|
||||
case TA_FW_TYPE_PSP_DTM:
|
||||
fw_info->ver = adev->psp.ta_fw_version;
|
||||
fw_info->feature = adev->psp.ta_dtm_ucode_version;
|
||||
break;
|
||||
case TA_FW_TYPE_PSP_RAP:
|
||||
fw_info->ver = adev->psp.ta_fw_version;
|
||||
fw_info->feature = adev->psp.ta_rap_ucode_version;
|
||||
break;
|
||||
case TA_FW_TYPE_PSP_SECUREDISPLAY:
|
||||
fw_info->ver = adev->psp.ta_fw_version;
|
||||
fw_info->feature = adev->psp.ta_securedisplay_ucode_version;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -981,6 +992,63 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
|||
min_t(u64, size, sizeof(ras_mask))) ?
|
||||
-EFAULT : 0;
|
||||
}
|
||||
case AMDGPU_INFO_VIDEO_CAPS: {
|
||||
const struct amdgpu_video_codecs *codecs;
|
||||
struct drm_amdgpu_info_video_caps *caps;
|
||||
int r;
|
||||
|
||||
switch (info->video_cap.type) {
|
||||
case AMDGPU_INFO_VIDEO_CAPS_DECODE:
|
||||
r = amdgpu_asic_query_video_codecs(adev, false, &codecs);
|
||||
if (r)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case AMDGPU_INFO_VIDEO_CAPS_ENCODE:
|
||||
r = amdgpu_asic_query_video_codecs(adev, true, &codecs);
|
||||
if (r)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("Invalid request %d\n",
|
||||
info->video_cap.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
caps = kzalloc(sizeof(*caps), GFP_KERNEL);
|
||||
if (!caps)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < codecs->codec_count; i++) {
|
||||
int idx = codecs->codec_array[i].codec_type;
|
||||
|
||||
switch (idx) {
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2:
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4:
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1:
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC:
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC:
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG:
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9:
|
||||
case AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1:
|
||||
caps->codec_info[idx].valid = 1;
|
||||
caps->codec_info[idx].max_width =
|
||||
codecs->codec_array[i].max_width;
|
||||
caps->codec_info[idx].max_height =
|
||||
codecs->codec_array[i].max_height;
|
||||
caps->codec_info[idx].max_pixels_per_frame =
|
||||
codecs->codec_array[i].max_pixels_per_frame;
|
||||
caps->codec_info[idx].max_level =
|
||||
codecs->codec_array[i].max_level;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
r = copy_to_user(out, caps,
|
||||
min((size_t)size, sizeof(*caps))) ? -EFAULT : 0;
|
||||
kfree(caps);
|
||||
return r;
|
||||
}
|
||||
default:
|
||||
DRM_DEBUG_KMS("Invalid request %d\n", info->query);
|
||||
return -EINVAL;
|
||||
|
@ -1262,16 +1330,25 @@ void amdgpu_disable_vblank_kms(struct drm_crtc *crtc)
|
|||
*/
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data)
|
||||
static int amdgpu_debugfs_firmware_info_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct drm_amdgpu_info_firmware fw_info;
|
||||
struct drm_amdgpu_query_fw query_fw;
|
||||
struct atom_context *ctx = adev->mode_info.atom_context;
|
||||
int ret, i;
|
||||
|
||||
static const char *ta_fw_name[TA_FW_TYPE_MAX_INDEX] = {
|
||||
#define TA_FW_NAME(type) [TA_FW_TYPE_PSP_##type] = #type
|
||||
TA_FW_NAME(XGMI),
|
||||
TA_FW_NAME(RAS),
|
||||
TA_FW_NAME(HDCP),
|
||||
TA_FW_NAME(DTM),
|
||||
TA_FW_NAME(RAP),
|
||||
TA_FW_NAME(SECUREDISPLAY),
|
||||
#undef TA_FW_NAME
|
||||
};
|
||||
|
||||
/* VCE */
|
||||
query_fw.fw_type = AMDGPU_INFO_FW_VCE;
|
||||
ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
|
||||
|
@ -1389,31 +1466,14 @@ static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data)
|
|||
fw_info.feature, fw_info.ver);
|
||||
|
||||
query_fw.fw_type = AMDGPU_INFO_FW_TA;
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = TA_FW_TYPE_PSP_XGMI; i < TA_FW_TYPE_MAX_INDEX; i++) {
|
||||
query_fw.index = i;
|
||||
ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
|
||||
if (ret)
|
||||
continue;
|
||||
switch (query_fw.index) {
|
||||
case 0:
|
||||
seq_printf(m, "TA %s feature version: 0x%08x, firmware version: 0x%08x\n",
|
||||
"RAS", fw_info.feature, fw_info.ver);
|
||||
break;
|
||||
case 1:
|
||||
seq_printf(m, "TA %s feature version: 0x%08x, firmware version: 0x%08x\n",
|
||||
"XGMI", fw_info.feature, fw_info.ver);
|
||||
break;
|
||||
case 2:
|
||||
seq_printf(m, "TA %s feature version: 0x%08x, firmware version: 0x%08x\n",
|
||||
"HDCP", fw_info.feature, fw_info.ver);
|
||||
break;
|
||||
case 3:
|
||||
seq_printf(m, "TA %s feature version: 0x%08x, firmware version: 0x%08x\n",
|
||||
"DTM", fw_info.feature, fw_info.ver);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
seq_printf(m, "TA %s feature version: 0x%08x, firmware version: 0x%08x\n",
|
||||
ta_fw_name[i], fw_info.feature, fw_info.ver);
|
||||
}
|
||||
|
||||
/* SMC */
|
||||
|
@ -1472,17 +1532,18 @@ static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_info_list amdgpu_firmware_info_list[] = {
|
||||
{"amdgpu_firmware_info", amdgpu_debugfs_firmware_info, 0, NULL},
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_firmware_info);
|
||||
|
||||
#endif
|
||||
|
||||
int amdgpu_debugfs_firmware_init(struct amdgpu_device *adev)
|
||||
void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
return amdgpu_debugfs_add_files(adev, amdgpu_firmware_info_list,
|
||||
ARRAY_SIZE(amdgpu_firmware_info_list));
|
||||
#else
|
||||
return 0;
|
||||
struct drm_minor *minor = adev_to_drm(adev)->primary;
|
||||
struct dentry *root = minor->debugfs_root;
|
||||
|
||||
debugfs_create_file("amdgpu_firmware_info", 0444, root,
|
||||
adev, &amdgpu_debugfs_firmware_info_fops);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -21,12 +21,16 @@
|
|||
#ifndef __AMDGPU_MMHUB_H__
|
||||
#define __AMDGPU_MMHUB_H__
|
||||
|
||||
struct amdgpu_mmhub_funcs {
|
||||
void (*ras_init)(struct amdgpu_device *adev);
|
||||
struct amdgpu_mmhub_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 *ras_error_status);
|
||||
void (*query_ras_error_status)(struct amdgpu_device *adev);
|
||||
void (*reset_ras_error_count)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_mmhub_funcs {
|
||||
u64 (*get_fb_location)(struct amdgpu_device *adev);
|
||||
void (*init)(struct amdgpu_device *adev);
|
||||
int (*gart_enable)(struct amdgpu_device *adev);
|
||||
|
@ -40,12 +44,12 @@ struct amdgpu_mmhub_funcs {
|
|||
uint64_t page_table_base);
|
||||
void (*update_power_gating)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*query_ras_error_status)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_mmhub {
|
||||
struct ras_common_if *ras_if;
|
||||
const struct amdgpu_mmhub_funcs *funcs;
|
||||
const struct amdgpu_mmhub_ras_funcs *ras_funcs;
|
||||
};
|
||||
|
||||
int amdgpu_mmhub_ras_late_init(struct amdgpu_device *adev);
|
||||
|
|
|
@ -602,6 +602,14 @@ int amdgpu_display_get_crtc_scanoutpos(struct drm_device *dev,
|
|||
int *hpos, ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
int amdgpu_display_gem_fb_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
int amdgpu_display_gem_fb_verify_and_init(
|
||||
struct drm_device *dev, struct amdgpu_framebuffer *rfb,
|
||||
struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
|
|
|
@ -47,6 +47,17 @@ struct nbio_hdp_flush_reg {
|
|||
u32 ref_and_mask_sdma7;
|
||||
};
|
||||
|
||||
struct amdgpu_nbio_ras_funcs {
|
||||
void (*handle_ras_controller_intr_no_bifring)(struct amdgpu_device *adev);
|
||||
void (*handle_ras_err_event_athub_intr_no_bifring)(struct amdgpu_device *adev);
|
||||
int (*init_ras_controller_interrupt)(struct amdgpu_device *adev);
|
||||
int (*init_ras_err_event_athub_interrupt)(struct amdgpu_device *adev);
|
||||
void (*query_ras_error_count)(struct amdgpu_device *adev,
|
||||
void *ras_error_status);
|
||||
int (*ras_late_init)(struct amdgpu_device *adev);
|
||||
void (*ras_fini)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_nbio_funcs {
|
||||
const struct nbio_hdp_flush_reg *hdp_flush_reg;
|
||||
u32 (*get_hdp_flush_req_offset)(struct amdgpu_device *adev);
|
||||
|
@ -79,13 +90,6 @@ struct amdgpu_nbio_funcs {
|
|||
void (*ih_control)(struct amdgpu_device *adev);
|
||||
void (*init_registers)(struct amdgpu_device *adev);
|
||||
void (*remap_hdp_registers)(struct amdgpu_device *adev);
|
||||
void (*handle_ras_controller_intr_no_bifring)(struct amdgpu_device *adev);
|
||||
void (*handle_ras_err_event_athub_intr_no_bifring)(struct amdgpu_device *adev);
|
||||
int (*init_ras_controller_interrupt)(struct amdgpu_device *adev);
|
||||
int (*init_ras_err_event_athub_interrupt)(struct amdgpu_device *adev);
|
||||
void (*query_ras_error_count)(struct amdgpu_device *adev,
|
||||
void *ras_error_status);
|
||||
int (*ras_late_init)(struct amdgpu_device *adev);
|
||||
void (*enable_aspm)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*program_aspm)(struct amdgpu_device *adev);
|
||||
|
@ -97,6 +101,7 @@ struct amdgpu_nbio {
|
|||
struct amdgpu_irq_src ras_err_event_athub_irq;
|
||||
struct ras_common_if *ras_if;
|
||||
const struct amdgpu_nbio_funcs *funcs;
|
||||
const struct amdgpu_nbio_ras_funcs *ras_funcs;
|
||||
};
|
||||
|
||||
int amdgpu_nbio_ras_late_init(struct amdgpu_device *adev);
|
||||
|
|
|
@ -77,6 +77,7 @@ 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);
|
||||
|
@ -94,7 +95,11 @@ static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo)
|
|||
}
|
||||
amdgpu_bo_unref(&bo->parent);
|
||||
|
||||
kfree(bo->metadata);
|
||||
if (bo->tbo.type == ttm_bo_type_device) {
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
kfree(ubo->metadata);
|
||||
}
|
||||
|
||||
kfree(bo);
|
||||
}
|
||||
|
||||
|
@ -248,6 +253,7 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
|
|||
bp.flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
if (!*bo_ptr) {
|
||||
r = amdgpu_bo_create(adev, &bp, bo_ptr);
|
||||
|
@ -523,7 +529,6 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
|
|||
};
|
||||
struct amdgpu_bo *bo;
|
||||
unsigned long page_align, size = bp->size;
|
||||
size_t acc_size;
|
||||
int r;
|
||||
|
||||
/* Note that GDS/GWS/OA allocates 1 page per byte/resource. */
|
||||
|
@ -544,12 +549,10 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
|
|||
if (!amdgpu_bo_validate_size(adev, size, bp->domain))
|
||||
return -ENOMEM;
|
||||
|
||||
BUG_ON(bp->bo_ptr_size < sizeof(struct amdgpu_bo));
|
||||
|
||||
*bo_ptr = NULL;
|
||||
|
||||
acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size,
|
||||
sizeof(struct amdgpu_bo));
|
||||
|
||||
bo = kzalloc(sizeof(struct amdgpu_bo), GFP_KERNEL);
|
||||
bo = kzalloc(bp->bo_ptr_size, GFP_KERNEL);
|
||||
if (bo == NULL)
|
||||
return -ENOMEM;
|
||||
drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size);
|
||||
|
@ -577,8 +580,8 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
|
|||
bo->tbo.priority = 1;
|
||||
|
||||
r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type,
|
||||
&bo->placement, page_align, &ctx, acc_size,
|
||||
NULL, bp->resv, &amdgpu_bo_destroy);
|
||||
&bo->placement, page_align, &ctx, NULL,
|
||||
bp->resv, &amdgpu_bo_destroy);
|
||||
if (unlikely(r != 0))
|
||||
return r;
|
||||
|
||||
|
@ -639,6 +642,7 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev,
|
|||
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) {
|
||||
|
@ -673,6 +677,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
|
|||
int r;
|
||||
|
||||
bp->flags = bp->flags & ~AMDGPU_GEM_CREATE_SHADOW;
|
||||
|
||||
r = amdgpu_bo_do_create(adev, bp, bo_ptr);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -694,6 +699,34 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
|
|||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_bo_create_user - create an &amdgpu_bo_user buffer object
|
||||
* @adev: amdgpu device object
|
||||
* @bp: parameters to be used for the buffer object
|
||||
* @ubo_ptr: pointer to the buffer object pointer
|
||||
*
|
||||
* Create a BO to be used by user application;
|
||||
*
|
||||
* Returns:
|
||||
* 0 for success or a negative error code on failure.
|
||||
*/
|
||||
|
||||
int amdgpu_bo_create_user(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_param *bp,
|
||||
struct amdgpu_bo_user **ubo_ptr)
|
||||
{
|
||||
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);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
*ubo_ptr = to_amdgpu_bo_user(bo_ptr);
|
||||
return r;
|
||||
}
|
||||
/**
|
||||
* amdgpu_bo_validate - validate an &amdgpu_bo buffer object
|
||||
* @bo: pointer to the buffer object
|
||||
|
@ -1062,13 +1095,17 @@ static const char *amdgpu_vram_names[] = {
|
|||
*/
|
||||
int amdgpu_bo_init(struct amdgpu_device *adev)
|
||||
{
|
||||
/* reserve PAT memory space to WC for VRAM */
|
||||
arch_io_reserve_memtype_wc(adev->gmc.aper_base,
|
||||
adev->gmc.aper_size);
|
||||
/* On A+A platform, VRAM can be mapped as WB */
|
||||
if (!adev->gmc.xgmi.connected_to_cpu) {
|
||||
/* reserve PAT memory space to WC for VRAM */
|
||||
arch_io_reserve_memtype_wc(adev->gmc.aper_base,
|
||||
adev->gmc.aper_size);
|
||||
|
||||
/* Add an MTRR for the VRAM */
|
||||
adev->gmc.vram_mtrr = arch_phys_wc_add(adev->gmc.aper_base,
|
||||
adev->gmc.aper_size);
|
||||
}
|
||||
|
||||
/* Add an MTRR for the VRAM */
|
||||
adev->gmc.vram_mtrr = arch_phys_wc_add(adev->gmc.aper_base,
|
||||
adev->gmc.aper_size);
|
||||
DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n",
|
||||
adev->gmc.mc_vram_size >> 20,
|
||||
(unsigned long long)adev->gmc.aper_size >> 20);
|
||||
|
@ -1086,27 +1123,10 @@ int amdgpu_bo_init(struct amdgpu_device *adev)
|
|||
void amdgpu_bo_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
amdgpu_ttm_fini(adev);
|
||||
arch_phys_wc_del(adev->gmc.vram_mtrr);
|
||||
arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_bo_fbdev_mmap - mmap fbdev memory
|
||||
* @bo: &amdgpu_bo buffer object
|
||||
* @vma: vma as input from the fbdev mmap method
|
||||
*
|
||||
* Calls ttm_fbdev_mmap() to mmap fbdev memory if it is backed by a bo.
|
||||
*
|
||||
* Returns:
|
||||
* 0 for success or a negative error code on failure.
|
||||
*/
|
||||
int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
if (vma->vm_pgoff != 0)
|
||||
return -EACCES;
|
||||
|
||||
return ttm_bo_mmap_obj(vma, &bo->tbo);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1123,12 +1143,15 @@ int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
|
|||
int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
|
||||
struct amdgpu_bo_user *ubo;
|
||||
|
||||
BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
|
||||
if (adev->family <= AMDGPU_FAMILY_CZ &&
|
||||
AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6)
|
||||
return -EINVAL;
|
||||
|
||||
bo->tiling_flags = tiling_flags;
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
ubo->tiling_flags = tiling_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1142,10 +1165,14 @@ int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
|
|||
*/
|
||||
void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
|
||||
{
|
||||
struct amdgpu_bo_user *ubo;
|
||||
|
||||
BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
|
||||
dma_resv_assert_held(bo->tbo.base.resv);
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
|
||||
if (tiling_flags)
|
||||
*tiling_flags = bo->tiling_flags;
|
||||
*tiling_flags = ubo->tiling_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1164,13 +1191,16 @@ void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
|
|||
int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
|
||||
uint32_t metadata_size, uint64_t flags)
|
||||
{
|
||||
struct amdgpu_bo_user *ubo;
|
||||
void *buffer;
|
||||
|
||||
BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
if (!metadata_size) {
|
||||
if (bo->metadata_size) {
|
||||
kfree(bo->metadata);
|
||||
bo->metadata = NULL;
|
||||
bo->metadata_size = 0;
|
||||
if (ubo->metadata_size) {
|
||||
kfree(ubo->metadata);
|
||||
ubo->metadata = NULL;
|
||||
ubo->metadata_size = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1182,10 +1212,10 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
|
|||
if (buffer == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
kfree(bo->metadata);
|
||||
bo->metadata_flags = flags;
|
||||
bo->metadata = buffer;
|
||||
bo->metadata_size = metadata_size;
|
||||
kfree(ubo->metadata);
|
||||
ubo->metadata_flags = flags;
|
||||
ubo->metadata = buffer;
|
||||
ubo->metadata_size = metadata_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1209,21 +1239,25 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
|
|||
size_t buffer_size, uint32_t *metadata_size,
|
||||
uint64_t *flags)
|
||||
{
|
||||
struct amdgpu_bo_user *ubo;
|
||||
|
||||
if (!buffer && !metadata_size)
|
||||
return -EINVAL;
|
||||
|
||||
BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
|
||||
ubo = to_amdgpu_bo_user(bo);
|
||||
if (buffer) {
|
||||
if (buffer_size < bo->metadata_size)
|
||||
if (buffer_size < ubo->metadata_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (bo->metadata_size)
|
||||
memcpy(buffer, bo->metadata, bo->metadata_size);
|
||||
if (ubo->metadata_size)
|
||||
memcpy(buffer, ubo->metadata, ubo->metadata_size);
|
||||
}
|
||||
|
||||
if (metadata_size)
|
||||
*metadata_size = bo->metadata_size;
|
||||
*metadata_size = ubo->metadata_size;
|
||||
if (flags)
|
||||
*flags = bo->metadata_flags;
|
||||
*flags = ubo->metadata_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -37,9 +37,12 @@
|
|||
#define AMDGPU_BO_INVALID_OFFSET LONG_MAX
|
||||
#define AMDGPU_BO_MAX_PLACEMENTS 3
|
||||
|
||||
#define to_amdgpu_bo_user(abo) container_of((abo), struct amdgpu_bo_user, bo)
|
||||
|
||||
struct amdgpu_bo_param {
|
||||
unsigned long size;
|
||||
int byte_align;
|
||||
u32 bo_ptr_size;
|
||||
u32 domain;
|
||||
u32 preferred_domain;
|
||||
u64 flags;
|
||||
|
@ -89,10 +92,6 @@ struct amdgpu_bo {
|
|||
struct ttm_buffer_object tbo;
|
||||
struct ttm_bo_kmap_obj kmap;
|
||||
u64 flags;
|
||||
u64 tiling_flags;
|
||||
u64 metadata_flags;
|
||||
void *metadata;
|
||||
u32 metadata_size;
|
||||
unsigned prime_shared_count;
|
||||
/* per VM structure for page tables and with virtual addresses */
|
||||
struct amdgpu_vm_bo_base *vm_bo;
|
||||
|
@ -100,7 +99,6 @@ struct amdgpu_bo {
|
|||
struct amdgpu_bo *parent;
|
||||
struct amdgpu_bo *shadow;
|
||||
|
||||
struct amdgpu_mn *mn;
|
||||
|
||||
|
||||
#ifdef CONFIG_MMU_NOTIFIER
|
||||
|
@ -112,6 +110,15 @@ struct amdgpu_bo {
|
|||
struct kgd_mem *kfd_bo;
|
||||
};
|
||||
|
||||
struct amdgpu_bo_user {
|
||||
struct amdgpu_bo bo;
|
||||
u64 tiling_flags;
|
||||
u64 metadata_flags;
|
||||
void *metadata;
|
||||
u32 metadata_size;
|
||||
|
||||
};
|
||||
|
||||
static inline struct amdgpu_bo *ttm_to_amdgpu_bo(struct ttm_buffer_object *tbo)
|
||||
{
|
||||
return container_of(tbo, struct amdgpu_bo, tbo);
|
||||
|
@ -255,6 +262,9 @@ int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
|
|||
int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
|
||||
uint64_t offset, uint64_t size, uint32_t domain,
|
||||
struct amdgpu_bo **bo_ptr, void **cpu_addr);
|
||||
int amdgpu_bo_create_user(struct amdgpu_device *adev,
|
||||
struct amdgpu_bo_param *bp,
|
||||
struct amdgpu_bo_user **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);
|
||||
|
@ -269,8 +279,6 @@ void amdgpu_bo_unpin(struct amdgpu_bo *bo);
|
|||
int amdgpu_bo_evict_vram(struct amdgpu_device *adev);
|
||||
int amdgpu_bo_init(struct amdgpu_device *adev);
|
||||
void amdgpu_bo_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo,
|
||||
struct vm_area_struct *vma);
|
||||
int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags);
|
||||
void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags);
|
||||
int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
|
||||
|
@ -329,7 +337,7 @@ void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager,
|
|||
struct seq_file *m);
|
||||
u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m);
|
||||
#endif
|
||||
int amdgpu_debugfs_sa_init(struct amdgpu_device *adev);
|
||||
void amdgpu_debugfs_sa_init(struct amdgpu_device *adev);
|
||||
|
||||
bool amdgpu_bo_support_uswc(u64 bo_flags);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "psp_v10_0.h"
|
||||
#include "psp_v11_0.h"
|
||||
#include "psp_v12_0.h"
|
||||
#include "psp_v13_0.h"
|
||||
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_securedisplay.h"
|
||||
|
@ -56,7 +57,7 @@ static int psp_load_smu_fw(struct psp_context *psp);
|
|||
* - Load XGMI/RAS/HDCP/DTM TA if any
|
||||
*
|
||||
* This new sequence is required for
|
||||
* - Arcturus
|
||||
* - Arcturus and onwards
|
||||
* - Navi12 and onwards
|
||||
*/
|
||||
static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp)
|
||||
|
@ -71,7 +72,7 @@ static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp
|
|||
if (adev->flags & AMD_IS_APU)
|
||||
return;
|
||||
|
||||
if ((adev->asic_type == CHIP_ARCTURUS) ||
|
||||
if ((adev->asic_type >= CHIP_ARCTURUS) ||
|
||||
(adev->asic_type >= CHIP_NAVI12))
|
||||
psp->pmfw_centralized_cstate_management = true;
|
||||
}
|
||||
|
@ -109,6 +110,9 @@ static int psp_early_init(void *handle)
|
|||
case CHIP_RENOIR:
|
||||
psp_v12_0_set_psp_funcs(psp);
|
||||
break;
|
||||
case CHIP_ALDEBARAN:
|
||||
psp_v13_0_set_psp_funcs(psp);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -383,7 +387,7 @@ static int psp_tmr_init(struct psp_context *psp)
|
|||
* Note: this memory need be reserved till the driver
|
||||
* uninitializes.
|
||||
*/
|
||||
tmr_size = PSP_TMR_SIZE;
|
||||
tmr_size = PSP_TMR_SIZE(psp->adev);
|
||||
|
||||
/* For ASICs support RLC autoload, psp will parse the toc
|
||||
* and calculate the total size of TMR needed */
|
||||
|
@ -399,10 +403,20 @@ static int psp_tmr_init(struct psp_context *psp)
|
|||
}
|
||||
|
||||
pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
|
||||
ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_SIZE,
|
||||
ret = amdgpu_bo_create_kernel(psp->adev, tmr_size, PSP_TMR_SIZE(psp->adev),
|
||||
AMDGPU_GEM_DOMAIN_VRAM,
|
||||
&psp->tmr_bo, &psp->tmr_mc_addr, pptr);
|
||||
|
||||
/* workaround the tmr_mc_addr:
|
||||
* PSP requires an address in FB aperture. Right now driver produce
|
||||
* tmr_mc_addr in the GART aperture. Convert it back to FB aperture
|
||||
* for PSP. Will revert it after we get a fix from PSP FW.
|
||||
*/
|
||||
if (psp->adev->asic_type == CHIP_ALDEBARAN) {
|
||||
psp->tmr_mc_addr -= psp->adev->gmc.fb_start;
|
||||
psp->tmr_mc_addr += psp->adev->gmc.fb_start_original;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -542,6 +556,46 @@ int psp_get_fw_attestation_records_addr(struct psp_context *psp,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int psp_boot_config_set(struct amdgpu_device *adev)
|
||||
{
|
||||
struct psp_context *psp = &adev->psp;
|
||||
struct psp_gfx_cmd_resp *cmd = psp->cmd;
|
||||
|
||||
if (adev->asic_type != CHIP_SIENNA_CICHLID)
|
||||
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;
|
||||
|
||||
return psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
|
||||
}
|
||||
|
||||
static int psp_rl_load(struct amdgpu_device *adev)
|
||||
{
|
||||
struct psp_context *psp = &adev->psp;
|
||||
struct psp_gfx_cmd_resp *cmd = psp->cmd;
|
||||
|
||||
if (psp->rl_bin_size == 0)
|
||||
return 0;
|
||||
|
||||
memset(psp->fw_pri_buf, 0, PSP_1_MEG);
|
||||
memcpy(psp->fw_pri_buf, psp->rl_start_addr, psp->rl_bin_size);
|
||||
|
||||
memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp));
|
||||
|
||||
cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
|
||||
cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(psp->fw_pri_mc_addr);
|
||||
cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(psp->fw_pri_mc_addr);
|
||||
cmd->cmd.cmd_load_ip_fw.fw_size = psp->rl_bin_size;
|
||||
cmd->cmd.cmd_load_ip_fw.fw_type = GFX_FW_TYPE_REG_LIST;
|
||||
|
||||
return psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
|
||||
}
|
||||
|
||||
static void psp_prep_asd_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
|
||||
uint64_t asd_mc, uint32_t size)
|
||||
{
|
||||
|
@ -755,8 +809,9 @@ static int psp_xgmi_unload(struct psp_context *psp)
|
|||
struct psp_gfx_cmd_resp *cmd;
|
||||
struct amdgpu_device *adev = psp->adev;
|
||||
|
||||
/* XGMI TA unload currently is not supported on Arcturus */
|
||||
if (adev->asic_type == CHIP_ARCTURUS)
|
||||
/* XGMI TA unload currently is not supported on Arcturus/Aldebaran A+A */
|
||||
if (adev->asic_type == CHIP_ARCTURUS ||
|
||||
(adev->asic_type == CHIP_ALDEBARAN && adev->gmc.xgmi.connected_to_cpu))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -1561,6 +1616,7 @@ static int psp_rap_unload(struct psp_context *psp)
|
|||
static int psp_rap_initialize(struct psp_context *psp)
|
||||
{
|
||||
int ret;
|
||||
enum ta_rap_status status = TA_RAP_STATUS__SUCCESS;
|
||||
|
||||
/*
|
||||
* TODO: bypass the initialize in sriov for now
|
||||
|
@ -1584,8 +1640,8 @@ static int psp_rap_initialize(struct psp_context *psp)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE);
|
||||
if (ret != TA_RAP_STATUS__SUCCESS) {
|
||||
ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE, &status);
|
||||
if (ret || status != TA_RAP_STATUS__SUCCESS) {
|
||||
psp_rap_unload(psp);
|
||||
|
||||
amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo,
|
||||
|
@ -1594,8 +1650,10 @@ static int psp_rap_initialize(struct psp_context *psp)
|
|||
|
||||
psp->rap_context.rap_initialized = false;
|
||||
|
||||
dev_warn(psp->adev->dev, "RAP TA initialize fail.\n");
|
||||
return -EINVAL;
|
||||
dev_warn(psp->adev->dev, "RAP TA initialize fail (%d) status %d.\n",
|
||||
ret, status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1620,13 +1678,13 @@ static int psp_rap_terminate(struct psp_context *psp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
|
||||
int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id, enum ta_rap_status *status)
|
||||
{
|
||||
struct ta_rap_shared_memory *rap_cmd;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (!psp->rap_context.rap_initialized)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
||||
if (ta_cmd_id != TA_CMD_RAP__INITIALIZE &&
|
||||
ta_cmd_id != TA_CMD_RAP__VALIDATE_L0)
|
||||
|
@ -1642,14 +1700,16 @@ int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
|
|||
rap_cmd->validation_method_id = METHOD_A;
|
||||
|
||||
ret = psp_ta_invoke(psp, rap_cmd->cmd_id, psp->rap_context.session_id);
|
||||
if (ret) {
|
||||
mutex_unlock(&psp->rap_context.mutex);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
if (status)
|
||||
*status = rap_cmd->rap_status;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&psp->rap_context.mutex);
|
||||
|
||||
return rap_cmd->rap_status;
|
||||
return ret;
|
||||
}
|
||||
// RAP end
|
||||
|
||||
|
@ -1870,6 +1930,11 @@ static int psp_hw_start(struct psp_context *psp)
|
|||
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");
|
||||
|
@ -2104,9 +2169,13 @@ static int psp_load_smu_fw(struct psp_context *psp)
|
|||
if (!ucode->fw || amdgpu_sriov_vf(psp->adev))
|
||||
return 0;
|
||||
|
||||
|
||||
if (amdgpu_in_reset(adev) && ras && ras->supported &&
|
||||
adev->asic_type == CHIP_ARCTURUS) {
|
||||
if ((amdgpu_in_reset(adev) &&
|
||||
ras && ras->supported &&
|
||||
(adev->asic_type == CHIP_ARCTURUS ||
|
||||
adev->asic_type == CHIP_VEGA20)) ||
|
||||
(adev->in_runpm &&
|
||||
adev->asic_type >= CHIP_NAVI10 &&
|
||||
adev->asic_type <= CHIP_NAVI12)) {
|
||||
ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD);
|
||||
if (ret) {
|
||||
DRM_WARN("Failed to set MP1 state prepare for reload\n");
|
||||
|
@ -2159,6 +2228,22 @@ static bool fw_load_skip_check(struct psp_context *psp,
|
|||
return false;
|
||||
}
|
||||
|
||||
int psp_load_fw_list(struct psp_context *psp,
|
||||
struct amdgpu_firmware_info **ucode_list, int ucode_count)
|
||||
{
|
||||
int ret = 0, i;
|
||||
struct amdgpu_firmware_info *ucode;
|
||||
|
||||
for (i = 0; i < ucode_count; ++i) {
|
||||
ucode = ucode_list[i];
|
||||
psp_print_fw_hdr(psp, ucode);
|
||||
ret = psp_execute_np_fw_load(psp, ucode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int psp_np_fw_load(struct psp_context *psp)
|
||||
{
|
||||
int i, ret;
|
||||
|
@ -2276,6 +2361,12 @@ skip_memalloc:
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = psp_rl_load(adev);
|
||||
if (ret) {
|
||||
DRM_ERROR("PSP load RL failed!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (psp->adev->psp.ta_fw) {
|
||||
ret = psp_ras_initialize(psp);
|
||||
if (ret)
|
||||
|
@ -2751,6 +2842,9 @@ int psp_init_sos_microcode(struct psp_context *psp,
|
|||
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);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -2916,7 +3010,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%x\n", fw_ver);
|
||||
return sysfs_emit(buf, "%x\n", fw_ver);
|
||||
}
|
||||
|
||||
static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
|
||||
|
@ -3052,3 +3146,11 @@ const struct amdgpu_ip_block_version psp_v12_0_ip_block =
|
|||
.rev = 0,
|
||||
.funcs = &psp_ip_funcs,
|
||||
};
|
||||
|
||||
const struct amdgpu_ip_block_version psp_v13_0_ip_block = {
|
||||
.type = AMD_IP_BLOCK_TYPE_PSP,
|
||||
.major = 13,
|
||||
.minor = 0,
|
||||
.rev = 0,
|
||||
.funcs = &psp_ip_funcs,
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#define PSP_XGMI_SHARED_MEM_SIZE 0x4000
|
||||
#define PSP_RAS_SHARED_MEM_SIZE 0x4000
|
||||
#define PSP_1_MEG 0x100000
|
||||
#define PSP_TMR_SIZE 0x400000
|
||||
#define PSP_TMR_SIZE(adev) ((adev)->asic_type == CHIP_ALDEBARAN ? 0x800000 : 0x400000)
|
||||
#define PSP_HDCP_SHARED_MEM_SIZE 0x4000
|
||||
#define PSP_DTM_SHARED_MEM_SIZE 0x4000
|
||||
#define PSP_RAP_SHARED_MEM_SIZE 0x4000
|
||||
|
@ -248,11 +248,13 @@ struct psp_context
|
|||
uint32_t toc_bin_size;
|
||||
uint32_t kdb_bin_size;
|
||||
uint32_t spl_bin_size;
|
||||
uint32_t rl_bin_size;
|
||||
uint8_t *sys_start_addr;
|
||||
uint8_t *sos_start_addr;
|
||||
uint8_t *toc_start_addr;
|
||||
uint8_t *kdb_start_addr;
|
||||
uint8_t *spl_start_addr;
|
||||
uint8_t *rl_start_addr;
|
||||
|
||||
/* tmr buffer */
|
||||
struct amdgpu_bo *tmr_bo;
|
||||
|
@ -365,12 +367,14 @@ struct amdgpu_psp_funcs {
|
|||
extern const struct amd_ip_funcs psp_ip_funcs;
|
||||
|
||||
extern const struct amdgpu_ip_block_version psp_v3_1_ip_block;
|
||||
extern const struct amdgpu_ip_block_version psp_v10_0_ip_block;
|
||||
extern const struct amdgpu_ip_block_version psp_v11_0_ip_block;
|
||||
extern const struct amdgpu_ip_block_version psp_v12_0_ip_block;
|
||||
extern const struct amdgpu_ip_block_version psp_v13_0_ip_block;
|
||||
|
||||
extern int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
|
||||
uint32_t field_val, uint32_t mask, bool check_changed);
|
||||
|
||||
extern const struct amdgpu_ip_block_version psp_v10_0_ip_block;
|
||||
extern const struct amdgpu_ip_block_version psp_v12_0_ip_block;
|
||||
|
||||
int psp_gpu_reset(struct amdgpu_device *adev);
|
||||
int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx,
|
||||
uint64_t cmd_gpu_addr, int cmd_size);
|
||||
|
@ -395,12 +399,11 @@ int psp_ras_trigger_error(struct psp_context *psp,
|
|||
|
||||
int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
|
||||
int psp_dtm_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
|
||||
int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
|
||||
int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id, enum ta_rap_status *status);
|
||||
int psp_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
|
||||
|
||||
int psp_rlc_autoload_start(struct psp_context *psp);
|
||||
|
||||
extern const struct amdgpu_ip_block_version psp_v11_0_ip_block;
|
||||
int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg,
|
||||
uint32_t value);
|
||||
int psp_ring_cmd_submit(struct psp_context *psp,
|
||||
|
@ -417,4 +420,7 @@ int psp_init_ta_microcode(struct psp_context *psp,
|
|||
const char *chip_name);
|
||||
int psp_get_fw_attestation_records_addr(struct psp_context *psp,
|
||||
uint64_t *output_ptr);
|
||||
|
||||
int psp_load_fw_list(struct psp_context *psp,
|
||||
struct amdgpu_firmware_info **ucode_list, int ucode_count);
|
||||
#endif
|
||||
|
|
|
@ -48,6 +48,7 @@ static ssize_t amdgpu_rap_debugfs_write(struct file *f, const char __user *buf,
|
|||
struct ta_rap_cmd_output_data *rap_cmd_output;
|
||||
struct drm_device *dev = adev_to_drm(adev);
|
||||
uint32_t op;
|
||||
enum ta_rap_status status;
|
||||
int ret;
|
||||
|
||||
if (*pos || size != 2)
|
||||
|
@ -70,9 +71,8 @@ static ssize_t amdgpu_rap_debugfs_write(struct file *f, const char __user *buf,
|
|||
|
||||
switch (op) {
|
||||
case 2:
|
||||
ret = psp_rap_invoke(&adev->psp, op);
|
||||
|
||||
if (ret == TA_RAP_STATUS__SUCCESS) {
|
||||
ret = psp_rap_invoke(&adev->psp, op, &status);
|
||||
if (!ret && status == TA_RAP_STATUS__SUCCESS) {
|
||||
dev_info(adev->dev, "RAP L0 validate test success.\n");
|
||||
} else {
|
||||
rap_shared_mem = (struct ta_rap_shared_memory *)
|
||||
|
@ -97,6 +97,7 @@ static ssize_t amdgpu_rap_debugfs_write(struct file *f, const char __user *buf,
|
|||
default:
|
||||
dev_info(adev->dev, "Unsupported op id: %d, ", op);
|
||||
dev_info(adev->dev, "Only support op 2(L0 validate test).\n");
|
||||
break;
|
||||
}
|
||||
|
||||
amdgpu_gfx_off_ctrl(adev, true);
|
||||
|
|
|
@ -99,6 +99,49 @@ static bool amdgpu_ras_get_error_query_ready(struct amdgpu_device *adev)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int amdgpu_reserve_page_direct(struct amdgpu_device *adev, uint64_t address)
|
||||
{
|
||||
struct ras_err_data err_data = {0, 0, 0, NULL};
|
||||
struct eeprom_table_record err_rec;
|
||||
|
||||
if ((address >= adev->gmc.mc_vram_size) ||
|
||||
(address >= RAS_UMC_INJECT_ADDR_LIMIT)) {
|
||||
dev_warn(adev->dev,
|
||||
"RAS WARN: input address 0x%llx is invalid.\n",
|
||||
address);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (amdgpu_ras_check_bad_page(adev, address)) {
|
||||
dev_warn(adev->dev,
|
||||
"RAS WARN: 0x%llx has been marked as bad page!\n",
|
||||
address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&err_rec, 0x0, sizeof(struct eeprom_table_record));
|
||||
|
||||
err_rec.address = address;
|
||||
err_rec.retired_page = address >> AMDGPU_GPU_PAGE_SHIFT;
|
||||
err_rec.ts = (uint64_t)ktime_get_real_seconds();
|
||||
err_rec.err_type = AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE;
|
||||
|
||||
err_data.err_addr = &err_rec;
|
||||
err_data.err_addr_cnt = 1;
|
||||
|
||||
if (amdgpu_bad_page_threshold != 0) {
|
||||
amdgpu_ras_add_bad_pages(adev, err_data.err_addr,
|
||||
err_data.err_addr_cnt);
|
||||
amdgpu_ras_save_bad_pages(adev);
|
||||
}
|
||||
|
||||
dev_warn(adev->dev, "WARNING: THIS IS ONLY FOR TEST PURPOSES AND WILL CORRUPT RAS EEPROM\n");
|
||||
dev_warn(adev->dev, "Clear EEPROM:\n");
|
||||
dev_warn(adev->dev, " echo 1 > /sys/kernel/debug/dri/0/ras/ras_eeprom_reset\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t amdgpu_ras_debugfs_read(struct file *f, char __user *buf,
|
||||
size_t size, loff_t *pos)
|
||||
{
|
||||
|
@ -109,7 +152,7 @@ static ssize_t amdgpu_ras_debugfs_read(struct file *f, char __user *buf,
|
|||
ssize_t s;
|
||||
char val[128];
|
||||
|
||||
if (amdgpu_ras_error_query(obj->adev, &info))
|
||||
if (amdgpu_ras_query_error_status(obj->adev, &info))
|
||||
return -EINVAL;
|
||||
|
||||
s = snprintf(val, sizeof(val), "%s: %lu\n%s: %lu\n",
|
||||
|
@ -178,11 +221,25 @@ static int amdgpu_ras_debugfs_ctrl_parse_data(struct file *f,
|
|||
op = 1;
|
||||
else if (sscanf(str, "inject %32s %8s", block_name, err) == 2)
|
||||
op = 2;
|
||||
else if (sscanf(str, "retire_page") == 0)
|
||||
op = 3;
|
||||
else if (str[0] && str[1] && str[2] && str[3])
|
||||
/* ascii string, but commands are not matched. */
|
||||
return -EINVAL;
|
||||
|
||||
if (op != -1) {
|
||||
|
||||
if (op == 3) {
|
||||
if (sscanf(str, "%*s %llu", &address) != 1)
|
||||
if (sscanf(str, "%*s 0x%llx", &address) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
data->op = op;
|
||||
data->inject.address = address;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (amdgpu_ras_find_block_id_by_name(block_name, &block_id))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -310,6 +367,16 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user *
|
|||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (data.op == 3)
|
||||
{
|
||||
ret = amdgpu_reserve_page_direct(adev, data.inject.address);
|
||||
|
||||
if (ret)
|
||||
return size;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!amdgpu_ras_is_supported(adev, data.head.block))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -431,15 +498,13 @@ static ssize_t amdgpu_ras_sysfs_read(struct device *dev,
|
|||
};
|
||||
|
||||
if (!amdgpu_ras_get_error_query_ready(obj->adev))
|
||||
return snprintf(buf, PAGE_SIZE,
|
||||
"Query currently inaccessible\n");
|
||||
return sysfs_emit(buf, "Query currently inaccessible\n");
|
||||
|
||||
if (amdgpu_ras_error_query(obj->adev, &info))
|
||||
if (amdgpu_ras_query_error_status(obj->adev, &info))
|
||||
return -EINVAL;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s: %lu\n%s: %lu\n",
|
||||
"ue", info.ue_count,
|
||||
"ce", info.ce_count);
|
||||
return sysfs_emit(buf, "%s: %lu\n%s: %lu\n", "ue", info.ue_count,
|
||||
"ce", info.ce_count);
|
||||
}
|
||||
|
||||
/* obj begin */
|
||||
|
@ -449,11 +514,10 @@ static ssize_t amdgpu_ras_sysfs_read(struct device *dev,
|
|||
|
||||
static inline void put_obj(struct ras_manager *obj)
|
||||
{
|
||||
if (obj && --obj->use == 0)
|
||||
if (obj && (--obj->use == 0))
|
||||
list_del(&obj->node);
|
||||
if (obj && obj->use < 0) {
|
||||
DRM_ERROR("RAS ERROR: Unbalance obj(%s) use\n", obj->head.name);
|
||||
}
|
||||
if (obj && (obj->use < 0))
|
||||
DRM_ERROR("RAS ERROR: Unbalance obj(%s) use\n", obj->head.name);
|
||||
}
|
||||
|
||||
/* make one obj and return it. */
|
||||
|
@ -463,7 +527,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 (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return NULL;
|
||||
|
||||
if (head->block >= AMDGPU_RAS_BLOCK_COUNT)
|
||||
|
@ -490,7 +554,7 @@ struct ras_manager *amdgpu_ras_find_obj(struct amdgpu_device *adev,
|
|||
struct ras_manager *obj;
|
||||
int i;
|
||||
|
||||
if (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return NULL;
|
||||
|
||||
if (head) {
|
||||
|
@ -590,7 +654,11 @@ 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)) {
|
||||
con->features &= ~BIT(head->block);
|
||||
/* 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);
|
||||
put_obj(obj);
|
||||
}
|
||||
}
|
||||
|
@ -693,6 +761,10 @@ int amdgpu_ras_feature_enable_on_boot(struct amdgpu_device *adev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* gfx block ras dsiable cmd must send to ras-ta */
|
||||
if (head->block == AMDGPU_RAS_BLOCK__GFX)
|
||||
con->features |= BIT(head->block);
|
||||
|
||||
ret = amdgpu_ras_feature_enable(adev, head, 0);
|
||||
}
|
||||
} else
|
||||
|
@ -757,8 +829,8 @@ static int amdgpu_ras_enable_all_features(struct amdgpu_device *adev,
|
|||
/* feature ctl end */
|
||||
|
||||
/* query/inject/cure begin */
|
||||
int amdgpu_ras_error_query(struct amdgpu_device *adev,
|
||||
struct ras_query_if *info)
|
||||
int amdgpu_ras_query_error_status(struct amdgpu_device *adev,
|
||||
struct ras_query_if *info)
|
||||
{
|
||||
struct ras_manager *obj = amdgpu_ras_find_obj(adev, &info->head);
|
||||
struct ras_err_data err_data = {0, 0, 0, NULL};
|
||||
|
@ -769,13 +841,15 @@ int amdgpu_ras_error_query(struct amdgpu_device *adev,
|
|||
|
||||
switch (info->head.block) {
|
||||
case AMDGPU_RAS_BLOCK__UMC:
|
||||
if (adev->umc.funcs->query_ras_error_count)
|
||||
adev->umc.funcs->query_ras_error_count(adev, &err_data);
|
||||
if (adev->umc.ras_funcs &&
|
||||
adev->umc.ras_funcs->query_ras_error_count)
|
||||
adev->umc.ras_funcs->query_ras_error_count(adev, &err_data);
|
||||
/* umc query_ras_error_address is also responsible for clearing
|
||||
* error status
|
||||
*/
|
||||
if (adev->umc.funcs->query_ras_error_address)
|
||||
adev->umc.funcs->query_ras_error_address(adev, &err_data);
|
||||
if (adev->umc.ras_funcs &&
|
||||
adev->umc.ras_funcs->query_ras_error_address)
|
||||
adev->umc.ras_funcs->query_ras_error_address(adev, &err_data);
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__SDMA:
|
||||
if (adev->sdma.funcs->query_ras_error_count) {
|
||||
|
@ -785,19 +859,32 @@ int amdgpu_ras_error_query(struct amdgpu_device *adev,
|
|||
}
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__GFX:
|
||||
if (adev->gfx.funcs->query_ras_error_count)
|
||||
adev->gfx.funcs->query_ras_error_count(adev, &err_data);
|
||||
if (adev->gfx.ras_funcs &&
|
||||
adev->gfx.ras_funcs->query_ras_error_count)
|
||||
adev->gfx.ras_funcs->query_ras_error_count(adev, &err_data);
|
||||
|
||||
if (adev->gfx.ras_funcs &&
|
||||
adev->gfx.ras_funcs->query_ras_error_status)
|
||||
adev->gfx.ras_funcs->query_ras_error_status(adev);
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__MMHUB:
|
||||
if (adev->mmhub.funcs->query_ras_error_count)
|
||||
adev->mmhub.funcs->query_ras_error_count(adev, &err_data);
|
||||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->query_ras_error_count)
|
||||
adev->mmhub.ras_funcs->query_ras_error_count(adev, &err_data);
|
||||
|
||||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->query_ras_error_status)
|
||||
adev->mmhub.ras_funcs->query_ras_error_status(adev);
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__PCIE_BIF:
|
||||
if (adev->nbio.funcs->query_ras_error_count)
|
||||
adev->nbio.funcs->query_ras_error_count(adev, &err_data);
|
||||
if (adev->nbio.ras_funcs &&
|
||||
adev->nbio.ras_funcs->query_ras_error_count)
|
||||
adev->nbio.ras_funcs->query_ras_error_count(adev, &err_data);
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__XGMI_WAFL:
|
||||
amdgpu_xgmi_query_ras_error_count(adev, &err_data);
|
||||
if (adev->gmc.xgmi.ras_funcs &&
|
||||
adev->gmc.xgmi.ras_funcs->query_ras_error_count)
|
||||
adev->gmc.xgmi.ras_funcs->query_ras_error_count(adev, &err_data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -826,6 +913,38 @@ int amdgpu_ras_error_query(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_ras_reset_error_status(struct amdgpu_device *adev,
|
||||
enum amdgpu_ras_block block)
|
||||
{
|
||||
if (!amdgpu_ras_is_supported(adev, block))
|
||||
return -EINVAL;
|
||||
|
||||
switch (block) {
|
||||
case AMDGPU_RAS_BLOCK__GFX:
|
||||
if (adev->gfx.ras_funcs &&
|
||||
adev->gfx.ras_funcs->reset_ras_error_count)
|
||||
adev->gfx.ras_funcs->reset_ras_error_count(adev);
|
||||
|
||||
if (adev->gfx.ras_funcs &&
|
||||
adev->gfx.ras_funcs->reset_ras_error_status)
|
||||
adev->gfx.ras_funcs->reset_ras_error_status(adev);
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__MMHUB:
|
||||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->reset_ras_error_count)
|
||||
adev->mmhub.ras_funcs->reset_ras_error_count(adev);
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__SDMA:
|
||||
if (adev->sdma.funcs->reset_ras_error_count)
|
||||
adev->sdma.funcs->reset_ras_error_count(adev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Trigger XGMI/WAFL error */
|
||||
static int amdgpu_ras_error_inject_xgmi(struct amdgpu_device *adev,
|
||||
struct ta_ras_trigger_error_input *block_info)
|
||||
|
@ -878,12 +997,14 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev,
|
|||
|
||||
switch (info->head.block) {
|
||||
case AMDGPU_RAS_BLOCK__GFX:
|
||||
if (adev->gfx.funcs->ras_error_inject)
|
||||
ret = adev->gfx.funcs->ras_error_inject(adev, info);
|
||||
if (adev->gfx.ras_funcs &&
|
||||
adev->gfx.ras_funcs->ras_error_inject)
|
||||
ret = adev->gfx.ras_funcs->ras_error_inject(adev, info);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__UMC:
|
||||
case AMDGPU_RAS_BLOCK__SDMA:
|
||||
case AMDGPU_RAS_BLOCK__MMHUB:
|
||||
case AMDGPU_RAS_BLOCK__PCIE_BIF:
|
||||
ret = psp_ras_trigger_error(&adev->psp, &block_info);
|
||||
|
@ -913,7 +1034,7 @@ unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev,
|
|||
struct ras_manager *obj;
|
||||
struct ras_err_data data = {0, 0};
|
||||
|
||||
if (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(obj, &con->head, node) {
|
||||
|
@ -921,7 +1042,7 @@ unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev,
|
|||
.head = obj->head,
|
||||
};
|
||||
|
||||
if (amdgpu_ras_error_query(adev, &info))
|
||||
if (amdgpu_ras_query_error_status(adev, &info))
|
||||
return 0;
|
||||
|
||||
data.ce_count += info.ce_count;
|
||||
|
@ -1137,16 +1258,17 @@ static int amdgpu_ras_sysfs_remove_all(struct amdgpu_device *adev)
|
|||
*
|
||||
*/
|
||||
/* debugfs begin */
|
||||
static void amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev)
|
||||
static struct dentry *amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct dentry *dir;
|
||||
struct drm_minor *minor = adev_to_drm(adev)->primary;
|
||||
|
||||
con->dir = debugfs_create_dir(RAS_FS_NAME, minor->debugfs_root);
|
||||
debugfs_create_file("ras_ctrl", S_IWUGO | S_IRUGO, con->dir,
|
||||
adev, &amdgpu_ras_debugfs_ctrl_ops);
|
||||
debugfs_create_file("ras_eeprom_reset", S_IWUGO | S_IRUGO, con->dir,
|
||||
adev, &amdgpu_ras_debugfs_eeprom_ops);
|
||||
dir = debugfs_create_dir(RAS_FS_NAME, minor->debugfs_root);
|
||||
debugfs_create_file("ras_ctrl", S_IWUGO | S_IRUGO, dir, adev,
|
||||
&amdgpu_ras_debugfs_ctrl_ops);
|
||||
debugfs_create_file("ras_eeprom_reset", S_IWUGO | S_IRUGO, dir, adev,
|
||||
&amdgpu_ras_debugfs_eeprom_ops);
|
||||
|
||||
/*
|
||||
* After one uncorrectable error happens, usually GPU recovery will
|
||||
|
@ -1156,24 +1278,24 @@ static void amdgpu_ras_debugfs_create_ctrl_node(struct amdgpu_device *adev)
|
|||
* ERREVENT_ATHUB_INTERRUPT generated. Normal GPU recovery routine
|
||||
* will never be called.
|
||||
*/
|
||||
debugfs_create_bool("auto_reboot", S_IWUGO | S_IRUGO, con->dir,
|
||||
&con->reboot);
|
||||
debugfs_create_bool("auto_reboot", S_IWUGO | S_IRUGO, dir, &con->reboot);
|
||||
|
||||
/*
|
||||
* User could set this not to clean up hardware's error count register
|
||||
* of RAS IPs during ras recovery.
|
||||
*/
|
||||
debugfs_create_bool("disable_ras_err_cnt_harvest", 0644,
|
||||
con->dir, &con->disable_ras_err_cnt_harvest);
|
||||
debugfs_create_bool("disable_ras_err_cnt_harvest", 0644, dir,
|
||||
&con->disable_ras_err_cnt_harvest);
|
||||
return dir;
|
||||
}
|
||||
|
||||
static void amdgpu_ras_debugfs_create(struct amdgpu_device *adev,
|
||||
struct ras_fs_if *head)
|
||||
struct ras_fs_if *head,
|
||||
struct dentry *dir)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head->head);
|
||||
|
||||
if (!obj || obj->ent)
|
||||
if (!obj || !dir)
|
||||
return;
|
||||
|
||||
get_obj(obj);
|
||||
|
@ -1182,14 +1304,14 @@ static void amdgpu_ras_debugfs_create(struct amdgpu_device *adev,
|
|||
head->debugfs_name,
|
||||
sizeof(obj->fs_data.debugfs_name));
|
||||
|
||||
obj->ent = debugfs_create_file(obj->fs_data.debugfs_name,
|
||||
S_IWUGO | S_IRUGO, con->dir, obj,
|
||||
&amdgpu_ras_debugfs_ops);
|
||||
debugfs_create_file(obj->fs_data.debugfs_name, S_IWUGO | S_IRUGO, dir,
|
||||
obj, &amdgpu_ras_debugfs_ops);
|
||||
}
|
||||
|
||||
void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct dentry *dir;
|
||||
struct ras_manager *obj;
|
||||
struct ras_fs_if fs_info;
|
||||
|
||||
|
@ -1200,7 +1322,7 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev)
|
|||
if (!IS_ENABLED(CONFIG_DEBUG_FS) || !con)
|
||||
return;
|
||||
|
||||
amdgpu_ras_debugfs_create_ctrl_node(adev);
|
||||
dir = amdgpu_ras_debugfs_create_ctrl_node(adev);
|
||||
|
||||
list_for_each_entry(obj, &con->head, node) {
|
||||
if (amdgpu_ras_is_supported(adev, obj->head.block) &&
|
||||
|
@ -1208,34 +1330,11 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev)
|
|||
sprintf(fs_info.debugfs_name, "%s_err_inject",
|
||||
ras_block_str(obj->head.block));
|
||||
fs_info.head = obj->head;
|
||||
amdgpu_ras_debugfs_create(adev, &fs_info);
|
||||
amdgpu_ras_debugfs_create(adev, &fs_info, dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_ras_debugfs_remove(struct amdgpu_device *adev,
|
||||
struct ras_common_if *head)
|
||||
{
|
||||
struct ras_manager *obj = amdgpu_ras_find_obj(adev, head);
|
||||
|
||||
if (!obj || !obj->ent)
|
||||
return;
|
||||
|
||||
obj->ent = NULL;
|
||||
put_obj(obj);
|
||||
}
|
||||
|
||||
static void amdgpu_ras_debugfs_remove_all(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct ras_manager *obj, *tmp;
|
||||
|
||||
list_for_each_entry_safe(obj, tmp, &con->head, node) {
|
||||
amdgpu_ras_debugfs_remove(adev, &obj->head);
|
||||
}
|
||||
|
||||
con->dir = NULL;
|
||||
}
|
||||
/* debugfs end */
|
||||
|
||||
/* ras fs */
|
||||
|
@ -1282,8 +1381,17 @@ static int amdgpu_ras_fs_init(struct amdgpu_device *adev)
|
|||
|
||||
static int amdgpu_ras_fs_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS))
|
||||
amdgpu_ras_debugfs_remove_all(adev);
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct ras_manager *con_obj, *ip_obj, *tmp;
|
||||
|
||||
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
|
||||
list_for_each_entry_safe(con_obj, tmp, &con->head, node) {
|
||||
ip_obj = amdgpu_ras_find_obj(adev, &con_obj->head);
|
||||
if (ip_obj)
|
||||
put_obj(ip_obj);
|
||||
}
|
||||
}
|
||||
|
||||
amdgpu_ras_sysfs_remove_all(adev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1447,7 +1555,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 (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return;
|
||||
|
||||
list_for_each_entry(obj, &con->head, node) {
|
||||
|
@ -1464,7 +1572,7 @@ static void amdgpu_ras_log_on_err_counter(struct amdgpu_device *adev)
|
|||
if (info.head.block == AMDGPU_RAS_BLOCK__PCIE_BIF)
|
||||
continue;
|
||||
|
||||
amdgpu_ras_error_query(adev, &info);
|
||||
amdgpu_ras_query_error_status(adev, &info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1478,12 +1586,14 @@ static void amdgpu_ras_error_status_query(struct amdgpu_device *adev,
|
|||
*/
|
||||
switch (info->head.block) {
|
||||
case AMDGPU_RAS_BLOCK__GFX:
|
||||
if (adev->gfx.funcs->query_ras_error_status)
|
||||
adev->gfx.funcs->query_ras_error_status(adev);
|
||||
if (adev->gfx.ras_funcs &&
|
||||
adev->gfx.ras_funcs->query_ras_error_status)
|
||||
adev->gfx.ras_funcs->query_ras_error_status(adev);
|
||||
break;
|
||||
case AMDGPU_RAS_BLOCK__MMHUB:
|
||||
if (adev->mmhub.funcs->query_ras_error_status)
|
||||
adev->mmhub.funcs->query_ras_error_status(adev);
|
||||
if (adev->mmhub.ras_funcs &&
|
||||
adev->mmhub.ras_funcs->query_ras_error_status)
|
||||
adev->mmhub.ras_funcs->query_ras_error_status(adev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1495,7 +1605,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 (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return;
|
||||
|
||||
list_for_each_entry(obj, &con->head, node) {
|
||||
|
@ -1809,7 +1919,7 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev)
|
|||
bool exc_err_limit = false;
|
||||
int ret;
|
||||
|
||||
if (con)
|
||||
if (adev->ras_features && con)
|
||||
data = &con->eh_data;
|
||||
else
|
||||
return 0;
|
||||
|
@ -1828,6 +1938,12 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev)
|
|||
max_eeprom_records_len = amdgpu_ras_eeprom_get_record_max_length();
|
||||
amdgpu_ras_validate_threshold(adev, max_eeprom_records_len);
|
||||
|
||||
/* Todo: During test the SMU might fail to read the eeprom through I2C
|
||||
* when the GPU is pending on XGMI reset during probe time
|
||||
* (Mostly after second bus reset), skip it now
|
||||
*/
|
||||
if (adev->gmc.xgmi.pending_reset)
|
||||
return 0;
|
||||
ret = amdgpu_ras_eeprom_init(&con->eeprom_control, &exc_err_limit);
|
||||
/*
|
||||
* This calling fails when exc_err_limit is true or
|
||||
|
@ -1897,15 +2013,13 @@ int amdgpu_ras_request_reset_on_boot(struct amdgpu_device *adev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_ras_check_asic_type(struct amdgpu_device *adev)
|
||||
static bool amdgpu_ras_asic_supported(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->asic_type != CHIP_VEGA10 &&
|
||||
adev->asic_type != CHIP_VEGA20 &&
|
||||
adev->asic_type != CHIP_ARCTURUS &&
|
||||
adev->asic_type != CHIP_SIENNA_CICHLID)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return adev->asic_type == CHIP_VEGA10 ||
|
||||
adev->asic_type == CHIP_VEGA20 ||
|
||||
adev->asic_type == CHIP_ARCTURUS ||
|
||||
adev->asic_type == CHIP_ALDEBARAN ||
|
||||
adev->asic_type == CHIP_SIENNA_CICHLID;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1924,22 +2038,32 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev,
|
|||
*supported = 0;
|
||||
|
||||
if (amdgpu_sriov_vf(adev) || !adev->is_atom_fw ||
|
||||
amdgpu_ras_check_asic_type(adev))
|
||||
!amdgpu_ras_asic_supported(adev))
|
||||
return;
|
||||
|
||||
if (amdgpu_atomfirmware_mem_ecc_supported(adev)) {
|
||||
dev_info(adev->dev, "HBM ECC is active.\n");
|
||||
*hw_supported |= (1 << AMDGPU_RAS_BLOCK__UMC |
|
||||
1 << AMDGPU_RAS_BLOCK__DF);
|
||||
} else
|
||||
dev_info(adev->dev, "HBM ECC is not presented.\n");
|
||||
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);
|
||||
} 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);
|
||||
} else
|
||||
dev_info(adev->dev, "SRAM 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);
|
||||
} 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);
|
||||
}
|
||||
|
||||
/* hw_supported needs to be aligned with RAS block mask. */
|
||||
*hw_supported &= AMDGPU_RAS_BLOCK_MASK;
|
||||
|
@ -1970,6 +2094,15 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
|
|||
amdgpu_ras_check_supported(adev, &con->hw_supported,
|
||||
&con->supported);
|
||||
if (!con->hw_supported || (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) {
|
||||
con->features |= BIT(AMDGPU_RAS_BLOCK__GFX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
goto release_con;
|
||||
}
|
||||
|
@ -1979,14 +2112,31 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
|
|||
/* Might need get this flag from vbios. */
|
||||
con->flags = RAS_DEFAULT_FLAGS;
|
||||
|
||||
if (adev->nbio.funcs->init_ras_controller_interrupt) {
|
||||
r = adev->nbio.funcs->init_ras_controller_interrupt(adev);
|
||||
/* initialize nbio ras function ahead of any other
|
||||
* ras functions so hardware fatal error interrupt
|
||||
* can be enabled as early as possible */
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_VEGA20:
|
||||
case CHIP_ARCTURUS:
|
||||
case CHIP_ALDEBARAN:
|
||||
if (!adev->gmc.xgmi.connected_to_cpu)
|
||||
adev->nbio.ras_funcs = &nbio_v7_4_ras_funcs;
|
||||
break;
|
||||
default:
|
||||
/* nbio ras is not available */
|
||||
break;
|
||||
}
|
||||
|
||||
if (adev->nbio.ras_funcs &&
|
||||
adev->nbio.ras_funcs->init_ras_controller_interrupt) {
|
||||
r = adev->nbio.ras_funcs->init_ras_controller_interrupt(adev);
|
||||
if (r)
|
||||
goto release_con;
|
||||
}
|
||||
|
||||
if (adev->nbio.funcs->init_ras_err_event_athub_interrupt) {
|
||||
r = adev->nbio.funcs->init_ras_err_event_athub_interrupt(adev);
|
||||
if (adev->nbio.ras_funcs &&
|
||||
adev->nbio.ras_funcs->init_ras_err_event_athub_interrupt) {
|
||||
r = adev->nbio.ras_funcs->init_ras_err_event_athub_interrupt(adev);
|
||||
if (r)
|
||||
goto release_con;
|
||||
}
|
||||
|
@ -2007,6 +2157,32 @@ release_con:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int amdgpu_persistent_edc_harvesting_supported(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_persistent_edc_harvesting(struct amdgpu_device *adev,
|
||||
struct ras_common_if *ras_block)
|
||||
{
|
||||
struct ras_query_if info = {
|
||||
.head = *ras_block,
|
||||
};
|
||||
|
||||
if (!amdgpu_persistent_edc_harvesting_supported(adev))
|
||||
return 0;
|
||||
|
||||
if (amdgpu_ras_query_error_status(adev, &info) != 0)
|
||||
DRM_WARN("RAS init harvest failure");
|
||||
|
||||
if (amdgpu_ras_reset_error_status(adev, ras_block->block) != 0)
|
||||
DRM_WARN("RAS init harvest reset failure");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* helper function to handle common stuff in ip late init phase */
|
||||
int amdgpu_ras_late_init(struct amdgpu_device *adev,
|
||||
struct ras_common_if *ras_block,
|
||||
|
@ -2036,6 +2212,9 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev,
|
|||
return r;
|
||||
}
|
||||
|
||||
/* check for errors on warm reset edc persisant supported ASIC */
|
||||
amdgpu_persistent_edc_harvesting(adev, ras_block);
|
||||
|
||||
/* in resume phase, no need to create ras fs node */
|
||||
if (adev->in_suspend || amdgpu_in_reset(adev))
|
||||
return 0;
|
||||
|
@ -2083,8 +2262,12 @@ void amdgpu_ras_resume(struct amdgpu_device *adev)
|
|||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
struct ras_manager *obj, *tmp;
|
||||
|
||||
if (!con)
|
||||
if (!adev->ras_features || !con) {
|
||||
/* clean ras context for VEGA20 Gaming after send ras disable cmd */
|
||||
amdgpu_release_ras_context(adev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (con->flags & AMDGPU_RAS_FLAG_INIT_BY_VBIOS) {
|
||||
/* Set up all other IPs which are not implemented. There is a
|
||||
|
@ -2125,7 +2308,7 @@ void amdgpu_ras_suspend(struct amdgpu_device *adev)
|
|||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
|
||||
if (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return;
|
||||
|
||||
amdgpu_ras_disable_all_features(adev, 0);
|
||||
|
@ -2139,7 +2322,7 @@ int amdgpu_ras_pre_fini(struct amdgpu_device *adev)
|
|||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
|
||||
if (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return 0;
|
||||
|
||||
/* Need disable ras on all IPs here before ip [hw/sw]fini */
|
||||
|
@ -2152,7 +2335,7 @@ int amdgpu_ras_fini(struct amdgpu_device *adev)
|
|||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
|
||||
if (!con)
|
||||
if (!adev->ras_features || !con)
|
||||
return 0;
|
||||
|
||||
amdgpu_ras_fs_fini(adev);
|
||||
|
@ -2196,18 +2379,16 @@ bool amdgpu_ras_need_emergency_restart(struct amdgpu_device *adev)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool amdgpu_ras_check_err_threshold(struct amdgpu_device *adev)
|
||||
void amdgpu_release_ras_context(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
bool exc_err_limit = false;
|
||||
|
||||
if (con && (amdgpu_bad_page_threshold != 0))
|
||||
amdgpu_ras_eeprom_check_err_threshold(&con->eeprom_control,
|
||||
&exc_err_limit);
|
||||
if (!con)
|
||||
return;
|
||||
|
||||
/*
|
||||
* We are only interested in variable exc_err_limit,
|
||||
* as it says if GPU is in bad state or not.
|
||||
*/
|
||||
return exc_err_limit;
|
||||
if (!adev->ras_features && con->features & BIT(AMDGPU_RAS_BLOCK__GFX)) {
|
||||
con->features &= ~BIT(AMDGPU_RAS_BLOCK__GFX);
|
||||
amdgpu_ras_set_context(adev, NULL);
|
||||
kfree(con);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -318,8 +318,6 @@ struct amdgpu_ras {
|
|||
uint32_t supported;
|
||||
uint32_t features;
|
||||
struct list_head head;
|
||||
/* debugfs */
|
||||
struct dentry *dir;
|
||||
/* sysfs */
|
||||
struct device_attribute features_attr;
|
||||
struct bin_attribute badpages_attr;
|
||||
|
@ -395,8 +393,6 @@ struct ras_manager {
|
|||
struct list_head node;
|
||||
/* the device */
|
||||
struct amdgpu_device *adev;
|
||||
/* debugfs */
|
||||
struct dentry *ent;
|
||||
/* sysfs */
|
||||
struct device_attribute sysfs_attr;
|
||||
int attr_inuse;
|
||||
|
@ -495,8 +491,6 @@ void amdgpu_ras_suspend(struct amdgpu_device *adev);
|
|||
unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev,
|
||||
bool is_ce);
|
||||
|
||||
bool amdgpu_ras_check_err_threshold(struct amdgpu_device *adev);
|
||||
|
||||
/* error handling functions */
|
||||
int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
|
||||
struct eeprom_table_record *bps, int pages);
|
||||
|
@ -594,9 +588,12 @@ int amdgpu_ras_sysfs_remove(struct amdgpu_device *adev,
|
|||
|
||||
void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_ras_error_query(struct amdgpu_device *adev,
|
||||
int amdgpu_ras_query_error_status(struct amdgpu_device *adev,
|
||||
struct ras_query_if *info);
|
||||
|
||||
int amdgpu_ras_reset_error_status(struct amdgpu_device *adev,
|
||||
enum amdgpu_ras_block block);
|
||||
|
||||
int amdgpu_ras_error_inject(struct amdgpu_device *adev,
|
||||
struct ras_inject_if *info);
|
||||
|
||||
|
@ -629,4 +626,6 @@ void amdgpu_ras_global_ras_isr(struct amdgpu_device *adev);
|
|||
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);
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS 0xA8
|
||||
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0xA0
|
||||
#define EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID 0xA0
|
||||
#define EEPROM_I2C_TARGET_ADDR_ALDEBARAN 0xA0
|
||||
|
||||
/*
|
||||
* The 2 macros bellow represent the actual size in bytes that
|
||||
|
@ -64,7 +65,8 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev)
|
|||
{
|
||||
if ((adev->asic_type == CHIP_VEGA20) ||
|
||||
(adev->asic_type == CHIP_ARCTURUS) ||
|
||||
(adev->asic_type == CHIP_SIENNA_CICHLID))
|
||||
(adev->asic_type == CHIP_SIENNA_CICHLID) ||
|
||||
(adev->asic_type == CHIP_ALDEBARAN))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -106,6 +108,10 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev,
|
|||
*i2c_addr = EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID;
|
||||
break;
|
||||
|
||||
case CHIP_ALDEBARAN:
|
||||
*i2c_addr = EEPROM_I2C_TARGET_ADDR_ALDEBARAN;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -434,47 +440,28 @@ static uint32_t __correct_eeprom_dest_address(uint32_t curr_address)
|
|||
return curr_address;
|
||||
}
|
||||
|
||||
int amdgpu_ras_eeprom_check_err_threshold(
|
||||
struct amdgpu_ras_eeprom_control *control,
|
||||
bool *exceed_err_limit)
|
||||
bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_device *adev = to_amdgpu_device(control);
|
||||
unsigned char buff[EEPROM_ADDRESS_SIZE +
|
||||
EEPROM_TABLE_HEADER_SIZE] = { 0 };
|
||||
struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr;
|
||||
struct i2c_msg msg = {
|
||||
.addr = control->i2c_address,
|
||||
.flags = I2C_M_RD,
|
||||
.len = EEPROM_ADDRESS_SIZE + EEPROM_TABLE_HEADER_SIZE,
|
||||
.buf = buff,
|
||||
};
|
||||
int ret;
|
||||
|
||||
*exceed_err_limit = false;
|
||||
struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
|
||||
|
||||
if (!__is_ras_eeprom_supported(adev))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* read EEPROM table header */
|
||||
mutex_lock(&control->tbl_mutex);
|
||||
ret = i2c_transfer(&adev->pm.smu_i2c, &msg, 1);
|
||||
if (ret < 1) {
|
||||
dev_err(adev->dev, "Failed to read EEPROM table header.\n");
|
||||
goto err;
|
||||
}
|
||||
/* skip check eeprom table for VEGA20 Gaming */
|
||||
if (!con)
|
||||
return false;
|
||||
else
|
||||
if (!(con->features & BIT(AMDGPU_RAS_BLOCK__UMC)))
|
||||
return false;
|
||||
|
||||
__decode_table_header_from_buff(hdr, &buff[2]);
|
||||
|
||||
if (hdr->header == EEPROM_TABLE_HDR_BAD) {
|
||||
if (con->eeprom_control.tbl_hdr.header == EEPROM_TABLE_HDR_BAD) {
|
||||
dev_warn(adev->dev, "This GPU is in BAD status.");
|
||||
dev_warn(adev->dev, "Please retire it or setting one bigger "
|
||||
"threshold value when reloading driver.\n");
|
||||
*exceed_err_limit = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
err:
|
||||
mutex_unlock(&control->tbl_mutex);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control,
|
||||
|
|
|
@ -80,9 +80,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control,
|
|||
bool *exceed_err_limit);
|
||||
int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control);
|
||||
|
||||
int amdgpu_ras_eeprom_check_err_threshold(
|
||||
struct amdgpu_ras_eeprom_control *control,
|
||||
bool *exceed_err_limit);
|
||||
bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control,
|
||||
struct eeprom_table_record *records,
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* Copyright 2020 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
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_RES_CURSOR_H__
|
||||
#define __AMDGPU_RES_CURSOR_H__
|
||||
|
||||
#include <drm/drm_mm.h>
|
||||
#include <drm/ttm/ttm_resource.h>
|
||||
|
||||
/* state back for walking over vram_mgr and gtt_mgr allocations */
|
||||
struct amdgpu_res_cursor {
|
||||
uint64_t start;
|
||||
uint64_t size;
|
||||
uint64_t remaining;
|
||||
struct drm_mm_node *node;
|
||||
};
|
||||
|
||||
/**
|
||||
* amdgpu_res_first - initialize a amdgpu_res_cursor
|
||||
*
|
||||
* @res: TTM resource object to walk
|
||||
* @start: Start of the range
|
||||
* @size: Size of the range
|
||||
* @cur: cursor object to initialize
|
||||
*
|
||||
* Start walking over the range of allocations between @start and @size.
|
||||
*/
|
||||
static inline void amdgpu_res_first(struct ttm_resource *res,
|
||||
uint64_t start, uint64_t size,
|
||||
struct amdgpu_res_cursor *cur)
|
||||
{
|
||||
struct drm_mm_node *node;
|
||||
|
||||
if (!res || !res->mm_node) {
|
||||
cur->start = start;
|
||||
cur->size = size;
|
||||
cur->remaining = size;
|
||||
cur->node = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
|
||||
|
||||
node = res->mm_node;
|
||||
while (start >= node->size << PAGE_SHIFT)
|
||||
start -= node++->size << PAGE_SHIFT;
|
||||
|
||||
cur->start = (node->start << PAGE_SHIFT) + start;
|
||||
cur->size = min((node->size << PAGE_SHIFT) - start, size);
|
||||
cur->remaining = size;
|
||||
cur->node = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_res_next - advance the cursor
|
||||
*
|
||||
* @cur: the cursor to advance
|
||||
* @size: number of bytes to move forward
|
||||
*
|
||||
* Move the cursor @size bytes forwrad, walking to the next node if necessary.
|
||||
*/
|
||||
static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
|
||||
{
|
||||
struct drm_mm_node *node = cur->node;
|
||||
|
||||
BUG_ON(size > cur->remaining);
|
||||
|
||||
cur->remaining -= size;
|
||||
if (!cur->remaining)
|
||||
return;
|
||||
|
||||
cur->size -= size;
|
||||
if (cur->size) {
|
||||
cur->start += size;
|
||||
return;
|
||||
}
|
||||
|
||||
cur->node = ++node;
|
||||
cur->start = node->start << PAGE_SHIFT;
|
||||
cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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_reset.h"
|
||||
#include "aldebaran.h"
|
||||
|
||||
int amdgpu_reset_add_handler(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_handler *handler)
|
||||
{
|
||||
/* TODO: Check if handler exists? */
|
||||
list_add_tail(&handler->handler_list, &reset_ctl->reset_handlers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_reset_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_ALDEBARAN:
|
||||
ret = aldebaran_reset_init(adev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_reset_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (adev->asic_type) {
|
||||
case CHIP_ALDEBARAN:
|
||||
ret = aldebaran_reset_fini(adev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_reset_prepare_hwcontext(struct amdgpu_device *adev,
|
||||
struct amdgpu_reset_context *reset_context)
|
||||
{
|
||||
struct amdgpu_reset_handler *reset_handler = NULL;
|
||||
|
||||
if (adev->reset_cntl && adev->reset_cntl->get_reset_handler)
|
||||
reset_handler = adev->reset_cntl->get_reset_handler(
|
||||
adev->reset_cntl, reset_context);
|
||||
if (!reset_handler)
|
||||
return -ENOSYS;
|
||||
|
||||
return reset_handler->prepare_hwcontext(adev->reset_cntl,
|
||||
reset_context);
|
||||
}
|
||||
|
||||
int amdgpu_reset_perform_reset(struct amdgpu_device *adev,
|
||||
struct amdgpu_reset_context *reset_context)
|
||||
{
|
||||
int ret;
|
||||
struct amdgpu_reset_handler *reset_handler = NULL;
|
||||
|
||||
if (adev->reset_cntl)
|
||||
reset_handler = adev->reset_cntl->get_reset_handler(
|
||||
adev->reset_cntl, reset_context);
|
||||
if (!reset_handler)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = reset_handler->perform_reset(adev->reset_cntl, reset_context);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return reset_handler->restore_hwcontext(adev->reset_cntl,
|
||||
reset_context);
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_RESET_H__
|
||||
#define __AMDGPU_RESET_H__
|
||||
|
||||
#include "amdgpu.h"
|
||||
|
||||
enum AMDGPU_RESET_FLAGS {
|
||||
|
||||
AMDGPU_NEED_FULL_RESET = 0,
|
||||
AMDGPU_SKIP_HW_RESET = 1,
|
||||
};
|
||||
|
||||
struct amdgpu_reset_context {
|
||||
enum amd_reset_method method;
|
||||
struct amdgpu_device *reset_req_dev;
|
||||
struct amdgpu_job *job;
|
||||
struct amdgpu_hive_info *hive;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct amdgpu_reset_handler {
|
||||
enum amd_reset_method reset_method;
|
||||
struct list_head handler_list;
|
||||
int (*prepare_env)(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *context);
|
||||
int (*prepare_hwcontext)(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *context);
|
||||
int (*perform_reset)(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *context);
|
||||
int (*restore_hwcontext)(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *context);
|
||||
int (*restore_env)(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *context);
|
||||
|
||||
int (*do_reset)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_reset_control {
|
||||
void *handle;
|
||||
struct work_struct reset_work;
|
||||
struct mutex reset_lock;
|
||||
struct list_head reset_handlers;
|
||||
atomic_t in_reset;
|
||||
enum amd_reset_method active_reset;
|
||||
struct amdgpu_reset_handler *(*get_reset_handler)(
|
||||
struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_context *context);
|
||||
void (*async_reset)(struct work_struct *work);
|
||||
};
|
||||
|
||||
int amdgpu_reset_init(struct amdgpu_device *adev);
|
||||
int amdgpu_reset_fini(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_reset_prepare_hwcontext(struct amdgpu_device *adev,
|
||||
struct amdgpu_reset_context *reset_context);
|
||||
|
||||
int amdgpu_reset_perform_reset(struct amdgpu_device *adev,
|
||||
struct amdgpu_reset_context *reset_context);
|
||||
|
||||
int amdgpu_reset_add_handler(struct amdgpu_reset_control *reset_ctl,
|
||||
struct amdgpu_reset_handler *handler);
|
||||
|
||||
#endif
|
|
@ -164,7 +164,8 @@ void amdgpu_ring_undo(struct amdgpu_ring *ring)
|
|||
*/
|
||||
int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
||||
unsigned int max_dw, struct amdgpu_irq_src *irq_src,
|
||||
unsigned int irq_type, unsigned int hw_prio)
|
||||
unsigned int irq_type, unsigned int hw_prio,
|
||||
atomic_t *sched_score)
|
||||
{
|
||||
int r;
|
||||
int sched_hw_submission = amdgpu_sched_hw_submission;
|
||||
|
@ -189,7 +190,8 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
|||
ring->adev = adev;
|
||||
ring->idx = adev->num_rings++;
|
||||
adev->rings[ring->idx] = ring;
|
||||
r = amdgpu_fence_driver_init_ring(ring, sched_hw_submission);
|
||||
r = amdgpu_fence_driver_init_ring(ring, sched_hw_submission,
|
||||
sched_score);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,8 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev);
|
|||
void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
|
||||
|
||||
int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring,
|
||||
unsigned num_hw_submission);
|
||||
unsigned num_hw_submission,
|
||||
atomic_t *sched_score);
|
||||
int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
|
||||
struct amdgpu_irq_src *irq_src,
|
||||
unsigned irq_type);
|
||||
|
@ -282,7 +283,8 @@ void amdgpu_ring_commit(struct amdgpu_ring *ring);
|
|||
void amdgpu_ring_undo(struct amdgpu_ring *ring);
|
||||
int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
|
||||
unsigned int ring_size, struct amdgpu_irq_src *irq_src,
|
||||
unsigned int irq_type, unsigned int prio);
|
||||
unsigned int irq_type, unsigned int prio,
|
||||
atomic_t *sched_score);
|
||||
void amdgpu_ring_fini(struct amdgpu_ring *ring);
|
||||
void amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring,
|
||||
uint32_t reg0, uint32_t val0,
|
||||
|
|
|
@ -127,7 +127,8 @@ struct amdgpu_rlc_funcs {
|
|||
void (*reset)(struct amdgpu_device *adev);
|
||||
void (*start)(struct amdgpu_device *adev);
|
||||
void (*update_spm_vmid)(struct amdgpu_device *adev, unsigned vmid);
|
||||
void (*rlcg_wreg)(struct amdgpu_device *adev, u32 offset, u32 v);
|
||||
void (*rlcg_wreg)(struct amdgpu_device *adev, u32 offset, u32 v, u32 flag);
|
||||
u32 (*rlcg_rreg)(struct amdgpu_device *adev, u32 offset, u32 flag);
|
||||
bool (*is_rlcg_access_range)(struct amdgpu_device *adev, uint32_t reg);
|
||||
};
|
||||
|
||||
|
|
|
@ -64,6 +64,11 @@ struct amdgpu_sdma {
|
|||
struct amdgpu_irq_src trap_irq;
|
||||
struct amdgpu_irq_src illegal_inst_irq;
|
||||
struct amdgpu_irq_src ecc_irq;
|
||||
struct amdgpu_irq_src vm_hole_irq;
|
||||
struct amdgpu_irq_src doorbell_invalid_irq;
|
||||
struct amdgpu_irq_src pool_timeout_irq;
|
||||
struct amdgpu_irq_src srbm_write_irq;
|
||||
|
||||
int num_instances;
|
||||
uint32_t srbm_soft_reset;
|
||||
bool has_page_queue;
|
||||
|
|
|
@ -69,6 +69,9 @@ void psp_securedisplay_parse_resp_status(struct psp_context *psp,
|
|||
case TA_SECUREDISPLAY_STATUS__READ_CRC_ERROR:
|
||||
dev_err(psp->adev->dev, "Secure display: Failed to Read CRC");
|
||||
break;
|
||||
case TA_SECUREDISPLAY_STATUS__I2C_INIT_ERROR:
|
||||
dev_err(psp->adev->dev, "Secure display: Failed to initialize I2C.");
|
||||
break;
|
||||
default:
|
||||
dev_err(psp->adev->dev, "Secure display: Failed to parse status: %d\n", status);
|
||||
}
|
||||
|
@ -92,9 +95,7 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
|
|||
struct drm_device *dev = adev_to_drm(adev);
|
||||
uint32_t phy_id;
|
||||
uint32_t op;
|
||||
int i;
|
||||
char str[64];
|
||||
char i2c_output[256];
|
||||
int ret;
|
||||
|
||||
if (*pos || size > sizeof(str) - 1)
|
||||
|
@ -136,11 +137,9 @@ static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __u
|
|||
ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
|
||||
if (!ret) {
|
||||
if (securedisplay_cmd->status == TA_SECUREDISPLAY_STATUS__SUCCESS) {
|
||||
memset(i2c_output, 0, sizeof(i2c_output));
|
||||
for (i = 0; i < TA_SECUREDISPLAY_I2C_BUFFER_SIZE; i++)
|
||||
sprintf(i2c_output, "%s 0x%X", i2c_output,
|
||||
securedisplay_cmd->securedisplay_out_message.send_roi_crc.i2c_buf[i]);
|
||||
dev_info(adev->dev, "SECUREDISPLAY: I2C buffer out put is :%s\n", i2c_output);
|
||||
dev_info(adev->dev, "SECUREDISPLAY: I2C buffer out put is: %*ph\n",
|
||||
TA_SECUREDISPLAY_I2C_BUFFER_SIZE,
|
||||
securedisplay_cmd->securedisplay_out_message.send_roi_crc.i2c_buf);
|
||||
} else {
|
||||
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ struct amdgpu_smuio_funcs {
|
|||
u32 (*get_rom_data_offset)(struct amdgpu_device *adev);
|
||||
void (*update_rom_clock_gating)(struct amdgpu_device *adev, bool enable);
|
||||
void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags);
|
||||
u32 (*get_die_id)(struct amdgpu_device *adev);
|
||||
bool (*is_host_gpu_xgmi_supported)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_smuio {
|
||||
|
|
|
@ -62,6 +62,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
|
|||
bp.flags = 0;
|
||||
bp.type = ttm_bo_type_kernel;
|
||||
bp.resv = NULL;
|
||||
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
|
||||
|
||||
r = amdgpu_bo_create(adev, &bp, &vram_obj);
|
||||
if (r) {
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#include <drm/ttm/ttm_bo_driver.h>
|
||||
#include <drm/ttm/ttm_placement.h>
|
||||
|
||||
#include <drm/drm_debugfs.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
|
@ -57,14 +56,15 @@
|
|||
#include "amdgpu_sdma.h"
|
||||
#include "amdgpu_ras.h"
|
||||
#include "amdgpu_atomfirmware.h"
|
||||
#include "amdgpu_res_cursor.h"
|
||||
#include "bif/bif_4_1_d.h"
|
||||
|
||||
#define AMDGPU_TTM_VRAM_MAX_DW_READ (size_t)128
|
||||
|
||||
static int amdgpu_ttm_backend_bind(struct ttm_bo_device *bdev,
|
||||
static int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm,
|
||||
struct ttm_resource *bo_mem);
|
||||
static void amdgpu_ttm_backend_unbind(struct ttm_bo_device *bdev,
|
||||
static void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm);
|
||||
|
||||
static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev,
|
||||
|
@ -178,55 +178,12 @@ static int amdgpu_verify_access(struct ttm_buffer_object *bo, struct file *filp)
|
|||
filp->private_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_mm_node_addr - Compute the GPU relative offset of a GTT buffer.
|
||||
*
|
||||
* @bo: The bo to assign the memory to.
|
||||
* @mm_node: Memory manager node for drm allocator.
|
||||
* @mem: The region where the bo resides.
|
||||
*
|
||||
*/
|
||||
static uint64_t amdgpu_mm_node_addr(struct ttm_buffer_object *bo,
|
||||
struct drm_mm_node *mm_node,
|
||||
struct ttm_resource *mem)
|
||||
{
|
||||
uint64_t addr = 0;
|
||||
|
||||
if (mm_node->start != AMDGPU_BO_INVALID_OFFSET) {
|
||||
addr = mm_node->start << PAGE_SHIFT;
|
||||
addr += amdgpu_ttm_domain_start(amdgpu_ttm_adev(bo->bdev),
|
||||
mem->mem_type);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_find_mm_node - Helper function finds the drm_mm_node corresponding to
|
||||
* @offset. It also modifies the offset to be within the drm_mm_node returned
|
||||
*
|
||||
* @mem: The region where the bo resides.
|
||||
* @offset: The offset that drm_mm_node is used for finding.
|
||||
*
|
||||
*/
|
||||
static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_resource *mem,
|
||||
uint64_t *offset)
|
||||
{
|
||||
struct drm_mm_node *mm_node = mem->mm_node;
|
||||
|
||||
while (*offset >= (mm_node->size << PAGE_SHIFT)) {
|
||||
*offset -= (mm_node->size << PAGE_SHIFT);
|
||||
++mm_node;
|
||||
}
|
||||
return mm_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_ttm_map_buffer - Map memory into the GART windows
|
||||
* @bo: buffer object to map
|
||||
* @mem: memory object to map
|
||||
* @mm_node: drm_mm node object to map
|
||||
* @mm_cur: range to map
|
||||
* @num_pages: number of pages to map
|
||||
* @offset: offset into @mm_node where to start
|
||||
* @window: which GART window to use
|
||||
* @ring: DMA ring to use for the copy
|
||||
* @tmz: if we should setup a TMZ enabled mapping
|
||||
|
@ -237,10 +194,10 @@ static struct drm_mm_node *amdgpu_find_mm_node(struct ttm_resource *mem,
|
|||
*/
|
||||
static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
|
||||
struct ttm_resource *mem,
|
||||
struct drm_mm_node *mm_node,
|
||||
unsigned num_pages, uint64_t offset,
|
||||
unsigned window, struct amdgpu_ring *ring,
|
||||
bool tmz, uint64_t *addr)
|
||||
struct amdgpu_res_cursor *mm_cur,
|
||||
unsigned num_pages, unsigned window,
|
||||
struct amdgpu_ring *ring, bool tmz,
|
||||
uint64_t *addr)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
struct amdgpu_job *job;
|
||||
|
@ -257,14 +214,15 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
|
|||
|
||||
/* Map only what can't be accessed directly */
|
||||
if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) {
|
||||
*addr = amdgpu_mm_node_addr(bo, mm_node, mem) + offset;
|
||||
*addr = amdgpu_ttm_domain_start(adev, mem->mem_type) +
|
||||
mm_cur->start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addr = adev->gmc.gart_start;
|
||||
*addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE *
|
||||
AMDGPU_GPU_PAGE_SIZE;
|
||||
*addr += offset & ~PAGE_MASK;
|
||||
*addr += mm_cur->start & ~PAGE_MASK;
|
||||
|
||||
num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
|
||||
num_bytes = num_pages * 8;
|
||||
|
@ -292,17 +250,17 @@ static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
|
|||
cpu_addr = &job->ibs[0].ptr[num_dw];
|
||||
|
||||
if (mem->mem_type == TTM_PL_TT) {
|
||||
dma_addr_t *dma_address;
|
||||
dma_addr_t *dma_addr;
|
||||
|
||||
dma_address = &bo->ttm->dma_address[offset >> PAGE_SHIFT];
|
||||
r = amdgpu_gart_map(adev, 0, num_pages, dma_address, flags,
|
||||
dma_addr = &bo->ttm->dma_address[mm_cur->start >> PAGE_SHIFT];
|
||||
r = amdgpu_gart_map(adev, 0, num_pages, dma_addr, flags,
|
||||
cpu_addr);
|
||||
if (r)
|
||||
goto error_free;
|
||||
} else {
|
||||
dma_addr_t dma_address;
|
||||
|
||||
dma_address = (mm_node->start << PAGE_SHIFT) + offset;
|
||||
dma_address = mm_cur->start;
|
||||
dma_address += adev->vm_manager.vram_base_offset;
|
||||
|
||||
for (i = 0; i < num_pages; ++i) {
|
||||
|
@ -354,9 +312,8 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
|
|||
const uint32_t GTT_MAX_BYTES = (AMDGPU_GTT_MAX_TRANSFER_SIZE *
|
||||
AMDGPU_GPU_PAGE_SIZE);
|
||||
|
||||
uint64_t src_node_size, dst_node_size, src_offset, dst_offset;
|
||||
struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
|
||||
struct drm_mm_node *src_mm, *dst_mm;
|
||||
struct amdgpu_res_cursor src_mm, dst_mm;
|
||||
struct dma_fence *fence = NULL;
|
||||
int r = 0;
|
||||
|
||||
|
@ -365,29 +322,13 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
src_offset = src->offset;
|
||||
if (src->mem->mm_node) {
|
||||
src_mm = amdgpu_find_mm_node(src->mem, &src_offset);
|
||||
src_node_size = (src_mm->size << PAGE_SHIFT) - src_offset;
|
||||
} else {
|
||||
src_mm = NULL;
|
||||
src_node_size = ULLONG_MAX;
|
||||
}
|
||||
|
||||
dst_offset = dst->offset;
|
||||
if (dst->mem->mm_node) {
|
||||
dst_mm = amdgpu_find_mm_node(dst->mem, &dst_offset);
|
||||
dst_node_size = (dst_mm->size << PAGE_SHIFT) - dst_offset;
|
||||
} else {
|
||||
dst_mm = NULL;
|
||||
dst_node_size = ULLONG_MAX;
|
||||
}
|
||||
amdgpu_res_first(src->mem, src->offset, size, &src_mm);
|
||||
amdgpu_res_first(dst->mem, dst->offset, size, &dst_mm);
|
||||
|
||||
mutex_lock(&adev->mman.gtt_window_lock);
|
||||
|
||||
while (size) {
|
||||
uint32_t src_page_offset = src_offset & ~PAGE_MASK;
|
||||
uint32_t dst_page_offset = dst_offset & ~PAGE_MASK;
|
||||
while (src_mm.remaining) {
|
||||
uint32_t src_page_offset = src_mm.start & ~PAGE_MASK;
|
||||
uint32_t dst_page_offset = dst_mm.start & ~PAGE_MASK;
|
||||
struct dma_fence *next;
|
||||
uint32_t cur_size;
|
||||
uint64_t from, to;
|
||||
|
@ -396,19 +337,19 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
|
|||
* begins at an offset, then adjust the size accordingly
|
||||
*/
|
||||
cur_size = max(src_page_offset, dst_page_offset);
|
||||
cur_size = min(min3(src_node_size, dst_node_size, size),
|
||||
cur_size = min(min3(src_mm.size, dst_mm.size, size),
|
||||
(uint64_t)(GTT_MAX_BYTES - cur_size));
|
||||
|
||||
/* Map src to window 0 and dst to window 1. */
|
||||
r = amdgpu_ttm_map_buffer(src->bo, src->mem, src_mm,
|
||||
r = amdgpu_ttm_map_buffer(src->bo, src->mem, &src_mm,
|
||||
PFN_UP(cur_size + src_page_offset),
|
||||
src_offset, 0, ring, tmz, &from);
|
||||
0, ring, tmz, &from);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
r = amdgpu_ttm_map_buffer(dst->bo, dst->mem, dst_mm,
|
||||
r = amdgpu_ttm_map_buffer(dst->bo, dst->mem, &dst_mm,
|
||||
PFN_UP(cur_size + dst_page_offset),
|
||||
dst_offset, 1, ring, tmz, &to);
|
||||
1, ring, tmz, &to);
|
||||
if (r)
|
||||
goto error;
|
||||
|
||||
|
@ -420,27 +361,8 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
|
|||
dma_fence_put(fence);
|
||||
fence = next;
|
||||
|
||||
size -= cur_size;
|
||||
if (!size)
|
||||
break;
|
||||
|
||||
src_node_size -= cur_size;
|
||||
if (!src_node_size) {
|
||||
++src_mm;
|
||||
src_node_size = src_mm->size << PAGE_SHIFT;
|
||||
src_offset = 0;
|
||||
} else {
|
||||
src_offset += cur_size;
|
||||
}
|
||||
|
||||
dst_node_size -= cur_size;
|
||||
if (!dst_node_size) {
|
||||
++dst_mm;
|
||||
dst_node_size = dst_mm->size << PAGE_SHIFT;
|
||||
dst_offset = 0;
|
||||
} else {
|
||||
dst_offset += cur_size;
|
||||
}
|
||||
amdgpu_res_next(&src_mm, cur_size);
|
||||
amdgpu_res_next(&dst_mm, cur_size);
|
||||
}
|
||||
error:
|
||||
mutex_unlock(&adev->mman.gtt_window_lock);
|
||||
|
@ -519,7 +441,8 @@ error:
|
|||
static bool amdgpu_mem_visible(struct amdgpu_device *adev,
|
||||
struct ttm_resource *mem)
|
||||
{
|
||||
struct drm_mm_node *nodes = mem->mm_node;
|
||||
uint64_t mem_size = (u64)mem->num_pages << PAGE_SHIFT;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
|
||||
if (mem->mem_type == TTM_PL_SYSTEM ||
|
||||
mem->mem_type == TTM_PL_TT)
|
||||
|
@ -527,12 +450,13 @@ static bool amdgpu_mem_visible(struct amdgpu_device *adev,
|
|||
if (mem->mem_type != TTM_PL_VRAM)
|
||||
return false;
|
||||
|
||||
amdgpu_res_first(mem, 0, mem_size, &cursor);
|
||||
|
||||
/* ttm_resource_ioremap only supports contiguous memory */
|
||||
if (nodes->size != mem->num_pages)
|
||||
if (cursor.size != mem_size)
|
||||
return false;
|
||||
|
||||
return ((nodes->start + nodes->size) << PAGE_SHIFT)
|
||||
<= adev->gmc.visible_vram_size;
|
||||
return cursor.start + cursor.size <= adev->gmc.visible_vram_size;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -646,7 +570,7 @@ out:
|
|||
*
|
||||
* Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault()
|
||||
*/
|
||||
static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
|
||||
static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *mem)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
|
||||
struct drm_mm_node *mm_node = mem->mm_node;
|
||||
|
@ -674,7 +598,10 @@ static int amdgpu_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_reso
|
|||
|
||||
mem->bus.offset += adev->gmc.aper_base;
|
||||
mem->bus.is_iomem = true;
|
||||
mem->bus.caching = ttm_write_combined;
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
mem->bus.caching = ttm_cached;
|
||||
else
|
||||
mem->bus.caching = ttm_write_combined;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -686,12 +613,10 @@ static unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
|
|||
unsigned long page_offset)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
|
||||
uint64_t offset = (page_offset << PAGE_SHIFT);
|
||||
struct drm_mm_node *mm;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
|
||||
mm = amdgpu_find_mm_node(&bo->mem, &offset);
|
||||
offset += adev->gmc.aper_base;
|
||||
return mm->start + (offset >> PAGE_SHIFT);
|
||||
amdgpu_res_first(&bo->mem, (u64)page_offset << PAGE_SHIFT, 0, &cursor);
|
||||
return (adev->gmc.aper_base + cursor.start) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -893,16 +818,15 @@ void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages)
|
|||
*
|
||||
* Called by amdgpu_ttm_backend_bind()
|
||||
**/
|
||||
static int amdgpu_ttm_tt_pin_userptr(struct ttm_bo_device *bdev,
|
||||
static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
|
||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||
int r;
|
||||
|
||||
int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
|
||||
enum dma_data_direction direction = write ?
|
||||
DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
|
||||
int r;
|
||||
|
||||
/* Allocate an SG array and squash pages into it */
|
||||
r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
|
||||
|
@ -931,18 +855,17 @@ release_sg:
|
|||
/*
|
||||
* amdgpu_ttm_tt_unpin_userptr - Unpin and unmap userptr pages
|
||||
*/
|
||||
static void amdgpu_ttm_tt_unpin_userptr(struct ttm_bo_device *bdev,
|
||||
static void amdgpu_ttm_tt_unpin_userptr(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
|
||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||
|
||||
int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
|
||||
enum dma_data_direction direction = write ?
|
||||
DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
|
||||
|
||||
/* double check that we don't free the table twice */
|
||||
if (!ttm->sg->sgl)
|
||||
if (!ttm->sg || !ttm->sg->sgl)
|
||||
return;
|
||||
|
||||
/* unmap the pages mapped to the device */
|
||||
|
@ -1015,7 +938,7 @@ gart_bind_fail:
|
|||
* Called by ttm_tt_bind() on behalf of ttm_bo_handle_move_mem().
|
||||
* This handles binding GTT memory to the device address space.
|
||||
*/
|
||||
static int amdgpu_ttm_backend_bind(struct ttm_bo_device *bdev,
|
||||
static int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm,
|
||||
struct ttm_resource *bo_mem)
|
||||
{
|
||||
|
@ -1155,20 +1078,20 @@ int amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo)
|
|||
* Called by ttm_tt_unbind() on behalf of ttm_bo_move_ttm() and
|
||||
* ttm_tt_destroy().
|
||||
*/
|
||||
static void amdgpu_ttm_backend_unbind(struct ttm_bo_device *bdev,
|
||||
static void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm)
|
||||
{
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
|
||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||
int r;
|
||||
|
||||
if (!gtt->bound)
|
||||
return;
|
||||
|
||||
/* if the pages have userptr pinning then clear that first */
|
||||
if (gtt->userptr)
|
||||
amdgpu_ttm_tt_unpin_userptr(bdev, ttm);
|
||||
|
||||
if (!gtt->bound)
|
||||
return;
|
||||
|
||||
if (gtt->offset == AMDGPU_BO_INVALID_OFFSET)
|
||||
return;
|
||||
|
||||
|
@ -1180,7 +1103,7 @@ static void amdgpu_ttm_backend_unbind(struct ttm_bo_device *bdev,
|
|||
gtt->bound = false;
|
||||
}
|
||||
|
||||
static void amdgpu_ttm_backend_destroy(struct ttm_bo_device *bdev,
|
||||
static void amdgpu_ttm_backend_destroy(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm)
|
||||
{
|
||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||
|
@ -1234,7 +1157,7 @@ static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_buffer_object *bo,
|
|||
* Map the pages of a ttm_tt object to an address space visible
|
||||
* to the underlying device.
|
||||
*/
|
||||
static int amdgpu_ttm_tt_populate(struct ttm_bo_device *bdev,
|
||||
static int amdgpu_ttm_tt_populate(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm,
|
||||
struct ttm_operation_ctx *ctx)
|
||||
{
|
||||
|
@ -1278,7 +1201,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_bo_device *bdev,
|
|||
* Unmaps pages of a ttm_tt object from the device address space and
|
||||
* unpopulates the page array backing it.
|
||||
*/
|
||||
static void amdgpu_ttm_tt_unpopulate(struct ttm_bo_device *bdev,
|
||||
static void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev,
|
||||
struct ttm_tt *ttm)
|
||||
{
|
||||
struct amdgpu_ttm_tt *gtt = (void *)ttm;
|
||||
|
@ -1430,6 +1353,10 @@ uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem)
|
|||
flags |= AMDGPU_PTE_SNOOPED;
|
||||
}
|
||||
|
||||
if (mem && mem->mem_type == TTM_PL_VRAM &&
|
||||
mem->bus.caching == ttm_cached)
|
||||
flags |= AMDGPU_PTE_SNOOPED;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
@ -1469,7 +1396,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
|
|||
const struct ttm_place *place)
|
||||
{
|
||||
unsigned long num_pages = bo->mem.num_pages;
|
||||
struct drm_mm_node *node = bo->mem.mm_node;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
struct dma_resv_list *flist;
|
||||
struct dma_fence *f;
|
||||
int i;
|
||||
|
@ -1501,13 +1428,15 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
|
|||
|
||||
case TTM_PL_VRAM:
|
||||
/* Check each drm MM node individually */
|
||||
while (num_pages) {
|
||||
if (place->fpfn < (node->start + node->size) &&
|
||||
!(place->lpfn && place->lpfn <= node->start))
|
||||
amdgpu_res_first(&bo->mem, 0, (u64)num_pages << PAGE_SHIFT,
|
||||
&cursor);
|
||||
while (cursor.remaining) {
|
||||
if (place->fpfn < PFN_DOWN(cursor.start + cursor.size)
|
||||
&& !(place->lpfn &&
|
||||
place->lpfn <= PFN_DOWN(cursor.start)))
|
||||
return true;
|
||||
|
||||
num_pages -= node->size;
|
||||
++node;
|
||||
amdgpu_res_next(&cursor, cursor.size);
|
||||
}
|
||||
return false;
|
||||
|
||||
|
@ -1531,41 +1460,36 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
|
|||
* access for debugging purposes.
|
||||
*/
|
||||
static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
|
||||
unsigned long offset,
|
||||
void *buf, int len, int write)
|
||||
unsigned long offset, void *buf, int len,
|
||||
int write)
|
||||
{
|
||||
struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
|
||||
struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
|
||||
struct drm_mm_node *nodes;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
unsigned long flags;
|
||||
uint32_t value = 0;
|
||||
int ret = 0;
|
||||
uint64_t pos;
|
||||
unsigned long flags;
|
||||
|
||||
if (bo->mem.mem_type != TTM_PL_VRAM)
|
||||
return -EIO;
|
||||
|
||||
pos = offset;
|
||||
nodes = amdgpu_find_mm_node(&abo->tbo.mem, &pos);
|
||||
pos += (nodes->start << PAGE_SHIFT);
|
||||
|
||||
while (len && pos < adev->gmc.mc_vram_size) {
|
||||
uint64_t aligned_pos = pos & ~(uint64_t)3;
|
||||
uint64_t bytes = 4 - (pos & 3);
|
||||
uint32_t shift = (pos & 3) * 8;
|
||||
amdgpu_res_first(&bo->mem, offset, len, &cursor);
|
||||
while (cursor.remaining) {
|
||||
uint64_t aligned_pos = cursor.start & ~(uint64_t)3;
|
||||
uint64_t bytes = 4 - (cursor.start & 3);
|
||||
uint32_t shift = (cursor.start & 3) * 8;
|
||||
uint32_t mask = 0xffffffff << shift;
|
||||
|
||||
if (len < bytes) {
|
||||
mask &= 0xffffffff >> (bytes - len) * 8;
|
||||
bytes = len;
|
||||
if (cursor.size < bytes) {
|
||||
mask &= 0xffffffff >> (bytes - cursor.size) * 8;
|
||||
bytes = cursor.size;
|
||||
}
|
||||
|
||||
if (mask != 0xffffffff) {
|
||||
spin_lock_irqsave(&adev->mmio_idx_lock, flags);
|
||||
WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t)aligned_pos) | 0x80000000);
|
||||
WREG32_NO_KIQ(mmMM_INDEX_HI, aligned_pos >> 31);
|
||||
if (!write || mask != 0xffffffff)
|
||||
value = RREG32_NO_KIQ(mmMM_DATA);
|
||||
value = RREG32_NO_KIQ(mmMM_DATA);
|
||||
if (write) {
|
||||
value &= ~mask;
|
||||
value |= (*(uint32_t *)buf << shift) & mask;
|
||||
|
@ -1577,21 +1501,15 @@ static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
|
|||
memcpy(buf, &value, bytes);
|
||||
}
|
||||
} else {
|
||||
bytes = (nodes->start + nodes->size) << PAGE_SHIFT;
|
||||
bytes = min(bytes - pos, (uint64_t)len & ~0x3ull);
|
||||
|
||||
amdgpu_device_vram_access(adev, pos, (uint32_t *)buf,
|
||||
bytes, write);
|
||||
bytes = cursor.size & ~0x3ULL;
|
||||
amdgpu_device_vram_access(adev, cursor.start,
|
||||
(uint32_t *)buf, bytes,
|
||||
write);
|
||||
}
|
||||
|
||||
ret += bytes;
|
||||
buf = (uint8_t *)buf + bytes;
|
||||
pos += bytes;
|
||||
len -= bytes;
|
||||
if (pos >= (nodes->start + nodes->size) << PAGE_SHIFT) {
|
||||
++nodes;
|
||||
pos = (nodes->start << PAGE_SHIFT);
|
||||
}
|
||||
amdgpu_res_next(&cursor, bytes);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -1603,7 +1521,7 @@ amdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo)
|
|||
amdgpu_bo_move_notify(bo, false, NULL);
|
||||
}
|
||||
|
||||
static struct ttm_bo_driver amdgpu_bo_driver = {
|
||||
static struct ttm_device_funcs amdgpu_bo_driver = {
|
||||
.ttm_tt_create = &amdgpu_ttm_tt_create,
|
||||
.ttm_tt_populate = &amdgpu_ttm_tt_populate,
|
||||
.ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate,
|
||||
|
@ -1696,7 +1614,7 @@ static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev)
|
|||
(adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET);
|
||||
ctx->train_data_size =
|
||||
GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES;
|
||||
|
||||
|
||||
DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n",
|
||||
ctx->train_data_size,
|
||||
ctx->p2c_train_data_offset,
|
||||
|
@ -1785,7 +1703,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
|
|||
mutex_init(&adev->mman.gtt_window_lock);
|
||||
|
||||
/* No others user of address space so set it to 0 */
|
||||
r = ttm_bo_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->dev,
|
||||
r = ttm_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->dev,
|
||||
adev_to_drm(adev)->anon_inode->i_mapping,
|
||||
adev_to_drm(adev)->vma_offset_manager,
|
||||
adev->need_swiotlb,
|
||||
|
@ -1812,8 +1730,15 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
|
|||
/* Change the size here instead of the init above so only lpfn is affected */
|
||||
amdgpu_ttm_set_buffer_funcs_status(adev, false);
|
||||
#ifdef CONFIG_64BIT
|
||||
adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
#ifdef CONFIG_X86
|
||||
if (adev->gmc.xgmi.connected_to_cpu)
|
||||
adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
|
||||
else
|
||||
#endif
|
||||
adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base,
|
||||
adev->gmc.visible_vram_size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -1926,7 +1851,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
|
|||
ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS);
|
||||
ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS);
|
||||
ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA);
|
||||
ttm_bo_device_release(&adev->mman.bdev);
|
||||
ttm_device_fini(&adev->mman.bdev);
|
||||
adev->mman.initialized = false;
|
||||
DRM_INFO("amdgpu: ttm finalized\n");
|
||||
}
|
||||
|
@ -2002,7 +1927,7 @@ unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct vm_operations_struct amdgpu_ttm_vm_ops = {
|
||||
static const struct vm_operations_struct amdgpu_ttm_vm_ops = {
|
||||
.fault = amdgpu_ttm_fault,
|
||||
.open = ttm_bo_vm_open,
|
||||
.close = ttm_bo_vm_close,
|
||||
|
@ -2053,7 +1978,8 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
|
|||
return r;
|
||||
|
||||
if (vm_needs_flush) {
|
||||
job->vm_pd_addr = amdgpu_gmc_pd_addr(adev->gart.bo);
|
||||
job->vm_pd_addr = amdgpu_gmc_pd_addr(adev->gmc.pdb0_bo ?
|
||||
adev->gmc.pdb0_bo : adev->gart.bo);
|
||||
job->vm_needs_flush = true;
|
||||
}
|
||||
if (resv) {
|
||||
|
@ -2104,9 +2030,9 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
|
|||
uint32_t max_bytes = adev->mman.buffer_funcs->fill_max_bytes;
|
||||
struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
|
||||
|
||||
struct drm_mm_node *mm_node;
|
||||
unsigned long num_pages;
|
||||
struct amdgpu_res_cursor cursor;
|
||||
unsigned int num_loops, num_dw;
|
||||
uint64_t num_bytes;
|
||||
|
||||
struct amdgpu_job *job;
|
||||
int r;
|
||||
|
@ -2122,15 +2048,13 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
|
|||
return r;
|
||||
}
|
||||
|
||||
num_pages = bo->tbo.mem.num_pages;
|
||||
mm_node = bo->tbo.mem.mm_node;
|
||||
num_bytes = bo->tbo.mem.num_pages << PAGE_SHIFT;
|
||||
num_loops = 0;
|
||||
while (num_pages) {
|
||||
uint64_t byte_count = mm_node->size << PAGE_SHIFT;
|
||||
|
||||
num_loops += DIV_ROUND_UP_ULL(byte_count, max_bytes);
|
||||
num_pages -= mm_node->size;
|
||||
++mm_node;
|
||||
amdgpu_res_first(&bo->tbo.mem, 0, num_bytes, &cursor);
|
||||
while (cursor.remaining) {
|
||||
num_loops += DIV_ROUND_UP_ULL(cursor.size, max_bytes);
|
||||
amdgpu_res_next(&cursor, cursor.size);
|
||||
}
|
||||
num_dw = num_loops * adev->mman.buffer_funcs->fill_num_dw;
|
||||
|
||||
|
@ -2152,27 +2076,16 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
|
|||
}
|
||||
}
|
||||
|
||||
num_pages = bo->tbo.mem.num_pages;
|
||||
mm_node = bo->tbo.mem.mm_node;
|
||||
amdgpu_res_first(&bo->tbo.mem, 0, num_bytes, &cursor);
|
||||
while (cursor.remaining) {
|
||||
uint32_t cur_size = min_t(uint64_t, cursor.size, max_bytes);
|
||||
uint64_t dst_addr = cursor.start;
|
||||
|
||||
while (num_pages) {
|
||||
uint64_t byte_count = mm_node->size << PAGE_SHIFT;
|
||||
uint64_t dst_addr;
|
||||
dst_addr += amdgpu_ttm_domain_start(adev, bo->tbo.mem.mem_type);
|
||||
amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data, dst_addr,
|
||||
cur_size);
|
||||
|
||||
dst_addr = amdgpu_mm_node_addr(&bo->tbo, mm_node, &bo->tbo.mem);
|
||||
while (byte_count) {
|
||||
uint32_t cur_size_in_bytes = min_t(uint64_t, byte_count,
|
||||
max_bytes);
|
||||
|
||||
amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data,
|
||||
dst_addr, cur_size_in_bytes);
|
||||
|
||||
dst_addr += cur_size_in_bytes;
|
||||
byte_count -= cur_size_in_bytes;
|
||||
}
|
||||
|
||||
num_pages -= mm_node->size;
|
||||
++mm_node;
|
||||
amdgpu_res_next(&cursor, cur_size);
|
||||
}
|
||||
|
||||
amdgpu_ring_pad_ib(ring, &job->ibs[0]);
|
||||
|
@ -2191,36 +2104,74 @@ error_free:
|
|||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
static int amdgpu_mm_dump_table(struct seq_file *m, void *data)
|
||||
static int amdgpu_mm_vram_table_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
unsigned ttm_pl = (uintptr_t)node->info_ent->data;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, ttm_pl);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev,
|
||||
TTM_PL_VRAM);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
|
||||
man->func->debug(man, &p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_ttm_pool_debugfs(struct seq_file *m, void *data)
|
||||
static int amdgpu_ttm_page_pool_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *)m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
|
||||
return ttm_pool_debugfs(&adev->mman.bdev.pool, m);
|
||||
}
|
||||
|
||||
static const struct drm_info_list amdgpu_ttm_debugfs_list[] = {
|
||||
{"amdgpu_vram_mm", amdgpu_mm_dump_table, 0, (void *)TTM_PL_VRAM},
|
||||
{"amdgpu_gtt_mm", amdgpu_mm_dump_table, 0, (void *)TTM_PL_TT},
|
||||
{"amdgpu_gds_mm", amdgpu_mm_dump_table, 0, (void *)AMDGPU_PL_GDS},
|
||||
{"amdgpu_gws_mm", amdgpu_mm_dump_table, 0, (void *)AMDGPU_PL_GWS},
|
||||
{"amdgpu_oa_mm", amdgpu_mm_dump_table, 0, (void *)AMDGPU_PL_OA},
|
||||
{"ttm_page_pool", amdgpu_ttm_pool_debugfs, 0, NULL},
|
||||
};
|
||||
static int amdgpu_mm_tt_table_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev,
|
||||
TTM_PL_TT);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
|
||||
man->func->debug(man, &p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_mm_gds_table_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev,
|
||||
AMDGPU_PL_GDS);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
|
||||
man->func->debug(man, &p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_mm_gws_table_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev,
|
||||
AMDGPU_PL_GWS);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
|
||||
man->func->debug(man, &p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdgpu_mm_oa_table_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
|
||||
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev,
|
||||
AMDGPU_PL_OA);
|
||||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
|
||||
man->func->debug(man, &p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_mm_vram_table);
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_mm_tt_table);
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_mm_gds_table);
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_mm_gws_table);
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_mm_oa_table);
|
||||
DEFINE_SHOW_ATTRIBUTE(amdgpu_ttm_page_pool);
|
||||
|
||||
/*
|
||||
* amdgpu_ttm_vram_read - Linear read access to VRAM
|
||||
|
@ -2308,58 +2259,6 @@ static const struct file_operations amdgpu_ttm_vram_fops = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
|
||||
/*
|
||||
* amdgpu_ttm_gtt_read - Linear read access to GTT memory
|
||||
*/
|
||||
static ssize_t amdgpu_ttm_gtt_read(struct file *f, char __user *buf,
|
||||
size_t size, loff_t *pos)
|
||||
{
|
||||
struct amdgpu_device *adev = file_inode(f)->i_private;
|
||||
ssize_t result = 0;
|
||||
int r;
|
||||
|
||||
while (size) {
|
||||
loff_t p = *pos / PAGE_SIZE;
|
||||
unsigned off = *pos & ~PAGE_MASK;
|
||||
size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
|
||||
struct page *page;
|
||||
void *ptr;
|
||||
|
||||
if (p >= adev->gart.num_cpu_pages)
|
||||
return result;
|
||||
|
||||
page = adev->gart.pages[p];
|
||||
if (page) {
|
||||
ptr = kmap(page);
|
||||
ptr += off;
|
||||
|
||||
r = copy_to_user(buf, ptr, cur_size);
|
||||
kunmap(adev->gart.pages[p]);
|
||||
} else
|
||||
r = clear_user(buf, cur_size);
|
||||
|
||||
if (r)
|
||||
return -EFAULT;
|
||||
|
||||
result += cur_size;
|
||||
buf += cur_size;
|
||||
*pos += cur_size;
|
||||
size -= cur_size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const struct file_operations amdgpu_ttm_gtt_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = amdgpu_ttm_gtt_read,
|
||||
.llseek = default_llseek
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* amdgpu_iomem_read - Virtual read access to GPU mapped memory
|
||||
*
|
||||
|
@ -2474,46 +2373,29 @@ static const struct file_operations amdgpu_ttm_iomem_fops = {
|
|||
.llseek = default_llseek
|
||||
};
|
||||
|
||||
static const struct {
|
||||
char *name;
|
||||
const struct file_operations *fops;
|
||||
int domain;
|
||||
} ttm_debugfs_entries[] = {
|
||||
{ "amdgpu_vram", &amdgpu_ttm_vram_fops, TTM_PL_VRAM },
|
||||
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
|
||||
{ "amdgpu_gtt", &amdgpu_ttm_gtt_fops, TTM_PL_TT },
|
||||
#endif
|
||||
{ "amdgpu_iomem", &amdgpu_ttm_iomem_fops, TTM_PL_SYSTEM },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev)
|
||||
void amdgpu_ttm_debugfs_init(struct amdgpu_device *adev)
|
||||
{
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
unsigned count;
|
||||
|
||||
struct drm_minor *minor = adev_to_drm(adev)->primary;
|
||||
struct dentry *ent, *root = minor->debugfs_root;
|
||||
struct dentry *root = minor->debugfs_root;
|
||||
|
||||
for (count = 0; count < ARRAY_SIZE(ttm_debugfs_entries); count++) {
|
||||
ent = debugfs_create_file(
|
||||
ttm_debugfs_entries[count].name,
|
||||
S_IFREG | S_IRUGO, root,
|
||||
adev,
|
||||
ttm_debugfs_entries[count].fops);
|
||||
if (IS_ERR(ent))
|
||||
return PTR_ERR(ent);
|
||||
if (ttm_debugfs_entries[count].domain == TTM_PL_VRAM)
|
||||
i_size_write(ent->d_inode, adev->gmc.mc_vram_size);
|
||||
else if (ttm_debugfs_entries[count].domain == TTM_PL_TT)
|
||||
i_size_write(ent->d_inode, adev->gmc.gart_size);
|
||||
adev->mman.debugfs_entries[count] = ent;
|
||||
}
|
||||
|
||||
count = ARRAY_SIZE(amdgpu_ttm_debugfs_list);
|
||||
return amdgpu_debugfs_add_files(adev, amdgpu_ttm_debugfs_list, count);
|
||||
#else
|
||||
return 0;
|
||||
debugfs_create_file_size("amdgpu_vram", 0444, root, adev,
|
||||
&amdgpu_ttm_vram_fops, adev->gmc.mc_vram_size);
|
||||
debugfs_create_file("amdgpu_iomem", 0444, root, adev,
|
||||
&amdgpu_ttm_iomem_fops);
|
||||
debugfs_create_file("amdgpu_vram_mm", 0444, root, adev,
|
||||
&amdgpu_mm_vram_table_fops);
|
||||
debugfs_create_file("amdgpu_gtt_mm", 0444, root, adev,
|
||||
&amdgpu_mm_tt_table_fops);
|
||||
debugfs_create_file("amdgpu_gds_mm", 0444, root, adev,
|
||||
&amdgpu_mm_gds_table_fops);
|
||||
debugfs_create_file("amdgpu_gws_mm", 0444, root, adev,
|
||||
&amdgpu_mm_gws_table_fops);
|
||||
debugfs_create_file("amdgpu_oa_mm", 0444, root, adev,
|
||||
&amdgpu_mm_oa_table_fops);
|
||||
debugfs_create_file("ttm_page_pool", 0444, root, adev,
|
||||
&amdgpu_ttm_page_pool_fops);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -60,14 +60,10 @@ struct amdgpu_gtt_mgr {
|
|||
};
|
||||
|
||||
struct amdgpu_mman {
|
||||
struct ttm_bo_device bdev;
|
||||
struct ttm_device bdev;
|
||||
bool initialized;
|
||||
void __iomem *aper_base_kaddr;
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
struct dentry *debugfs_entries[8];
|
||||
#endif
|
||||
|
||||
/* buffer handling */
|
||||
const struct amdgpu_buffer_funcs *buffer_funcs;
|
||||
struct amdgpu_ring *buffer_funcs_ring;
|
||||
|
@ -119,8 +115,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
|
|||
struct device *dev,
|
||||
enum dma_data_direction dir,
|
||||
struct sg_table **sgt);
|
||||
void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
|
||||
struct device *dev,
|
||||
void amdgpu_vram_mgr_free_sgt(struct device *dev,
|
||||
enum dma_data_direction dir,
|
||||
struct sg_table *sgt);
|
||||
uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man);
|
||||
|
@ -186,6 +181,6 @@ uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem);
|
|||
uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
|
||||
struct ttm_resource *mem);
|
||||
|
||||
int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
|
||||
void amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
|
||||
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue