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:
Linus Torvalds 2021-04-28 10:01:40 -07:00
commit 68a32ba141
1145 changed files with 182199 additions and 31506 deletions

View File

@ -591,6 +591,24 @@ For printing netdev_features_t.
Passed by reference. 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 Thanks
====== ======

View File

@ -12,8 +12,8 @@ description: |
and CEC. and CEC.
These DT bindings follow the Synopsys DWC HDMI TX bindings defined These DT bindings follow the Synopsys DWC HDMI TX bindings defined
in Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with in bridge/synopsys,dw-hdmi.yaml with the following device-specific
the following device-specific properties. properties.
maintainers: maintainers:
- Chen-Yu Tsai <wens@csie.org> - Chen-Yu Tsai <wens@csie.org>

View File

@ -109,7 +109,7 @@ required:
- resets - resets
- ddc - ddc
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |

View File

@ -34,6 +34,15 @@ properties:
description: used for reset chip control, RESET_N pin B7. description: used for reset chip control, RESET_N pin B7.
maxItems: 1 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: ports:
$ref: /schemas/graph.yaml#/properties/ports $ref: /schemas/graph.yaml#/properties/ports
@ -55,6 +64,9 @@ properties:
required: required:
- compatible - compatible
- reg - reg
- vdd10-supply
- vdd18-supply
- vdd33-supply
- ports - ports
additionalProperties: false additionalProperties: false
@ -72,6 +84,9 @@ examples:
reg = <0x58>; reg = <0x58>;
enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>; enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>;
reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>; reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>;
vdd10-supply = <&pp1000_mipibrdg>;
vdd18-supply = <&pp1800_mipibrdg>;
vdd33-supply = <&pp3300_mipibrdg>;
ports { ports {
#address-cells = <1>; #address-cells = <1>;

View File

@ -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>;
};
};
};
};
};

View File

@ -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.

View File

@ -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>;
};
};
};
};
};
...

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};
};
...

View File

@ -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
...

View File

@ -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>;
};
};
};
...

View File

@ -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>;
};
};
};
};
...

View File

@ -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>;
};
};
};

View File

@ -22,6 +22,7 @@ properties:
- mediatek,mt7623-dpi - mediatek,mt7623-dpi
- mediatek,mt8173-dpi - mediatek,mt8173-dpi
- mediatek,mt8183-dpi - mediatek,mt8183-dpi
- mediatek,mt8192-dpi
reg: reg:
maxItems: 1 maxItems: 1
@ -50,15 +51,10 @@ properties:
- const: sleep - const: sleep
port: port:
type: object $ref: /schemas/graph.yaml#/properties/port
description: description:
Output port node with endpoint definitions as described in Output port node. This port should be connected to the input port of an
Documentation/devicetree/bindings/graph.txt. This port should be connected attached HDMI or LVDS encoder chip.
to the input port of an attached HDMI or LVDS encoder chip.
properties:
endpoint:
type: object
required: required:
- compatible - compatible

View File

@ -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>;
};
};
};
};

View File

@ -161,6 +161,8 @@ properties:
# Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel # Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel
- innolux,g121x1-l03 - innolux,g121x1-l03
# Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel # Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
- innolux,n116bca-ea1
# Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
- innolux,n116bge - innolux,n116bge
# InnoLux 13.3" FHD (1920x1080) eDP TFT LCD panel # InnoLux 13.3" FHD (1920x1080) eDP TFT LCD panel
- innolux,n125hce-gn1 - innolux,n125hce-gn1

View File

@ -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 {
};
};
};
};

View File

@ -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>;
};
};
};
};
...

View File

@ -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>;
};
};
};
};

View File

@ -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>;
};
};
};
};
...

View File

@ -257,3 +257,79 @@ fences in the kernel. This means:
userspace is allowed to use userspace fencing or long running compute userspace is allowed to use userspace fencing or long running compute
workloads. This also means no implicit fencing for shared buffers in these workloads. This also means no implicit fencing for shared buffers in these
cases. 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.

View File

@ -80,6 +80,18 @@ Atomic State Helper Reference
.. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c .. kernel-doc:: drivers/gpu/drm/drm_atomic_state_helper.c
:export: :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 Simple KMS Helper Reference
=========================== ===========================

View File

@ -16,6 +16,7 @@ Linux GPU Driver Developer's Guide
vga-switcheroo vga-switcheroo
vgaarbiter vgaarbiter
todo todo
rfc/index
.. only:: subproject and html .. only:: subproject and html

View File

@ -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.

View File

@ -459,52 +459,6 @@ Contact: Emil Velikov, respective driver maintainers
Level: Intermediate 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 Use struct dma_buf_map throughout codebase
------------------------------------------ ------------------------------------------
@ -596,20 +550,24 @@ Contact: Daniel Vetter
Level: Intermediate 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 - Cleanup up the various ->destroy callbacks, which often are all the same
function tables in drivers, but before we can remove them we need to make sure simple code.
that all the users in helpers and drivers do correctly check for a NULL
vtable.
- Cleanup up the various ->destroy callbacks. A lot of them just wrapt the - Lots of drivers erroneously allocate DRM modeset objects using devm_kzalloc,
drm_*_cleanup implementations and can be removed. Some tack a kfree() at the which results in use-after free issues on driver unload. This can be serious
end, for which we could add drm_*_cleanup_kfree(). And then there's the (for trouble even for drivers for hardware integrated on the SoC due to
historical reasons) misnamed drm_primary_helper_destroy() function. 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 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 internship task, since it only requires a virtual machine and can be sized to
fit the available time. fit the available time.
Contact: Daniel Vetter
Level: See details Level: See details
Backlight Refactoring Backlight Refactoring
@ -721,7 +677,7 @@ Outside DRM
Convert fbdev drivers to 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 become obsolete, but some still provides good(-enough) framebuffers. The
drivers that are still useful should be converted to DRM and afterwards drivers that are still useful should be converted to DRM and afterwards
removed from fbdev. removed from fbdev.

View File

@ -1326,7 +1326,7 @@ ARC PGU DRM DRIVER
M: Alexey Brodkin <abrodkin@synopsys.com> M: Alexey Brodkin <abrodkin@synopsys.com>
S: Supported S: Supported
F: Documentation/devicetree/bindings/display/snps,arcpgu.txt F: Documentation/devicetree/bindings/display/snps,arcpgu.txt
F: drivers/gpu/drm/arc/ F: drivers/gpu/drm/tiny/arcpgu.c
ARCNET NETWORK LAYER ARCNET NETWORK LAYER
M: Michael Grzeschik <m.grzeschik@pengutronix.de> M: Michael Grzeschik <m.grzeschik@pengutronix.de>
@ -5641,6 +5641,12 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/boe,himax8279d.yaml F: Documentation/devicetree/bindings/display/panel/boe,himax8279d.yaml
F: drivers/gpu/drm/panel/panel-boe-himax8279d.c 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 DRM DRIVER FOR FARADAY TVE200 TV ENCODER
M: Linus Walleij <linus.walleij@linaro.org> M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained S: Maintained
@ -5659,6 +5665,14 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml
F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c 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 DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
M: Hans de Goede <hdegoede@redhat.com> M: Hans de Goede <hdegoede@redhat.com>
S: Maintained S: Maintained
@ -5967,6 +5981,7 @@ F: drivers/gpu/drm/atmel-hlcdc/
DRM DRIVERS FOR BRIDGE CHIPS DRM DRIVERS FOR BRIDGE CHIPS
M: Andrzej Hajda <a.hajda@samsung.com> M: Andrzej Hajda <a.hajda@samsung.com>
M: Neil Armstrong <narmstrong@baylibre.com> M: Neil Armstrong <narmstrong@baylibre.com>
M: Robert Foss <robert.foss@linaro.org>
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
R: Jonas Karlman <jonas@kwiboo.se> R: Jonas Karlman <jonas@kwiboo.se>
R: Jernej Skrabec <jernej.skrabec@siol.net> R: Jernej Skrabec <jernej.skrabec@siol.net>
@ -6036,6 +6051,7 @@ DRM DRIVERS FOR MEDIATEK
M: Chun-Kuang Hu <chunkuang.hu@kernel.org> M: Chun-Kuang Hu <chunkuang.hu@kernel.org>
M: Philipp Zabel <p.zabel@pengutronix.de> M: Philipp Zabel <p.zabel@pengutronix.de>
L: dri-devel@lists.freedesktop.org L: dri-devel@lists.freedesktop.org
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Supported S: Supported
F: Documentation/devicetree/bindings/display/mediatek/ F: Documentation/devicetree/bindings/display/mediatek/
F: drivers/gpu/drm/mediatek/ F: drivers/gpu/drm/mediatek/
@ -6061,9 +6077,9 @@ L: dri-devel@lists.freedesktop.org
L: linux-renesas-soc@vger.kernel.org L: linux-renesas-soc@vger.kernel.org
S: Supported S: Supported
T: git git://linuxtv.org/pinchartl/media drm/du/next 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/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/rcar-du/
F: drivers/gpu/drm/shmobile/ F: drivers/gpu/drm/shmobile/
F: include/linux/platform_data/shmob_drm.h 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 T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
F: drivers/hid/hid-lg-g15.c 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) LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
M: Sathya Prakash <sathya.prakash@broadcom.com> M: Sathya Prakash <sathya.prakash@broadcom.com>
M: Sreekanth Reddy <sreekanth.reddy@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 L: dri-devel@lists.freedesktop.org
S: Supported S: Supported
T: git git://anongit.freedesktop.org/drm/drm-misc 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/ F: drivers/gpu/drm/mxsfb/
MYLEX DAC960 PCI RAID Controller MYLEX DAC960 PCI RAID Controller

View File

@ -551,6 +551,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
INTEL_EHL_IDS(&gen11_early_ops), INTEL_EHL_IDS(&gen11_early_ops),
INTEL_TGL_12_IDS(&gen11_early_ops), INTEL_TGL_12_IDS(&gen11_early_ops),
INTEL_RKL_IDS(&gen11_early_ops), INTEL_RKL_IDS(&gen11_early_ops),
INTEL_ADLS_IDS(&gen11_early_ops),
}; };
struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0); struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);

View File

@ -8,6 +8,7 @@
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io.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); 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, struct clk *clk_register_mux_table(struct device *dev, const char *name,
const char * const *parent_names, u8 num_parents, const char * const *parent_names, u8 num_parents,
unsigned long flags, void __iomem *reg, u8 shift, u32 mask, unsigned long flags, void __iomem *reg, u8 shift, u32 mask,

View File

@ -123,7 +123,9 @@ static const struct dma_fence_ops dma_fence_stub_ops = {
/** /**
* dma_fence_get_stub - return a signaled fence * 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) 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); 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 * dma_fence_context_alloc - allocate an array of fence contexts
* @num: amount of contexts to allocate * @num: amount of contexts to allocate

View File

@ -202,6 +202,18 @@ void *dma_heap_get_drvdata(struct dma_heap *heap)
return heap->priv; 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 *dma_heap_add(const struct dma_heap_export_info *exp_info)
{ {
struct dma_heap *heap, *h, *err_ret; struct dma_heap *heap, *h, *err_ret;

View File

@ -339,6 +339,7 @@ static struct dma_buf *cma_heap_allocate(struct dma_heap *heap,
buffer->pagecount = pagecount; buffer->pagecount = pagecount;
/* create the dmabuf */ /* create the dmabuf */
exp_info.exp_name = dma_heap_get_name(heap);
exp_info.ops = &cma_heap_buf_ops; exp_info.ops = &cma_heap_buf_ops;
exp_info.size = buffer->len; exp_info.size = buffer->len;
exp_info.flags = fd_flags; exp_info.flags = fd_flags;

View File

@ -390,6 +390,7 @@ static struct dma_buf *system_heap_allocate(struct dma_heap *heap,
} }
/* create the dmabuf */ /* create the dmabuf */
exp_info.exp_name = dma_heap_get_name(heap);
exp_info.ops = &system_heap_buf_ops; exp_info.ops = &system_heap_buf_ops;
exp_info.size = buffer->len; exp_info.size = buffer->len;
exp_info.flags = fd_flags; exp_info.flags = fd_flags;

View File

@ -352,8 +352,6 @@ source "drivers/gpu/drm/vc4/Kconfig"
source "drivers/gpu/drm/etnaviv/Kconfig" source "drivers/gpu/drm/etnaviv/Kconfig"
source "drivers/gpu/drm/arc/Kconfig"
source "drivers/gpu/drm/hisilicon/Kconfig" source "drivers/gpu/drm/hisilicon/Kconfig"
source "drivers/gpu/drm/mediatek/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/xlnx/Kconfig"
source "drivers/gpu/drm/gud/Kconfig"
# Keep legacy drivers last # Keep legacy drivers last
menuconfig DRM_LEGACY menuconfig DRM_LEGACY

View File

@ -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_file.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_drv.o \ drm_drv.o \
drm_sysfs.o drm_hashtab.o drm_mm.o \ drm_sysfs.o drm_hashtab.o drm_mm.o \
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_encoder_slave.o \
drm_trace_points.o drm_prime.o \ drm_trace_points.o drm_prime.o \
drm_rect.o drm_vma_manager.o drm_flip_work.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_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
drm_simple_kms_helper.o drm_modeset_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_atomic_state_helper.o drm_damage_helper.o \
drm_format_helper.o drm_self_refresh_helper.o drm_format_helper.o drm_self_refresh_helper.o
@ -110,7 +111,6 @@ obj-y += panel/
obj-y += bridge/ obj-y += bridge/
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/ obj-y += hisilicon/
obj-$(CONFIG_DRM_ZTE) += zte/ obj-$(CONFIG_DRM_ZTE) += zte/
obj-$(CONFIG_DRM_MXSFB) += mxsfb/ obj-$(CONFIG_DRM_MXSFB) += mxsfb/
@ -125,3 +125,4 @@ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
obj-$(CONFIG_DRM_MCDE) += mcde/ obj-$(CONFIG_DRM_MCDE) += mcde/
obj-$(CONFIG_DRM_TIDSS) += tidss/ obj-$(CONFIG_DRM_TIDSS) += tidss/
obj-y += xlnx/ obj-y += xlnx/
obj-y += gud/

View File

@ -34,15 +34,6 @@ config DRM_AMDGPU_USERPTR
This option selects CONFIG_HMM and CONFIG_HMM_MIRROR if it This option selects CONFIG_HMM and CONFIG_HMM_MIRROR if it
isn't already selected to enabled full userptr support. 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/acp/Kconfig"
source "drivers/gpu/drm/amd/display/Kconfig" source "drivers/gpu/drm/amd/display/Kconfig"
source "drivers/gpu/drm/amd/amdkfd/Kconfig" source "drivers/gpu/drm/amd/amdkfd/Kconfig"

View File

@ -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 \ vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \
vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o navi14_reg_init.o \ vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o navi10_reg_init.o navi14_reg_init.o \
arct_reg_init.o navi12_reg_init.o mxgpu_nv.o sienna_cichlid_reg_init.o vangogh_reg_init.o \ arct_reg_init.o navi12_reg_init.o mxgpu_nv.o sienna_cichlid_reg_init.o vangogh_reg_init.o \
nbio_v7_2.o dimgrey_cavefish_reg_init.o hdp_v4_0.o hdp_v5_0.o 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 # add DF block
amdgpu-y += \ amdgpu-y += \
@ -83,11 +83,12 @@ amdgpu-y += \
gmc_v7_0.o \ gmc_v7_0.o \
gmc_v8_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_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 # add UMC block
amdgpu-y += \ 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 # add IH block
amdgpu-y += \ amdgpu-y += \
@ -106,7 +107,8 @@ amdgpu-y += \
psp_v3_1.o \ psp_v3_1.o \
psp_v10_0.o \ psp_v10_0.o \
psp_v11_0.o \ psp_v11_0.o \
psp_v12_0.o psp_v12_0.o \
psp_v13_0.o
# add DCE block # add DCE block
amdgpu-y += \ amdgpu-y += \
@ -121,6 +123,7 @@ amdgpu-y += \
gfx_v8_0.o \ gfx_v8_0.o \
gfx_v9_0.o \ gfx_v9_0.o \
gfx_v9_4.o \ gfx_v9_4.o \
gfx_v9_4_2.o \
gfx_v10_0.o gfx_v10_0.o
# add async DMA block # add async DMA block
@ -129,6 +132,7 @@ amdgpu-y += \
sdma_v2_4.o \ sdma_v2_4.o \
sdma_v3_0.o \ sdma_v3_0.o \
sdma_v4_0.o \ sdma_v4_0.o \
sdma_v4_4.o \
sdma_v5_0.o \ sdma_v5_0.o \
sdma_v5_2.o sdma_v5_2.o
@ -172,11 +176,17 @@ amdgpu-y += \
amdgpu-y += \ amdgpu-y += \
smuio_v9_0.o \ smuio_v9_0.o \
smuio_v11_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 # add amdkfd interfaces
amdgpu-y += amdgpu_amdkfd.o amdgpu-y += amdgpu_amdkfd.o
ifneq ($(CONFIG_HSA_AMD),) ifneq ($(CONFIG_HSA_AMD),)
AMDKFD_PATH := ../amdkfd AMDKFD_PATH := ../amdkfd
include $(FULL_AMD_PATH)/amdkfd/Makefile include $(FULL_AMD_PATH)/amdkfd/Makefile
@ -187,6 +197,7 @@ amdgpu-y += \
amdgpu_amdkfd_gfx_v8.o \ amdgpu_amdkfd_gfx_v8.o \
amdgpu_amdkfd_gfx_v9.o \ amdgpu_amdkfd_gfx_v9.o \
amdgpu_amdkfd_arcturus.o \ amdgpu_amdkfd_arcturus.o \
amdgpu_amdkfd_aldebaran.o \
amdgpu_amdkfd_gfx_v10.o \ amdgpu_amdkfd_gfx_v10.o \
amdgpu_amdkfd_gfx_v10_3.o amdgpu_amdkfd_gfx_v10_3.o

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -107,7 +107,6 @@
#include "amdgpu_gfxhub.h" #include "amdgpu_gfxhub.h"
#include "amdgpu_df.h" #include "amdgpu_df.h"
#include "amdgpu_smuio.h" #include "amdgpu_smuio.h"
#include "amdgpu_hdp.h"
#define MAX_GPU_INSTANCE 16 #define MAX_GPU_INSTANCE 16
@ -124,6 +123,16 @@ struct amdgpu_mgpu_info
uint32_t num_gpu; uint32_t num_gpu;
uint32_t num_dgpu; uint32_t num_dgpu;
uint32_t num_apu; 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 #define AMDGPU_MAX_TIMEOUT_PARAM_LENGTH 256
@ -177,7 +186,9 @@ extern int amdgpu_compute_multipipe;
extern int amdgpu_gpu_recovery; extern int amdgpu_gpu_recovery;
extern int amdgpu_emu_mode; extern int amdgpu_emu_mode;
extern uint amdgpu_smu_memory_pool_size; extern uint amdgpu_smu_memory_pool_size;
extern int amdgpu_smu_pptable_id;
extern uint amdgpu_dc_feature_mask; extern uint amdgpu_dc_feature_mask;
extern uint amdgpu_freesync_vid_mode;
extern uint amdgpu_dc_debug_mask; extern uint amdgpu_dc_debug_mask;
extern uint amdgpu_dm_abm_level; extern uint amdgpu_dm_abm_level;
extern int amdgpu_backlight; extern int amdgpu_backlight;
@ -185,6 +196,7 @@ extern struct amdgpu_mgpu_info mgpu_info;
extern int amdgpu_ras_enable; extern int amdgpu_ras_enable;
extern uint amdgpu_ras_mask; extern uint amdgpu_ras_mask;
extern int amdgpu_bad_page_threshold; extern int amdgpu_bad_page_threshold;
extern struct amdgpu_watchdog_timer amdgpu_watchdog_timer;
extern int amdgpu_async_gfx_ring; extern int amdgpu_async_gfx_ring;
extern int amdgpu_mcbp; extern int amdgpu_mcbp;
extern int amdgpu_discovery; extern int amdgpu_discovery;
@ -258,6 +270,8 @@ struct amdgpu_bo_va_mapping;
struct amdgpu_atif; struct amdgpu_atif;
struct kfd_vm_fault_info; struct kfd_vm_fault_info;
struct amdgpu_hive_info; struct amdgpu_hive_info;
struct amdgpu_reset_context;
struct amdgpu_reset_control;
enum amdgpu_cp_irq { enum amdgpu_cp_irq {
AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0, AMDGPU_CP_IRQ_GFX_ME0_PIPE0_EOP = 0,
@ -576,6 +590,7 @@ struct amdgpu_allowed_register_entry {
}; };
enum amd_reset_method { enum amd_reset_method {
AMD_RESET_METHOD_NONE = -1,
AMD_RESET_METHOD_LEGACY = 0, AMD_RESET_METHOD_LEGACY = 0,
AMD_RESET_METHOD_MODE0, AMD_RESET_METHOD_MODE0,
AMD_RESET_METHOD_MODE1, AMD_RESET_METHOD_MODE1,
@ -584,6 +599,19 @@ enum amd_reset_method {
AMD_RESET_METHOD_PCI, 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. * ASIC specific functions.
*/ */
@ -628,6 +656,9 @@ struct amdgpu_asic_funcs {
void (*pre_asic_init)(struct amdgpu_device *adev); void (*pre_asic_init)(struct amdgpu_device *adev);
/* enter/exit umd stable pstate */ /* enter/exit umd stable pstate */
int (*update_umd_stable_pstate)(struct amdgpu_device *adev, bool enter); 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; bool accel_working;
struct notifier_block acpi_nb; struct notifier_block acpi_nb;
struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS]; struct amdgpu_i2c_chan *i2c_bus[AMDGPU_MAX_I2C_BUS];
struct amdgpu_debugfs debugfs[AMDGPU_DEBUGFS_MAX_COMPONENTS]; struct debugfs_blob_wrapper debugfs_vbios_blob;
unsigned debugfs_count;
#if defined(CONFIG_DEBUG_FS)
struct dentry *debugfs_preempt;
struct dentry *debugfs_regs[AMDGPU_DEBUGFS_MAX_COMPONENTS];
#endif
struct amdgpu_atif *atif; struct amdgpu_atif *atif;
struct amdgpu_atcs atcs; struct amdgpu_atcs atcs;
struct mutex srbm_mutex; struct mutex srbm_mutex;
@ -853,8 +879,6 @@ struct amdgpu_device {
spinlock_t audio_endpt_idx_lock; spinlock_t audio_endpt_idx_lock;
amdgpu_block_rreg_t audio_endpt_rreg; amdgpu_block_rreg_t audio_endpt_rreg;
amdgpu_block_wreg_t audio_endpt_wreg; amdgpu_block_wreg_t audio_endpt_wreg;
void __iomem *rio_mem;
resource_size_t rio_mem_size;
struct amdgpu_doorbell doorbell; struct amdgpu_doorbell doorbell;
/* clock/pll info */ /* clock/pll info */
@ -897,6 +921,8 @@ struct amdgpu_device {
struct amdgpu_irq_src vupdate_irq; struct amdgpu_irq_src vupdate_irq;
struct amdgpu_irq_src pageflip_irq; struct amdgpu_irq_src pageflip_irq;
struct amdgpu_irq_src hpd_irq; struct amdgpu_irq_src hpd_irq;
struct amdgpu_irq_src dmub_trace_irq;
struct amdgpu_irq_src dmub_outbox_irq;
/* rings */ /* rings */
u64 fence_context; u64 fence_context;
@ -1020,6 +1046,7 @@ struct amdgpu_device {
int asic_reset_res; int asic_reset_res;
struct work_struct xgmi_reset_work; struct work_struct xgmi_reset_work;
struct list_head reset_list;
long gfx_timeout; long gfx_timeout;
long sdma_timeout; long sdma_timeout;
@ -1050,6 +1077,8 @@ struct amdgpu_device {
bool in_pci_err_recovery; bool in_pci_err_recovery;
struct pci_saved_state *pci_state; struct pci_saved_state *pci_state;
struct amdgpu_reset_control *reset_cntl;
}; };
static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev) 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; 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); 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); 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); 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 amdgpu_device_indirect_rreg(struct amdgpu_device *adev,
u32 pcie_index, u32 pcie_data, u32 pcie_index, u32 pcie_data,
u32 reg_addr); 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_asic_has_dc_support(enum amd_asic_type asic_type);
bool amdgpu_device_has_dc_support(struct amdgpu_device *adev); 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); int emu_soc_asic_init(struct amdgpu_device *adev);
/* /*
@ -1168,8 +1200,6 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
} while (0) } while (0)
#define DREG32_SYS(sqf, adev, reg) seq_printf((sqf), #reg " : 0x%08X\n", amdgpu_device_rreg((adev), (reg), false)) #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_SHIFT(reg, field) reg##__##field##__SHIFT
#define REG_FIELD_MASK(reg, field) reg##__##field##_MASK #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_pre_asic_init(adev) (adev)->asic_funcs->pre_asic_init((adev))
#define amdgpu_asic_update_umd_stable_pstate(adev, enter) \ #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) ((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)); #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 *registers,
const u32 array_size); 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_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_boco(struct drm_device *dev);
bool amdgpu_device_supports_baco(struct drm_device *dev); bool amdgpu_device_supports_baco(struct drm_device *dev);
bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev,
@ -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_cache_pci_state(struct pci_dev *pdev);
bool amdgpu_device_load_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" #include "amdgpu_object.h"
static inline bool amdgpu_is_tmz(struct amdgpu_device *adev) static inline bool amdgpu_is_tmz(struct amdgpu_device *adev)

View File

@ -44,7 +44,7 @@ int amdgpu_amdkfd_init(void)
int ret; int ret;
si_meminfo(&si); 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; amdgpu_amdkfd_total_mem_size *= si.mem_unit;
ret = kgd2kfd_init(); ret = kgd2kfd_init();
@ -165,7 +165,8 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
adev->doorbell_index.last_non_cp; 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.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC;
bp.type = ttm_bo_type_kernel; bp.type = ttm_bo_type_kernel;
bp.resv = NULL; bp.resv = NULL;
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
if (cp_mqd_gfx9) if (cp_mqd_gfx9)
bp.flags |= AMDGPU_GEM_CREATE_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_device *adev = (struct amdgpu_device *)kgd;
struct amdgpu_bo *bo = NULL; struct amdgpu_bo *bo = NULL;
struct amdgpu_bo_user *ubo;
struct amdgpu_bo_param bp; struct amdgpu_bo_param bp;
int r; 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.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
bp.type = ttm_bo_type_device; bp.type = ttm_bo_type_device;
bp.resv = NULL; 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) { if (r) {
dev_err(adev->dev, dev_err(adev->dev,
"failed to allocate gws BO for amdkfd (%d)\n", r); "failed to allocate gws BO for amdkfd (%d)\n", r);
return r; return r;
} }
bo = &ubo->bo;
*mem_obj = bo; *mem_obj = bo;
return 0; 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; *dma_buf_kgd = (struct kgd_dev *)adev;
if (bo_size) if (bo_size)
*bo_size = amdgpu_bo_size(bo); *bo_size = amdgpu_bo_size(bo);
if (metadata_size)
*metadata_size = bo->metadata_size;
if (metadata_buffer) if (metadata_buffer)
r = amdgpu_bo_get_metadata(bo, metadata_buffer, buffer_size, r = amdgpu_bo_get_metadata(bo, metadata_buffer, buffer_size,
metadata_size, &metadata_flags); 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; 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, amdgpu_dpm_switch_power_profile(adev,
PP_SMC_POWER_PROFILE_COMPUTE, PP_SMC_POWER_PROFILE_COMPUTE,
!idle); !idle);

View File

@ -80,6 +80,7 @@ struct amdgpu_amdkfd_fence {
struct amdgpu_kfd_dev { struct amdgpu_kfd_dev {
struct kfd_dev *dev; struct kfd_dev *dev;
uint64_t vram_used; uint64_t vram_used;
bool init_complete;
}; };
enum kgd_engine_type { enum kgd_engine_type {

View File

@ -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,
};

View File

@ -122,7 +122,7 @@ static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
return sdma_rlc_reg_offset; 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) uint32_t __user *wptr, struct mm_struct *mm)
{ {
struct amdgpu_device *adev = get_amdgpu_device(kgd); 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; 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 engine_id, uint32_t queue_id,
uint32_t (**dump)[2], uint32_t *n_regs) uint32_t (**dump)[2], uint32_t *n_regs)
{ {
@ -224,7 +224,7 @@ static int kgd_hqd_sdma_dump(struct kgd_dev *kgd,
return 0; 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 amdgpu_device *adev = get_amdgpu_device(kgd);
struct v9_sdma_mqd *m; struct v9_sdma_mqd *m;
@ -243,7 +243,7 @@ static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
return false; 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) unsigned int utimeout)
{ {
struct amdgpu_device *adev = get_amdgpu_device(kgd); 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, .init_interrupts = kgd_gfx_v9_init_interrupts,
.hqd_load = kgd_gfx_v9_hqd_load, .hqd_load = kgd_gfx_v9_hqd_load,
.hiq_mqd_load = kgd_gfx_v9_hiq_mqd_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_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_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_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_disable = kgd_gfx_v9_address_watch_disable,
.address_watch_execute = kgd_gfx_v9_address_watch_execute, .address_watch_execute = kgd_gfx_v9_address_watch_execute,
.wave_control_execute = kgd_gfx_v9_wave_control_execute, .wave_control_execute = kgd_gfx_v9_wave_control_execute,

View File

@ -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);

View File

@ -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 * 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 * 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 * 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 * to process X. Otherwise, it will return true to indicate BO can be
* evicted by TTM. * 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 * the evcition process for that BO by calling ttm_bo_evict --> amdgpu_bo_move
* --> amdgpu_copy_buffer(). This sets up job in GPU scheduler. * --> amdgpu_copy_buffer(). This sets up job in GPU scheduler.
* *

View File

@ -31,6 +31,7 @@
#include "amdgpu_amdkfd.h" #include "amdgpu_amdkfd.h"
#include "amdgpu_dma_buf.h" #include "amdgpu_dma_buf.h"
#include <uapi/linux/kfd_ioctl.h> #include <uapi/linux/kfd_ioctl.h>
#include "amdgpu_xgmi.h"
/* BO flag to indicate a KFD userptr BO */ /* BO flag to indicate a KFD userptr BO */
#define AMDGPU_AMDKFD_USERPTR_BO (1ULL << 63) #define AMDGPU_AMDKFD_USERPTR_BO (1ULL << 63)
@ -96,7 +97,7 @@ void amdgpu_amdkfd_gpuvm_init_mem_limits(void)
uint64_t mem; uint64_t mem;
si_meminfo(&si); si_meminfo(&si);
mem = si.totalram - si.totalhigh; mem = si.freeram - si.freehigh;
mem *= si.mem_unit; mem *= si.mem_unit;
spin_lock_init(&kfd_mem_limit.mem_limit_lock); 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) #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, static int amdgpu_amdkfd_reserve_mem_limit(struct amdgpu_device *adev,
uint64_t size, u32 domain, bool sg) 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; size_t acc_size, system_mem_needed, ttm_mem_needed, vram_needed;
int ret = 0; int ret = 0;
acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size, acc_size = amdgpu_amdkfd_acc_size(size);
sizeof(struct amdgpu_bo));
vram_needed = 0; vram_needed = 0;
if (domain == AMDGPU_GEM_DOMAIN_GTT) { if (domain == AMDGPU_GEM_DOMAIN_GTT) {
@ -175,8 +185,7 @@ static void unreserve_mem_limit(struct amdgpu_device *adev,
{ {
size_t acc_size; size_t acc_size;
acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size, acc_size = amdgpu_amdkfd_acc_size(size);
sizeof(struct amdgpu_bo));
spin_lock(&kfd_mem_limit.mem_limit_lock); spin_lock(&kfd_mem_limit.mem_limit_lock);
if (domain == AMDGPU_GEM_DOMAIN_GTT) { 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); struct amdgpu_device *bo_adev = amdgpu_ttm_adev(mem->bo->tbo.bdev);
bool coherent = mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_COHERENT; 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; uint32_t mapping_flags;
uint64_t pte_flags;
bool snoop = false;
mapping_flags = AMDGPU_VM_PAGE_READABLE; mapping_flags = AMDGPU_VM_PAGE_READABLE;
if (mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE) 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; AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_NC;
} }
break; 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: default:
mapping_flags |= coherent ? mapping_flags |= coherent ?
AMDGPU_VM_MTYPE_UC : AMDGPU_VM_MTYPE_NC; 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 /* add_bo_to_vm - Add a BO to a VM

View File

@ -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); 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 { union voltage_object_info {
struct _ATOM_VOLTAGE_OBJECT_INFO v1; struct _ATOM_VOLTAGE_OBJECT_INFO v1;
struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2; 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; 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, static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) 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 amdgpu_device *adev = drm_to_adev(ddev);
struct atom_context *ctx = adev->mode_info.atom_context; 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, 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->dev = adev_to_drm(adev);
atom_card_info->reg_read = cail_reg_read; atom_card_info->reg_read = cail_reg_read;
atom_card_info->reg_write = cail_reg_write; 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_read = cail_mc_read;
atom_card_info->mc_write = cail_mc_write; atom_card_info->mc_write = cail_mc_write;
atom_card_info->pll_read = cail_pll_read; atom_card_info->pll_read = cail_pll_read;

View File

@ -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, void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev,
u32 eng_clock, u32 mem_clock); 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 bool
amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev, amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev,
u8 voltage_type, u8 voltage_mode); u8 voltage_type, u8 voltage_mode);

View File

@ -117,12 +117,15 @@ union igp_info {
union umc_info { union umc_info {
struct atom_umc_info_v3_1 v31; struct atom_umc_info_v3_1 v31;
struct atom_umc_info_v3_2 v32;
struct atom_umc_info_v3_3 v33;
}; };
union vram_info { union vram_info {
struct atom_vram_info_header_v2_3 v23; struct atom_vram_info_header_v2_3 v23;
struct atom_vram_info_header_v2_4 v24; struct atom_vram_info_header_v2_4 v24;
struct atom_vram_info_header_v2_5 v25; struct atom_vram_info_header_v2_5 v25;
struct atom_vram_info_header_v2_6 v26;
}; };
union vram_module { 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; vram_type = AMDGPU_VRAM_TYPE_GDDR5;
break; break;
case ATOM_DGPU_VRAM_TYPE_HBM2: case ATOM_DGPU_VRAM_TYPE_HBM2:
case ATOM_DGPU_VRAM_TYPE_HBM2E:
vram_type = AMDGPU_VRAM_TYPE_HBM; vram_type = AMDGPU_VRAM_TYPE_HBM;
break; break;
case ATOM_DGPU_VRAM_TYPE_GDDR6: case ATOM_DGPU_VRAM_TYPE_GDDR6:
@ -315,6 +319,26 @@ amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
if (vram_vendor) if (vram_vendor)
*vram_vendor = mem_vendor; *vram_vendor = mem_vendor;
break; 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: default:
return -EINVAL; return -EINVAL;
} }
@ -337,19 +361,39 @@ bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev)
union umc_info *umc_info; union umc_info *umc_info;
u8 frev, crev; u8 frev, crev;
bool ecc_default_enabled = false; 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, index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
umc_info); umc_info);
if (amdgpu_atom_parse_data_header(mode_info->atom_context, if (amdgpu_atom_parse_data_header(mode_info->atom_context,
index, &size, &frev, &crev, &data_offset)) { index, &size, &frev, &crev, &data_offset)) {
/* support umc_info 3.1+ */ if (frev == 3) {
if ((frev == 3 && crev >= 1) || (frev > 3)) {
umc_info = (union umc_info *) umc_info = (union umc_info *)
(mode_info->atom_context->bios + data_offset); (mode_info->atom_context->bios + data_offset);
ecc_default_enabled = switch (crev) {
(le32_to_cpu(umc_info->v31.umc_config) & case 1:
UMC_CONFIG__DEFAULT_MEM_ECC_ENABLE) ? true : false; 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 { 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) 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.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); adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v24.gc_lds_size);
return 0; 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: default:
return -EINVAL; return -EINVAL;
} }

View File

@ -85,6 +85,8 @@ static void amdgpu_benchmark_move(struct amdgpu_device *adev, unsigned size,
bp.flags = 0; bp.flags = 0;
bp.type = ttm_bo_type_kernel; bp.type = ttm_bo_type_kernel;
bp.resv = NULL; bp.resv = NULL;
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
n = AMDGPU_BENCHMARK_ITERATIONS; n = AMDGPU_BENCHMARK_ITERATIONS;
r = amdgpu_bo_create(adev, &bp, &sobj); r = amdgpu_bo_create(adev, &bp, &sobj);
if (r) { if (r) {

View File

@ -97,6 +97,10 @@ static bool igp_read_bios_from_vram(struct amdgpu_device *adev)
if (amdgpu_device_need_post(adev)) if (amdgpu_device_need_post(adev))
return false; return false;
/* FB BAR not enabled */
if (pci_resource_len(adev->pdev, 0) == 0)
return false;
adev->bios = NULL; adev->bios = NULL;
vram_base = pci_resource_start(adev->pdev, 0); vram_base = pci_resource_start(adev->pdev, 0);
bios = ioremap_wc(vram_base, size); 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); adev->bios = kmalloc(size, GFP_KERNEL);
if (!adev->bios) { if (!adev->bios) {
DRM_ERROR("Unable to allocate bios\n"); dev_err(adev->dev, "Unable to allocate bios\n");
return false; return false;
} }
@ -364,7 +368,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
return false; return false;
tbl_size = hdr->length; tbl_size = hdr->length;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { 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; return false;
} }
@ -377,13 +381,13 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
offset += sizeof(VFCT_IMAGE_HEADER); offset += sizeof(VFCT_IMAGE_HEADER);
if (offset > tbl_size) { 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; return false;
} }
offset += vhdr->ImageLength; offset += vhdr->ImageLength;
if (offset > tbl_size) { if (offset > tbl_size) {
DRM_ERROR("ACPI VFCT image truncated\n"); dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n");
return false; 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; return false;
} }
#else #else
@ -453,7 +457,7 @@ bool amdgpu_get_bios(struct amdgpu_device *adev)
goto success; goto success;
} }
DRM_ERROR("Unable to locate a BIOS ROM\n"); dev_err(adev->dev, "Unable to locate a BIOS ROM\n");
return false; return false;
success: success:

View File

@ -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) if (cs->in.num_chunks == 0)
return 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) if (!chunk_array)
return -ENOMEM; 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->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); GFP_KERNEL);
if (!p->chunks) { if (!p->chunks) {
ret = -ENOMEM; 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) if (p->uf_entry.tv.bo)
p->job->uf_addr = uf_offset; p->job->uf_addr = uf_offset;
kfree(chunk_array); kvfree(chunk_array);
/* Use this opportunity to fill in task info for the vm */ /* Use this opportunity to fill in task info for the vm */
amdgpu_vm_set_task_info(vm); amdgpu_vm_set_task_info(vm);
@ -250,11 +250,11 @@ free_all_kdata:
free_partial_kdata: free_partial_kdata:
for (; i >= 0; i--) for (; i >= 0; i--)
kvfree(p->chunks[i].kdata); kvfree(p->chunks[i].kdata);
kfree(p->chunks); kvfree(p->chunks);
p->chunks = NULL; p->chunks = NULL;
p->nchunks = 0; p->nchunks = 0;
free_chunk: free_chunk:
kfree(chunk_array); kvfree(chunk_array);
return ret; return ret;
} }
@ -559,7 +559,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
sizeof(struct page *), sizeof(struct page *),
GFP_KERNEL | __GFP_ZERO); GFP_KERNEL | __GFP_ZERO);
if (!e->user_pages) { if (!e->user_pages) {
DRM_ERROR("calloc failure\n"); DRM_ERROR("kvmalloc_array failure\n");
return -ENOMEM; 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++) for (i = 0; i < parser->nchunks; i++)
kvfree(parser->chunks[i].kdata); kvfree(parser->chunks[i].kdata);
kfree(parser->chunks); kvfree(parser->chunks);
if (parser->job) if (parser->job)
amdgpu_job_free(parser->job); amdgpu_job_free(parser->job);
if (parser->uf_entry.tv.bo) { if (parser->uf_entry.tv.bo) {

View File

@ -28,7 +28,6 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <drm/drm_debugfs.h>
#include "amdgpu.h" #include "amdgpu.h"
#include "amdgpu_pm.h" #include "amdgpu_pm.h"
@ -38,45 +37,6 @@
#include "amdgpu_securedisplay.h" #include "amdgpu_securedisplay.h"
#include "amdgpu_fw_attestation.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) int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev)
{ {
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
@ -1228,22 +1188,20 @@ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev)
adev, debugfs_regs[i]); adev, debugfs_regs[i]);
if (!i && !IS_ERR_OR_NULL(ent)) if (!i && !IS_ERR_OR_NULL(ent))
i_size_write(ent->d_inode, adev->rmmio_size); i_size_write(ent->d_inode, adev->rmmio_size);
adev->debugfs_regs[i] = ent;
} }
return 0; 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 amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = adev_to_drm(adev);
struct amdgpu_device *adev = drm_to_adev(dev);
int r = 0, i; int r = 0, i;
r = pm_runtime_get_sync(dev->dev); r = pm_runtime_get_sync(dev->dev);
if (r < 0) { if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(dev->dev);
return r; return r;
} }
@ -1285,30 +1243,19 @@ static int amdgpu_debugfs_test_ib(struct seq_file *m, void *data)
return 0; 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 amdgpu_device *adev = (struct amdgpu_device *)data;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = adev_to_drm(adev);
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);
int r; int r;
r = pm_runtime_get_sync(dev->dev); r = pm_runtime_get_sync(dev->dev);
if (r < 0) { if (r < 0) {
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(dev->dev);
return r; 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_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(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; 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 amdgpu_device *adev = (struct amdgpu_device *)data;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = adev_to_drm(adev);
struct amdgpu_device *adev = drm_to_adev(dev);
struct ttm_resource_manager *man; struct ttm_resource_manager *man;
int r; 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); man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
r = ttm_resource_manager_evict_all(&adev->mman.bdev, man); *val = ttm_resource_manager_evict_all(&adev->mman.bdev, man);
seq_printf(m, "(%d)\n", r);
pm_runtime_mark_last_busy(dev->dev); pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev); pm_runtime_put_autosuspend(dev->dev);
@ -1340,10 +1286,11 @@ static int amdgpu_debugfs_evict_gtt(struct seq_file *m, void *data)
return 0; 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 amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = adev_to_drm(adev);
struct drm_file *file; struct drm_file *file;
int r; int r;
@ -1369,13 +1316,12 @@ static int amdgpu_debugfs_vm_info(struct seq_file *m, void *data)
return r; return r;
} }
static const struct drm_info_list amdgpu_debugfs_list[] = { DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_test_ib);
{"amdgpu_vbios", amdgpu_debugfs_get_vbios_dump}, DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_vm_info);
{"amdgpu_test_ib", &amdgpu_debugfs_test_ib}, DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_evict_vram_fops, amdgpu_debugfs_evict_vram,
{"amdgpu_evict_vram", &amdgpu_debugfs_evict_vram}, NULL, "%lld\n");
{"amdgpu_evict_gtt", &amdgpu_debugfs_evict_gtt}, DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_evict_gtt_fops, amdgpu_debugfs_evict_gtt,
{"amdgpu_vm_info", &amdgpu_debugfs_vm_info}, NULL, "%lld\n");
};
static void amdgpu_ib_preempt_fences_swap(struct amdgpu_ring *ring, static void amdgpu_ib_preempt_fences_swap(struct amdgpu_ring *ring,
struct dma_fence **fences) struct dma_fence **fences)
@ -1586,71 +1532,50 @@ static int amdgpu_debugfs_sclk_set(void *data, u64 val)
return 0; return 0;
} }
DEFINE_SIMPLE_ATTRIBUTE(fops_ib_preempt, NULL, DEFINE_DEBUGFS_ATTRIBUTE(fops_ib_preempt, NULL,
amdgpu_debugfs_ib_preempt, "%llu\n"); 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"); amdgpu_debugfs_sclk_set, "%llu\n");
int amdgpu_debugfs_init(struct amdgpu_device *adev) int amdgpu_debugfs_init(struct amdgpu_device *adev)
{ {
struct dentry *root = adev_to_drm(adev)->primary->debugfs_root;
struct dentry *ent;
int r, i; int r, i;
adev->debugfs_preempt =
debugfs_create_file("amdgpu_preempt_ib", 0600,
adev_to_drm(adev)->primary->debugfs_root, adev, ent = debugfs_create_file("amdgpu_preempt_ib", 0600, root, adev,
&fops_ib_preempt); &fops_ib_preempt);
if (!(adev->debugfs_preempt)) { if (!ent) {
DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n"); DRM_ERROR("unable to create amdgpu_preempt_ib debugsfs file\n");
return -EIO; return -EIO;
} }
adev->smu.debugfs_sclk = ent = debugfs_create_file("amdgpu_force_sclk", 0200, root, adev,
debugfs_create_file("amdgpu_force_sclk", 0200, &fops_sclk_set);
adev_to_drm(adev)->primary->debugfs_root, adev, if (!ent) {
&fops_sclk_set);
if (!(adev->smu.debugfs_sclk)) {
DRM_ERROR("unable to create amdgpu_set_sclk debugsfs file\n"); DRM_ERROR("unable to create amdgpu_set_sclk debugsfs file\n");
return -EIO; return -EIO;
} }
/* Register debugfs entries for amdgpu_ttm */ /* Register debugfs entries for amdgpu_ttm */
r = amdgpu_ttm_debugfs_init(adev); amdgpu_ttm_debugfs_init(adev);
if (r) { amdgpu_debugfs_pm_init(adev);
DRM_ERROR("Failed to init debugfs\n"); amdgpu_debugfs_sa_init(adev);
return r; amdgpu_debugfs_fence_init(adev);
} amdgpu_debugfs_gem_init(adev);
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);
r = amdgpu_debugfs_regs_init(adev); r = amdgpu_debugfs_regs_init(adev);
if (r) if (r)
DRM_ERROR("registering register debugfs failed (%d).\n", r); DRM_ERROR("registering register debugfs failed (%d).\n", r);
r = amdgpu_debugfs_firmware_init(adev); amdgpu_debugfs_firmware_init(adev);
if (r)
DRM_ERROR("registering firmware debugfs failed (%d).\n", r);
#if defined(CONFIG_DRM_AMD_DC) #if defined(CONFIG_DRM_AMD_DC)
if (amdgpu_device_has_dc_support(adev)) { if (amdgpu_device_has_dc_support(adev))
if (dtn_debugfs_init(adev)) dtn_debugfs_init(adev);
DRM_ERROR("amdgpu: failed initialize dtn debugfs support.\n");
}
#endif #endif
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 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_ras_debugfs_create_all(adev);
amdgpu_debugfs_autodump_init(adev); amdgpu_debugfs_autodump_init(adev);
amdgpu_rap_debugfs_init(adev); amdgpu_rap_debugfs_init(adev);
amdgpu_securedisplay_debugfs_init(adev); amdgpu_securedisplay_debugfs_init(adev);
amdgpu_fw_attestation_debugfs_init(adev); amdgpu_fw_attestation_debugfs_init(adev);
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_list, debugfs_create_file("amdgpu_evict_vram", 0444, root, adev,
ARRAY_SIZE(amdgpu_debugfs_list)); &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 #else

View File

@ -26,11 +26,6 @@
/* /*
* Debugfs * Debugfs
*/ */
struct amdgpu_debugfs {
const struct drm_info_list *files;
unsigned num_files;
};
struct amdgpu_autodump { struct amdgpu_autodump {
struct completion dumping; struct completion dumping;
struct wait_queue_head gpu_hang; 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_regs_init(struct amdgpu_device *adev);
int amdgpu_debugfs_init(struct amdgpu_device *adev); int amdgpu_debugfs_init(struct amdgpu_device *adev);
void amdgpu_debugfs_fini(struct amdgpu_device *adev); void amdgpu_debugfs_fini(struct amdgpu_device *adev);
int amdgpu_debugfs_add_files(struct amdgpu_device *adev, void amdgpu_debugfs_fence_init(struct amdgpu_device *adev);
const struct drm_info_list *files, void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev);
unsigned nfiles); void amdgpu_debugfs_gem_init(struct amdgpu_device *adev);
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);
int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev); int amdgpu_debugfs_wait_dump(struct amdgpu_device *adev);

File diff suppressed because it is too large Load Diff

View File

@ -870,17 +870,62 @@ static int amdgpu_display_get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb
return r; 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, int amdgpu_display_framebuffer_init(struct drm_device *dev,
struct amdgpu_framebuffer *rfb, struct amdgpu_framebuffer *rfb,
const struct drm_mode_fb_cmd2 *mode_cmd, const struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj) struct drm_gem_object *obj)
{ {
int ret, i; 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 * 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", drm_dbg_kms(dev, "Plane 0 and %d have different BOs: %u vs. %u\n",
i, mode_cmd->handles[0], mode_cmd->handles[i]); i, mode_cmd->handles[0], mode_cmd->handles[i]);
ret = -EINVAL; ret = -EINVAL;
goto fail; return ret;
} }
} }
ret = amdgpu_display_get_fb_info(rfb, &rfb->tiling_flags, &rfb->tmz_surface); ret = amdgpu_display_get_fb_info(rfb, &rfb->tiling_flags, &rfb->tmz_surface);
if (ret) if (ret)
goto fail; return ret;
if (dev->mode_config.allow_fb_modifiers && if (dev->mode_config.allow_fb_modifiers &&
!(rfb->base.flags & DRM_MODE_FB_MODIFIERS)) { !(rfb->base.flags & DRM_MODE_FB_MODIFIERS)) {
@ -905,20 +950,17 @@ int amdgpu_display_framebuffer_init(struct drm_device *dev,
if (ret) { if (ret) {
drm_dbg_kms(dev, "Failed to convert tiling flags 0x%llX to a modifier", drm_dbg_kms(dev, "Failed to convert tiling flags 0x%llX to a modifier",
rfb->tiling_flags); rfb->tiling_flags);
goto fail; return ret;
} }
} }
for (i = 1; i < rfb->base.format->num_planes; ++i) { 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]; rfb->base.obj[i] = rfb->base.obj[0];
drm_gem_object_get(rfb->base.obj[i]);
} }
return 0; return 0;
fail:
rfb->base.obj[0] = NULL;
return ret;
} }
struct drm_framebuffer * struct drm_framebuffer *
@ -953,13 +995,15 @@ amdgpu_display_user_framebuffer_create(struct drm_device *dev,
return ERR_PTR(-ENOMEM); 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) { if (ret) {
kfree(amdgpu_fb); kfree(amdgpu_fb);
drm_gem_object_put(obj); drm_gem_object_put(obj);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
drm_gem_object_put(obj);
return &amdgpu_fb->base; return &amdgpu_fb->base;
} }

View File

@ -321,17 +321,12 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach,
struct sg_table *sgt, struct sg_table *sgt,
enum dma_data_direction dir) 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) { if (sgt->sgl->page_link) {
dma_unmap_sgtable(attach->dev, sgt, dir, 0); dma_unmap_sgtable(attach->dev, sgt, dir, 0);
sg_free_table(sgt); sg_free_table(sgt);
kfree(sgt); kfree(sgt);
} else { } 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 dma_resv *resv = dma_buf->resv;
struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_bo *bo;
struct amdgpu_bo_param bp;
struct drm_gem_object *gobj; struct drm_gem_object *gobj;
struct amdgpu_bo *bo;
uint64_t flags = 0;
int ret; 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); 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, ret = amdgpu_gem_object_create(adev, dma_buf->size, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_CPU, AMDGPU_GEM_DOMAIN_CPU, flags,
0, ttm_bo_type_sg, resv, &gobj); ttm_bo_type_sg, resv, &gobj);
if (ret) if (ret)
goto error; goto error;

View File

@ -36,6 +36,7 @@
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/suspend.h>
#include "amdgpu.h" #include "amdgpu.h"
#include "amdgpu_irq.h" #include "amdgpu_irq.h"
@ -45,6 +46,8 @@
#include "amdgpu_amdkfd.h" #include "amdgpu_amdkfd.h"
#include "amdgpu_ras.h" #include "amdgpu_ras.h"
#include "amdgpu_xgmi.h"
#include "amdgpu_reset.h"
/* /*
* KMS wrapper. * KMS wrapper.
@ -90,9 +93,10 @@
* - 3.38.0 - Add AMDGPU_IB_FLAG_EMIT_MEM_SYNC * - 3.38.0 - Add AMDGPU_IB_FLAG_EMIT_MEM_SYNC
* - 3.39.0 - DMABUF implicit sync does a full pipeline sync * - 3.39.0 - DMABUF implicit sync does a full pipeline sync
* - 3.40.0 - Add AMDGPU_IDS_FLAGS_TMZ * - 3.40.0 - Add AMDGPU_IDS_FLAGS_TMZ
* - 3.41.0 - Add video codec query
*/ */
#define KMS_DRIVER_MAJOR 3 #define KMS_DRIVER_MAJOR 3
#define KMS_DRIVER_MINOR 40 #define KMS_DRIVER_MINOR 41
#define KMS_DRIVER_PATCHLEVEL 0 #define KMS_DRIVER_PATCHLEVEL 0
int amdgpu_vram_limit; int amdgpu_vram_limit;
@ -145,6 +149,7 @@ int amdgpu_compute_multipipe = -1;
int amdgpu_gpu_recovery = -1; /* auto */ int amdgpu_gpu_recovery = -1; /* auto */
int amdgpu_emu_mode; int amdgpu_emu_mode;
uint amdgpu_smu_memory_pool_size; uint amdgpu_smu_memory_pool_size;
int amdgpu_smu_pptable_id = -1;
/* /*
* FBC (bit 0) disabled by default * FBC (bit 0) disabled by default
* MULTI_MON_PP_MCLK_SWITCH (bit 1) enabled 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_mes;
int amdgpu_noretry = -1; int amdgpu_noretry = -1;
int amdgpu_force_asic_type = -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_reset_method = -1; /* auto */
int amdgpu_num_kcq = -1; int amdgpu_num_kcq = -1;
static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work);
struct amdgpu_mgpu_info mgpu_info = { struct amdgpu_mgpu_info mgpu_info = {
.mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), .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; int amdgpu_ras_enable = -1;
uint amdgpu_ras_mask = 0xffffffff; uint amdgpu_ras_mask = 0xffffffff;
int amdgpu_bad_page_threshold = -1; 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) * DOC: vramlimit (int)
@ -502,7 +517,7 @@ module_param_named(compute_multipipe, amdgpu_compute_multipipe, int, 0444);
* DOC: gpu_recovery (int) * DOC: gpu_recovery (int)
* Set to enable GPU recovery mechanism (1 = enable, 0 = disable). The default is -1 (auto, disabled except SRIOV). * 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); 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_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); 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) * 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, * 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_param(no_system_mem_limit, bool, 0644);
MODULE_PARM_DESC(no_system_mem_limit, "disable system memory limit (false = default)"); 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 #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. * 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); 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) * DOC: reset_method (int)
* GPU reset method (-1 = auto (default), 0 = legacy, 1 = mode0, 2 = mode1, 3 = mode2, 4 = baco, 5 = pci) * 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_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); 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[] = { static const struct pci_device_id pciidlist[] = {
#ifdef CONFIG_DRM_AMDGPU_SI #ifdef CONFIG_DRM_AMDGPU_SI
{0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI}, {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, 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}, {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} {0, 0, 0}
}; };
@ -1279,6 +1340,98 @@ amdgpu_pci_shutdown(struct pci_dev *pdev)
adev->mp1_state = PP_MP1_STATE_NONE; 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) static int amdgpu_pmops_suspend(struct device *dev)
{ {
struct drm_device *drm_dev = dev_get_drvdata(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; 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; drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
ret = amdgpu_device_suspend(drm_dev, false); ret = amdgpu_device_suspend(drm_dev, false);
@ -1373,16 +1526,14 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
return ret; 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 /* Only need to handle PCI state in the driver for ATPX
* PCI core handles it for _PR3. * PCI core handles it for _PR3.
*/ */
if (!amdgpu_is_atpx_hybrid()) { amdgpu_device_cache_pci_state(pdev);
amdgpu_device_cache_pci_state(pdev); pci_disable_device(pdev);
pci_disable_device(pdev); pci_ignore_hotplug(pdev);
pci_ignore_hotplug(pdev); pci_set_power_state(pdev, PCI_D3cold);
pci_set_power_state(pdev, PCI_D3cold);
}
drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF;
} else if (amdgpu_device_supports_baco(drm_dev)) { } else if (amdgpu_device_supports_baco(drm_dev)) {
amdgpu_device_baco_enter(drm_dev); amdgpu_device_baco_enter(drm_dev);
@ -1401,19 +1552,17 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
if (!adev->runpm) if (!adev->runpm)
return -EINVAL; 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; drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
/* Only need to handle PCI state in the driver for ATPX /* Only need to handle PCI state in the driver for ATPX
* PCI core handles it for _PR3. * PCI core handles it for _PR3.
*/ */
if (!amdgpu_is_atpx_hybrid()) { pci_set_power_state(pdev, PCI_D0);
pci_set_power_state(pdev, PCI_D0); amdgpu_device_load_pci_state(pdev);
amdgpu_device_load_pci_state(pdev); ret = pci_enable_device(pdev);
ret = pci_enable_device(pdev); if (ret)
if (ret) return ret;
return ret;
}
pci_set_master(pdev); pci_set_master(pdev);
} else if (amdgpu_device_supports_boco(drm_dev)) { } else if (amdgpu_device_supports_boco(drm_dev)) {
/* Only need to handle PCI state in the driver for ATPX /* 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); amdgpu_device_baco_exit(drm_dev);
} }
ret = amdgpu_device_resume(drm_dev, false); 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; drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
adev->in_runpm = false; adev->in_runpm = false;
return 0; return 0;
@ -1505,6 +1654,8 @@ out:
} }
static const struct dev_pm_ops amdgpu_pm_ops = { static const struct dev_pm_ops amdgpu_pm_ops = {
.prepare = amdgpu_pmops_prepare,
.complete = amdgpu_pmops_complete,
.suspend = amdgpu_pmops_suspend, .suspend = amdgpu_pmops_suspend,
.resume = amdgpu_pmops_resume, .resume = amdgpu_pmops_resume,
.freeze = amdgpu_pmops_freeze, .freeze = amdgpu_pmops_freeze,

View File

@ -232,8 +232,8 @@ static int amdgpufb_create(struct drm_fb_helper *helper,
goto out; goto out;
} }
ret = amdgpu_display_framebuffer_init(adev_to_drm(adev), &rfbdev->rfb, ret = amdgpu_display_gem_fb_init(adev_to_drm(adev), &rfbdev->rfb,
&mode_cmd, gobj); &mode_cmd, gobj);
if (ret) { if (ret) {
DRM_ERROR("failed to initialize framebuffer %d\n", ret); DRM_ERROR("failed to initialize framebuffer %d\n", ret);
goto out; goto out;

View File

@ -36,8 +36,6 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <drm/drm_debugfs.h>
#include "amdgpu.h" #include "amdgpu.h"
#include "amdgpu_trace.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(). * Helper function for amdgpu_fence_driver_init().
*/ */
int amdgpu_fence_driver_init_ring(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)
{ {
struct amdgpu_device *adev = ring->adev; struct amdgpu_device *adev = ring->adev;
long timeout; long timeout;
@ -469,30 +468,31 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring,
return -ENOMEM; return -ENOMEM;
/* No need to setup the GPU scheduler for rings that don't need it */ /* No need to setup the GPU scheduler for rings that don't need it */
if (!ring->no_scheduler) { if (ring->no_scheduler)
switch (ring->funcs->type) { return 0;
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, switch (ring->funcs->type) {
num_hw_submission, amdgpu_job_hang_limit, case AMDGPU_RING_TYPE_GFX:
timeout, ring->name); timeout = adev->gfx_timeout;
if (r) { break;
DRM_ERROR("Failed to create scheduler on ring %s.\n", case AMDGPU_RING_TYPE_COMPUTE:
ring->name); timeout = adev->compute_timeout;
return r; 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; return 0;
@ -533,6 +533,8 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
if (!ring || !ring->fence_drv.initialized) if (!ring || !ring->fence_drv.initialized)
continue; continue;
if (!ring->no_scheduler)
drm_sched_fini(&ring->sched);
r = amdgpu_fence_wait_empty(ring); r = amdgpu_fence_wait_empty(ring);
if (r) { if (r) {
/* no need to trigger GPU reset as we are unloading */ /* 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) if (ring->fence_drv.irq_src)
amdgpu_irq_put(adev, ring->fence_drv.irq_src, amdgpu_irq_put(adev, ring->fence_drv.irq_src,
ring->fence_drv.irq_type); ring->fence_drv.irq_type);
if (!ring->no_scheduler)
drm_sched_fini(&ring->sched);
del_timer_sync(&ring->fence_drv.fallback_timer); del_timer_sync(&ring->fence_drv.fallback_timer);
for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j) for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j)
dma_fence_put(ring->fence_drv.fences[j]); dma_fence_put(ring->fence_drv.fences[j]);
@ -697,11 +698,9 @@ static const struct dma_fence_ops amdgpu_fence_ops = {
* Fence debugfs * Fence debugfs
*/ */
#if defined(CONFIG_DEBUG_FS) #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 amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
int i; int i;
for (i = 0; i < AMDGPU_MAX_RINGS; ++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. * 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 amdgpu_device *adev = (struct amdgpu_device *)data;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = adev_to_drm(adev);
struct amdgpu_device *adev = drm_to_adev(dev);
int r; int r;
r = pm_runtime_get_sync(dev->dev); 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; return 0;
} }
seq_printf(m, "gpu recover\n"); *val = amdgpu_device_gpu_recover(adev, NULL);
amdgpu_device_gpu_recover(adev, NULL);
pm_runtime_mark_last_busy(dev->dev); pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev); pm_runtime_put_autosuspend(dev->dev);
@ -768,26 +765,24 @@ static int amdgpu_debugfs_gpu_recover(struct seq_file *m, void *data)
return 0; return 0;
} }
static const struct drm_info_list amdgpu_debugfs_fence_list[] = { DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_fence_info);
{"amdgpu_fence_info", &amdgpu_debugfs_fence_info, 0, NULL}, DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gpu_recover_fops, gpu_recover_get, NULL,
{"amdgpu_gpu_recover", &amdgpu_debugfs_gpu_recover, 0, NULL} "%lld\n");
};
static const struct drm_info_list amdgpu_debugfs_fence_list_sriov[] = {
{"amdgpu_fence_info", &amdgpu_debugfs_fence_info, 0, NULL},
};
#endif #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 defined(CONFIG_DEBUG_FS)
if (amdgpu_sriov_vf(adev)) struct drm_minor *minor = adev_to_drm(adev)->primary;
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_fence_list_sriov, struct dentry *root = minor->debugfs_root;
ARRAY_SIZE(amdgpu_debugfs_fence_list_sriov));
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_fence_list, debugfs_create_file("amdgpu_fence_info", 0444, root, adev,
ARRAY_SIZE(amdgpu_debugfs_fence_list)); &amdgpu_debugfs_fence_info_fops);
#else
return 0; if (!amdgpu_sriov_vf(adev))
debugfs_create_file("amdgpu_gpu_recover", 0444, root, adev,
&amdgpu_debugfs_gpu_recover_fops);
#endif #endif
} }

View File

@ -71,7 +71,7 @@
*/ */
static int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev) 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) if (adev->dummy_page_addr)
return 0; return 0;
@ -126,6 +126,8 @@ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
bp.type = ttm_bo_type_kernel; bp.type = ttm_bo_type_kernel;
bp.resv = NULL; bp.resv = NULL;
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
r = amdgpu_bo_create(adev, &bp, &adev->gart.bo); r = amdgpu_bo_create(adev, &bp, &adev->gart.bo);
if (r) { if (r) {
return r; return r;
@ -202,6 +204,7 @@ void amdgpu_gart_table_vram_free(struct amdgpu_device *adev)
return; return;
} }
amdgpu_bo_unref(&adev->gart.bo); 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; t = offset / AMDGPU_GPU_PAGE_SIZE;
p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE; p = t / AMDGPU_GPU_PAGES_IN_CPU_PAGE;
for (i = 0; i < pages; i++, p++) { 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; page_base = adev->dummy_page_addr;
if (!adev->gart.ptr) if (!adev->gart.ptr)
continue; 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, int pages, struct page **pagelist, dma_addr_t *dma_addr,
uint64_t flags) uint64_t flags)
{ {
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
unsigned t,p;
#endif
int r, i; int r, i;
if (!adev->gart.ready) { if (!adev->gart.ready) {
@ -322,13 +319,6 @@ int amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset,
return -EINVAL; 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) if (!adev->gart.ptr)
return 0; 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", DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
adev->gart.num_cpu_pages, adev->gart.num_gpu_pages); 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; return 0;
} }
@ -393,9 +375,5 @@ int amdgpu_gart_init(struct amdgpu_device *adev)
*/ */
void amdgpu_gart_fini(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); amdgpu_gart_dummy_page_fini(adev);
} }

View File

@ -46,9 +46,6 @@ struct amdgpu_gart {
unsigned num_gpu_pages; unsigned num_gpu_pages;
unsigned num_cpu_pages; unsigned num_cpu_pages;
unsigned table_size; unsigned table_size;
#ifdef CONFIG_DRM_AMDGPU_GART_DEBUGFS
struct page **pages;
#endif
bool ready; bool ready;
/* Asic default pte flags */ /* Asic default pte flags */

View File

@ -32,7 +32,6 @@
#include <linux/dma-buf.h> #include <linux/dma-buf.h>
#include <drm/amdgpu_drm.h> #include <drm/amdgpu_drm.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_gem_ttm_helper.h> #include <drm/drm_gem_ttm_helper.h>
#include "amdgpu.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 drm_gem_object **obj)
{ {
struct amdgpu_bo *bo; struct amdgpu_bo *bo;
struct amdgpu_bo_user *ubo;
struct amdgpu_bo_param bp; struct amdgpu_bo_param bp;
int r; int r;
@ -72,10 +72,13 @@ int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size,
bp.preferred_domain = initial_domain; bp.preferred_domain = initial_domain;
bp.flags = flags; bp.flags = flags;
bp.domain = initial_domain; 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) if (r)
return r; return r;
bo = &ubo->bo;
*obj = &bo->tbo.base; *obj = &bo->tbo.base;
(*obj)->funcs = &amdgpu_gem_object_funcs; (*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) #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 amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct drm_device *dev = node->minor->dev; struct drm_device *dev = adev_to_drm(adev);
struct drm_file *file; struct drm_file *file;
int r; int r;
@ -896,16 +899,17 @@ static int amdgpu_debugfs_gem_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static const struct drm_info_list amdgpu_debugfs_gem_list[] = { DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_gem_info);
{"amdgpu_gem_info", &amdgpu_debugfs_gem_info, 0, NULL},
};
#endif #endif
int amdgpu_debugfs_gem_init(struct amdgpu_device *adev) void amdgpu_debugfs_gem_init(struct amdgpu_device *adev)
{ {
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_gem_list, struct drm_minor *minor = adev_to_drm(adev)->primary;
ARRAY_SIZE(amdgpu_debugfs_gem_list)); struct dentry *root = minor->debugfs_root;
debugfs_create_file("amdgpu_gem_info", 0444, root, adev,
&amdgpu_debugfs_gem_info_fops);
#endif #endif
return 0;
} }

View File

@ -310,9 +310,8 @@ int amdgpu_gfx_kiq_init_ring(struct amdgpu_device *adev,
ring->eop_gpu_addr = kiq->eop_gpu_addr; ring->eop_gpu_addr = kiq->eop_gpu_addr;
ring->no_scheduler = true; ring->no_scheduler = true;
sprintf(ring->name, "kiq_%d.%d.%d", ring->me, ring->pipe, ring->queue); sprintf(ring->name, "kiq_%d.%d.%d", ring->me, ring->pipe, ring->queue);
r = amdgpu_ring_init(adev, ring, 1024, r = amdgpu_ring_init(adev, ring, 1024, irq, AMDGPU_CP_KIQ_IRQ_DRIVER0,
irq, AMDGPU_CP_KIQ_IRQ_DRIVER0, AMDGPU_RING_PRIO_DEFAULT, NULL);
AMDGPU_RING_PRIO_DEFAULT);
if (r) if (r)
dev_warn(adev->dev, "(%d) failed to init kiq ring\n", 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_kiq *kiq = &adev->gfx.kiq;
struct amdgpu_ring *kiq_ring = &kiq->ring; struct amdgpu_ring *kiq_ring = &kiq->ring;
int i; int i, r;
if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues) if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
return -EINVAL; return -EINVAL;
spin_lock(&adev->gfx.kiq.ring_lock);
if (amdgpu_ring_alloc(kiq_ring, kiq->pmf->unmap_queues_size * 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; return -ENOMEM;
}
for (i = 0; i < adev->gfx.num_compute_rings; i++) for (i = 0; i < adev->gfx.num_compute_rings; i++)
kiq->pmf->kiq_unmap_queues(kiq_ring, &adev->gfx.compute_ring[i], kiq->pmf->kiq_unmap_queues(kiq_ring, &adev->gfx.compute_ring[i],
RESET_QUEUES, 0, 0); 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, 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, DRM_INFO("kiq ring mec %d pipe %d q %d\n", kiq_ring->me, kiq_ring->pipe,
kiq_ring->queue); kiq_ring->queue);
spin_lock(&adev->gfx.kiq.ring_lock);
r = amdgpu_ring_alloc(kiq_ring, kiq->pmf->map_queues_size * r = amdgpu_ring_alloc(kiq_ring, kiq->pmf->map_queues_size *
adev->gfx.num_compute_rings + adev->gfx.num_compute_rings +
kiq->pmf->set_resources_size); kiq->pmf->set_resources_size);
if (r) { if (r) {
DRM_ERROR("Failed to lock KIQ (%d).\n", r); DRM_ERROR("Failed to lock KIQ (%d).\n", r);
spin_unlock(&adev->gfx.kiq.ring_lock);
return r; 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]); kiq->pmf->kiq_map_queues(kiq_ring, &adev->gfx.compute_ring[i]);
r = amdgpu_ring_test_helper(kiq_ring); r = amdgpu_ring_test_helper(kiq_ring);
spin_unlock(&adev->gfx.kiq.ring_lock);
if (r) if (r)
DRM_ERROR("KCQ enable failed\n"); 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 = { struct ras_ih_if ih_info = {
.cb = amdgpu_gfx_process_ras_data_cb, .cb = amdgpu_gfx_process_ras_data_cb,
}; };
struct ras_query_if info = { 0 };
if (!adev->gfx.ras_if) { if (!adev->gfx.ras_if) {
adev->gfx.ras_if = kmalloc(sizeof(struct ras_common_if), GFP_KERNEL); adev->gfx.ras_if = kmalloc(sizeof(struct ras_common_if), GFP_KERNEL);
@ -612,13 +619,19 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev)
strcpy(adev->gfx.ras_if->name, "gfx"); strcpy(adev->gfx.ras_if->name, "gfx");
} }
fs_info.head = ih_info.head = *adev->gfx.ras_if; fs_info.head = ih_info.head = *adev->gfx.ras_if;
r = amdgpu_ras_late_init(adev, adev->gfx.ras_if, r = amdgpu_ras_late_init(adev, adev->gfx.ras_if,
&fs_info, &ih_info); &fs_info, &ih_info);
if (r) if (r)
goto free; goto free;
if (amdgpu_ras_is_supported(adev, adev->gfx.ras_if->block)) { if (amdgpu_ras_is_supported(adev, adev->gfx.ras_if->block)) {
if (adev->gmc.xgmi.connected_to_cpu) {
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); r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0);
if (r) if (r)
goto late_fini; 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)) { if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) {
kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); kgd2kfd_set_sram_ecc_flag(adev->kfd.dev);
if (adev->gfx.funcs->query_ras_error_count) if (adev->gfx.ras_funcs &&
adev->gfx.funcs->query_ras_error_count(adev, err_data); adev->gfx.ras_funcs->query_ras_error_count)
adev->gfx.ras_funcs->query_ras_error_count(adev, err_data);
amdgpu_ras_reset_gpu(adev); amdgpu_ras_reset_gpu(adev);
} }
return AMDGPU_RAS_SUCCESS; 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_kiq *kiq = &adev->gfx.kiq;
struct amdgpu_ring *ring = &kiq->ring; struct amdgpu_ring *ring = &kiq->ring;
if (adev->in_pci_err_recovery) if (amdgpu_device_skip_hw_access(adev))
return 0; return 0;
BUG_ON(!ring->funcs->emit_rreg); 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); BUG_ON(!ring->funcs->emit_wreg);
if (adev->in_pci_err_recovery) if (amdgpu_device_skip_hw_access(adev))
return; return;
spin_lock_irqsave(&kiq->ring_lock, flags); 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) void amdgpu_gfx_state_change_set(struct amdgpu_device *adev, enum gfx_change_state state)
{ {
if (is_support_sw_smu(adev)) { mutex_lock(&adev->pm.mutex);
smu_gfx_state_change_set(&adev->smu, state); if (adev->powerplay.pp_funcs &&
} else { adev->powerplay.pp_funcs->gfx_state_change_set)
mutex_lock(&adev->pm.mutex); ((adev)->powerplay.pp_funcs->gfx_state_change_set(
if (adev->powerplay.pp_funcs && (adev)->powerplay.pp_handle, state));
adev->powerplay.pp_funcs->gfx_state_change_set) mutex_unlock(&adev->pm.mutex);
((adev)->powerplay.pp_funcs->gfx_state_change_set(
(adev)->powerplay.pp_handle, state));
mutex_unlock(&adev->pm.mutex);
}
} }

View File

@ -30,6 +30,7 @@
#include "clearstate_defs.h" #include "clearstate_defs.h"
#include "amdgpu_ring.h" #include "amdgpu_ring.h"
#include "amdgpu_rlc.h" #include "amdgpu_rlc.h"
#include "soc15.h"
/* GFX current status */ /* GFX current status */
#define AMDGPU_GFX_NORMAL_MODE 0x00000000L #define AMDGPU_GFX_NORMAL_MODE 0x00000000L
@ -204,6 +205,19 @@ struct amdgpu_cu_info {
uint32_t bitmap[4][4]; 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 { struct amdgpu_gfx_funcs {
/* get the gpu clock counter */ /* get the gpu clock counter */
uint64_t (*get_gpu_clock_counter)(struct amdgpu_device *adev); uint64_t (*get_gpu_clock_counter)(struct amdgpu_device *adev);
@ -219,11 +233,7 @@ struct amdgpu_gfx_funcs {
uint32_t *dst); uint32_t *dst);
void (*select_me_pipe_q)(struct amdgpu_device *adev, u32 me, u32 pipe, void (*select_me_pipe_q)(struct amdgpu_device *adev, u32 me, u32 pipe,
u32 queue, u32 vmid); 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 (*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); 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); DECLARE_BITMAP (pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES);
/*ras */ /*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)) #define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))

View File

@ -31,6 +31,59 @@
#include "amdgpu_ras.h" #include "amdgpu_ras.h"
#include "amdgpu_xgmi.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 * 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); 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 * 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 * @mc: memory controller structure holding memory information
* *
* Function will place try to place GART before or after VRAM. * Function will place try to place GART before or after VRAM.
*
* If GART size is bigger than space left then we ajust GART size. * If GART size is bigger than space left then we ajust GART size.
* Thus function will never fails. * 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*/ /*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); 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 /* VCE doesn't like it when BOs cross a 4GB segment, so align
* the GART base on a 4GB boundary as well. * 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; int r;
if (adev->umc.funcs && adev->umc.funcs->ras_late_init) { if (adev->umc.ras_funcs &&
r = adev->umc.funcs->ras_late_init(adev); adev->umc.ras_funcs->ras_late_init) {
r = adev->umc.ras_funcs->ras_late_init(adev);
if (r) if (r)
return r; return r;
} }
if (adev->mmhub.funcs && adev->mmhub.funcs->ras_late_init) { if (adev->mmhub.ras_funcs &&
r = adev->mmhub.funcs->ras_late_init(adev); adev->mmhub.ras_funcs->ras_late_init) {
r = adev->mmhub.ras_funcs->ras_late_init(adev);
if (r) if (r)
return 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) void amdgpu_gmc_ras_fini(struct amdgpu_device *adev)
{ {
amdgpu_umc_ras_fini(adev); if (adev->umc.ras_funcs &&
amdgpu_mmhub_ras_fini(adev); adev->umc.ras_funcs->ras_fini)
amdgpu_xgmi_ras_fini(adev); 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) { switch (adev->asic_type) {
case CHIP_RAVEN: 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_RENOIR:
case CHIP_NAVI10: case CHIP_NAVI10:
case CHIP_NAVI14: case CHIP_NAVI14:
@ -423,6 +536,8 @@ void amdgpu_gmc_noretry_set(struct amdgpu_device *adev)
switch (adev->asic_type) { switch (adev->asic_type) {
case CHIP_VEGA10: case CHIP_VEGA10:
case CHIP_VEGA20: case CHIP_VEGA20:
case CHIP_ARCTURUS:
case CHIP_ALDEBARAN:
/* /*
* noretry = 0 will cause kfd page fault tests fail * noretry = 0 will cause kfd page fault tests fail
* for some ASICs, so set default to 1 for these ASICs. * 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; 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);
}

View File

@ -135,6 +135,14 @@ struct amdgpu_gmc_funcs {
unsigned int (*get_vbios_fb_size)(struct amdgpu_device *adev); 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 { struct amdgpu_xgmi {
/* from psp */ /* from psp */
u64 node_id; u64 node_id;
@ -149,6 +157,9 @@ struct amdgpu_xgmi {
struct list_head head; struct list_head head;
bool supported; bool supported;
struct ras_common_if *ras_if; struct ras_common_if *ras_if;
bool connected_to_cpu;
bool pending_reset;
const struct amdgpu_xgmi_ras_funcs *ras_funcs;
}; };
struct amdgpu_gmc { struct amdgpu_gmc {
@ -189,10 +200,13 @@ struct amdgpu_gmc {
u64 gart_end; u64 gart_end;
/* Frame buffer aperture of this GPU device. Different from /* Frame buffer aperture of this GPU device. Different from
* fb_start (see below), this only covers the local GPU device. * fb_start (see below), this only covers the local GPU device.
* Driver get fb_start from MC_VM_FB_LOCATION_BASE (set by vbios) * If driver uses FB aperture to access FB, driver get fb_start from
* and calculate vram_start of this local device by adding an * MC_VM_FB_LOCATION_BASE (set by vbios) and calculate vram_start
* offset inside the XGMI hive. * of this local device by adding an offset inside the XGMI hive.
* Under VMID0, logical address == MC address * 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_start;
u64 vram_end; u64 vram_end;
@ -204,6 +218,15 @@ struct amdgpu_gmc {
*/ */
u64 fb_start; u64 fb_start;
u64 fb_end; 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; unsigned vram_width;
u64 real_vram_size; u64 real_vram_size;
int vram_mtrr; int vram_mtrr;
@ -240,6 +263,12 @@ struct amdgpu_gmc {
struct amdgpu_xgmi xgmi; struct amdgpu_xgmi xgmi;
struct amdgpu_irq_src ecc_irq; struct amdgpu_irq_src ecc_irq;
int noretry; 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))) #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; return addr;
} }
int amdgpu_gmc_pdb0_alloc(struct amdgpu_device *adev);
void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level, void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level,
uint64_t *addr, uint64_t *flags); uint64_t *addr, uint64_t *flags);
int amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, 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 flags);
uint64_t amdgpu_gmc_pd_addr(struct amdgpu_bo *bo); uint64_t amdgpu_gmc_pd_addr(struct amdgpu_bo *bo);
uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *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, void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc,
u64 base); u64 base);
void amdgpu_gmc_gart_location(struct amdgpu_device *adev, 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_get_vbios_allocations(struct amdgpu_device *adev);
void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev);
#endif #endif

View File

@ -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 amdgpu_device *adev = drm_to_adev(ddev);
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
return snprintf(buf, PAGE_SIZE, "%llu\n", return sysfs_emit(buf, "%llu\n", man->size * PAGE_SIZE);
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 amdgpu_device *adev = drm_to_adev(ddev);
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT); struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
return snprintf(buf, PAGE_SIZE, "%llu\n", return sysfs_emit(buf, "%llu\n", amdgpu_gtt_mgr_usage(man));
amdgpu_gtt_mgr_usage(man));
} }
static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO, static DEVICE_ATTR(mem_info_gtt_total, S_IRUGO,

View File

@ -30,7 +30,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <drm/amdgpu_drm.h> #include <drm/amdgpu_drm.h>
#include <drm/drm_debugfs.h>
#include "amdgpu.h" #include "amdgpu.h"
#include "atom.h" #include "atom.h"
@ -453,11 +452,9 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
*/ */
#if defined(CONFIG_DEBUG_FS) #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 amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
seq_printf(m, "--------------------- DELAYED --------------------- \n"); seq_printf(m, "--------------------- DELAYED --------------------- \n");
amdgpu_sa_bo_dump_debug_info(&adev->ib_pools[AMDGPU_IB_POOL_DELAYED], 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; return 0;
} }
static const struct drm_info_list amdgpu_debugfs_sa_list[] = { DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_sa_info);
{"amdgpu_sa_info", &amdgpu_debugfs_sa_info, 0, NULL},
};
#endif #endif
int amdgpu_debugfs_sa_init(struct amdgpu_device *adev) void amdgpu_debugfs_sa_init(struct amdgpu_device *adev)
{ {
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
return amdgpu_debugfs_add_files(adev, amdgpu_debugfs_sa_list, struct drm_minor *minor = adev_to_drm(adev)->primary;
ARRAY_SIZE(amdgpu_debugfs_sa_list)); struct dentry *root = minor->debugfs_root;
#else
return 0; debugfs_create_file("amdgpu_sa_info", 0444, root, adev,
&amdgpu_debugfs_sa_info_fops);
#endif #endif
} }

View File

@ -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_addr = adev->wb.gpu_addr + rptr_offs * 4;
ih->rptr_cpu = &adev->wb.wb[rptr_offs]; ih->rptr_cpu = &adev->wb.wb[rptr_offs];
} }
init_waitqueue_head(&ih->wait_process);
return 0; 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 * 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); wptr = amdgpu_ih_get_wptr(adev, ih);
restart_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); DRM_DEBUG("%s: rptr %d, wptr %d\n", __func__, ih->rptr, wptr);
/* Order reading of wptr vs. reading of IH ring data */ /* Order reading of wptr vs. reading of IH ring data */
@ -195,7 +239,7 @@ restart_ih:
} }
amdgpu_ih_set_rptr(adev, 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 */ /* make sure wptr hasn't changed while processing */
wptr = amdgpu_ih_get_wptr(adev, ih); wptr = amdgpu_ih_get_wptr(adev, ih);

View File

@ -64,8 +64,10 @@ struct amdgpu_ih_ring {
bool enabled; bool enabled;
unsigned rptr; unsigned rptr;
atomic_t lock;
struct amdgpu_ih_regs ih_regs; struct amdgpu_ih_regs ih_regs;
/* For waiting on IH processing at checkpoint. */
wait_queue_head_t wait_process;
}; };
/* provided by the ih block */ /* 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_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv, void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
unsigned int num_dw); 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); int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev, void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih, struct amdgpu_ih_ring *ih,

View File

@ -65,6 +65,41 @@
#define AMDGPU_WAIT_IDLE_TIMEOUT 200 #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 * 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 * ack the interrupt if it is there
*/ */
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__PCIE_BIF)) { if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__PCIE_BIF)) {
if (adev->nbio.funcs && if (adev->nbio.ras_funcs &&
adev->nbio.funcs->handle_ras_controller_intr_no_bifring) adev->nbio.ras_funcs->handle_ras_controller_intr_no_bifring)
adev->nbio.funcs->handle_ras_controller_intr_no_bifring(adev); adev->nbio.ras_funcs->handle_ras_controller_intr_no_bifring(adev);
if (adev->nbio.funcs && if (adev->nbio.ras_funcs &&
adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring) adev->nbio.ras_funcs->handle_ras_err_event_athub_intr_no_bifring)
adev->nbio.funcs->handle_ras_err_event_athub_intr_no_bifring(adev); adev->nbio.ras_funcs->handle_ras_err_event_athub_intr_no_bifring(adev);
} }
return ret; return ret;
@ -347,11 +382,6 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
kfree(src->enabled_types); kfree(src->enabled_types);
src->enabled_types = NULL; 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); kfree(adev->irq.client[i].sources);
adev->irq.client[i].sources = NULL; 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) { for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
struct amdgpu_irq_src *src = adev->irq.client[i].sources[j]; struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];
if (!src) if (!src || !src->funcs || !src->funcs->set)
continue; continue;
for (k = 0; k < src->num_types; k++) for (k = 0; k < src->num_types; k++)
amdgpu_irq_update(adev, src, k); amdgpu_irq_update(adev, src, k);

View File

@ -62,7 +62,6 @@ struct amdgpu_irq_src {
unsigned num_types; unsigned num_types;
atomic_t *enabled_types; atomic_t *enabled_types;
const struct amdgpu_irq_src_funcs *funcs; const struct amdgpu_irq_src_funcs *funcs;
void *data;
}; };
struct amdgpu_irq_client { struct amdgpu_irq_client {

View File

@ -28,7 +28,7 @@
#include "amdgpu.h" #include "amdgpu.h"
#include "amdgpu_trace.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_ring *ring = to_amdgpu_ring(s_job->sched);
struct amdgpu_job *job = to_amdgpu_job(s_job); 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)) { amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) {
DRM_ERROR("ring %s timeout, but soft recovered\n", DRM_ERROR("ring %s timeout, but soft recovered\n",
s_job->sched->name); s_job->sched->name);
return; return DRM_GPU_SCHED_STAT_NOMINAL;
} }
amdgpu_vm_get_task_info(ring->adev, job->pasid, &ti); 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)) { if (amdgpu_device_should_recover_gpu(ring->adev)) {
amdgpu_device_gpu_recover(ring->adev, job); amdgpu_device_gpu_recover(ring->adev, job);
return DRM_GPU_SCHED_STAT_NOMINAL;
} else { } else {
drm_sched_suspend_timeout(&ring->sched); drm_sched_suspend_timeout(&ring->sched);
if (amdgpu_sriov_vf(adev)) if (amdgpu_sriov_vf(adev))
adev->virt.tdr_debug = true; adev->virt.tdr_debug = true;
return DRM_GPU_SCHED_STAT_NOMINAL;
} }
} }

View File

@ -27,7 +27,6 @@
*/ */
#include "amdgpu.h" #include "amdgpu.h"
#include <drm/drm_debugfs.h>
#include <drm/amdgpu_drm.h> #include <drm/amdgpu_drm.h>
#include "amdgpu_uvd.h" #include "amdgpu_uvd.h"
#include "amdgpu_vce.h" #include "amdgpu_vce.h"
@ -160,7 +159,7 @@ int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags)
goto out; goto out;
} }
if (amdgpu_device_supports_atpx(dev) && if (amdgpu_device_supports_px(dev) &&
(amdgpu_runtime_pm != 0)) { /* enable runpm by default for atpx */ (amdgpu_runtime_pm != 0)) { /* enable runpm by default for atpx */
adev->runpm = true; adev->runpm = true;
dev_info(adev->dev, "Using ATPX for runtime pm\n"); 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) { if (adev->runpm) {
/* only need to skip on ATPX */ /* only need to skip on ATPX */
if (amdgpu_device_supports_atpx(dev) && if (amdgpu_device_supports_px(dev))
!amdgpu_is_atpx_hybrid())
dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); 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_use_autosuspend(dev->dev);
pm_runtime_set_autosuspend_delay(dev->dev, 5000); pm_runtime_set_autosuspend_delay(dev->dev, 5000);
pm_runtime_allow(dev->dev); pm_runtime_allow(dev->dev);
@ -287,22 +290,30 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info,
break; break;
case AMDGPU_INFO_FW_TA: case AMDGPU_INFO_FW_TA:
switch (query_fw->index) { switch (query_fw->index) {
case 0: case TA_FW_TYPE_PSP_XGMI:
fw_info->ver = adev->psp.ta_fw_version; fw_info->ver = adev->psp.ta_fw_version;
fw_info->feature = adev->psp.ta_xgmi_ucode_version; fw_info->feature = adev->psp.ta_xgmi_ucode_version;
break; break;
case 1: case TA_FW_TYPE_PSP_RAS:
fw_info->ver = adev->psp.ta_fw_version; fw_info->ver = adev->psp.ta_fw_version;
fw_info->feature = adev->psp.ta_ras_ucode_version; fw_info->feature = adev->psp.ta_ras_ucode_version;
break; break;
case 2: case TA_FW_TYPE_PSP_HDCP:
fw_info->ver = adev->psp.ta_fw_version; fw_info->ver = adev->psp.ta_fw_version;
fw_info->feature = adev->psp.ta_hdcp_ucode_version; fw_info->feature = adev->psp.ta_hdcp_ucode_version;
break; break;
case 3: case TA_FW_TYPE_PSP_DTM:
fw_info->ver = adev->psp.ta_fw_version; fw_info->ver = adev->psp.ta_fw_version;
fw_info->feature = adev->psp.ta_dtm_ucode_version; fw_info->feature = adev->psp.ta_dtm_ucode_version;
break; 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: default:
return -EINVAL; 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))) ? min_t(u64, size, sizeof(ras_mask))) ?
-EFAULT : 0; -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: default:
DRM_DEBUG_KMS("Invalid request %d\n", info->query); DRM_DEBUG_KMS("Invalid request %d\n", info->query);
return -EINVAL; return -EINVAL;
@ -1262,16 +1330,25 @@ void amdgpu_disable_vblank_kms(struct drm_crtc *crtc)
*/ */
#if defined(CONFIG_DEBUG_FS) #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 amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
struct drm_amdgpu_info_firmware fw_info; struct drm_amdgpu_info_firmware fw_info;
struct drm_amdgpu_query_fw query_fw; struct drm_amdgpu_query_fw query_fw;
struct atom_context *ctx = adev->mode_info.atom_context; struct atom_context *ctx = adev->mode_info.atom_context;
int ret, i; 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 */ /* VCE */
query_fw.fw_type = AMDGPU_INFO_FW_VCE; query_fw.fw_type = AMDGPU_INFO_FW_VCE;
ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); 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); fw_info.feature, fw_info.ver);
query_fw.fw_type = AMDGPU_INFO_FW_TA; 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; query_fw.index = i;
ret = amdgpu_firmware_info(&fw_info, &query_fw, adev); ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
if (ret) if (ret)
continue; continue;
switch (query_fw.index) {
case 0: seq_printf(m, "TA %s feature version: 0x%08x, firmware version: 0x%08x\n",
seq_printf(m, "TA %s feature version: 0x%08x, firmware version: 0x%08x\n", ta_fw_name[i], fw_info.feature, fw_info.ver);
"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;
}
} }
/* SMC */ /* SMC */
@ -1472,17 +1532,18 @@ static int amdgpu_debugfs_firmware_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static const struct drm_info_list amdgpu_firmware_info_list[] = { DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_firmware_info);
{"amdgpu_firmware_info", amdgpu_debugfs_firmware_info, 0, NULL},
};
#endif #endif
int amdgpu_debugfs_firmware_init(struct amdgpu_device *adev) void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev)
{ {
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
return amdgpu_debugfs_add_files(adev, amdgpu_firmware_info_list, struct drm_minor *minor = adev_to_drm(adev)->primary;
ARRAY_SIZE(amdgpu_firmware_info_list)); struct dentry *root = minor->debugfs_root;
#else
return 0; debugfs_create_file("amdgpu_firmware_info", 0444, root,
adev, &amdgpu_debugfs_firmware_info_fops);
#endif #endif
} }

View File

@ -21,12 +21,16 @@
#ifndef __AMDGPU_MMHUB_H__ #ifndef __AMDGPU_MMHUB_H__
#define __AMDGPU_MMHUB_H__ #define __AMDGPU_MMHUB_H__
struct amdgpu_mmhub_funcs { struct amdgpu_mmhub_ras_funcs {
void (*ras_init)(struct amdgpu_device *adev);
int (*ras_late_init)(struct amdgpu_device *adev); 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 (*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); void (*reset_ras_error_count)(struct amdgpu_device *adev);
};
struct amdgpu_mmhub_funcs {
u64 (*get_fb_location)(struct amdgpu_device *adev); u64 (*get_fb_location)(struct amdgpu_device *adev);
void (*init)(struct amdgpu_device *adev); void (*init)(struct amdgpu_device *adev);
int (*gart_enable)(struct amdgpu_device *adev); int (*gart_enable)(struct amdgpu_device *adev);
@ -40,12 +44,12 @@ struct amdgpu_mmhub_funcs {
uint64_t page_table_base); uint64_t page_table_base);
void (*update_power_gating)(struct amdgpu_device *adev, void (*update_power_gating)(struct amdgpu_device *adev,
bool enable); bool enable);
void (*query_ras_error_status)(struct amdgpu_device *adev);
}; };
struct amdgpu_mmhub { struct amdgpu_mmhub {
struct ras_common_if *ras_if; struct ras_common_if *ras_if;
const struct amdgpu_mmhub_funcs *funcs; const struct amdgpu_mmhub_funcs *funcs;
const struct amdgpu_mmhub_ras_funcs *ras_funcs;
}; };
int amdgpu_mmhub_ras_late_init(struct amdgpu_device *adev); int amdgpu_mmhub_ras_late_init(struct amdgpu_device *adev);

View File

@ -602,6 +602,14 @@ int amdgpu_display_get_crtc_scanoutpos(struct drm_device *dev,
int *hpos, ktime_t *stime, ktime_t *etime, int *hpos, ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode); 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, int amdgpu_display_framebuffer_init(struct drm_device *dev,
struct amdgpu_framebuffer *rfb, struct amdgpu_framebuffer *rfb,
const struct drm_mode_fb_cmd2 *mode_cmd, const struct drm_mode_fb_cmd2 *mode_cmd,

View File

@ -47,6 +47,17 @@ struct nbio_hdp_flush_reg {
u32 ref_and_mask_sdma7; 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 { struct amdgpu_nbio_funcs {
const struct nbio_hdp_flush_reg *hdp_flush_reg; const struct nbio_hdp_flush_reg *hdp_flush_reg;
u32 (*get_hdp_flush_req_offset)(struct amdgpu_device *adev); 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 (*ih_control)(struct amdgpu_device *adev);
void (*init_registers)(struct amdgpu_device *adev); void (*init_registers)(struct amdgpu_device *adev);
void (*remap_hdp_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, void (*enable_aspm)(struct amdgpu_device *adev,
bool enable); bool enable);
void (*program_aspm)(struct amdgpu_device *adev); void (*program_aspm)(struct amdgpu_device *adev);
@ -97,6 +101,7 @@ struct amdgpu_nbio {
struct amdgpu_irq_src ras_err_event_athub_irq; struct amdgpu_irq_src ras_err_event_athub_irq;
struct ras_common_if *ras_if; struct ras_common_if *ras_if;
const struct amdgpu_nbio_funcs *funcs; const struct amdgpu_nbio_funcs *funcs;
const struct amdgpu_nbio_ras_funcs *ras_funcs;
}; };
int amdgpu_nbio_ras_late_init(struct amdgpu_device *adev); int amdgpu_nbio_ras_late_init(struct amdgpu_device *adev);

View File

@ -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_device *adev = amdgpu_ttm_adev(tbo->bdev);
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo);
struct amdgpu_bo_user *ubo;
if (bo->tbo.pin_count > 0) if (bo->tbo.pin_count > 0)
amdgpu_bo_subtract_pin_size(bo); 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); 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); kfree(bo);
} }
@ -248,6 +253,7 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
bp.flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; bp.flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
bp.type = ttm_bo_type_kernel; bp.type = ttm_bo_type_kernel;
bp.resv = NULL; bp.resv = NULL;
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
if (!*bo_ptr) { if (!*bo_ptr) {
r = amdgpu_bo_create(adev, &bp, 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; struct amdgpu_bo *bo;
unsigned long page_align, size = bp->size; unsigned long page_align, size = bp->size;
size_t acc_size;
int r; int r;
/* Note that GDS/GWS/OA allocates 1 page per byte/resource. */ /* 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)) if (!amdgpu_bo_validate_size(adev, size, bp->domain))
return -ENOMEM; return -ENOMEM;
BUG_ON(bp->bo_ptr_size < sizeof(struct amdgpu_bo));
*bo_ptr = NULL; *bo_ptr = NULL;
bo = kzalloc(bp->bo_ptr_size, GFP_KERNEL);
acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size,
sizeof(struct amdgpu_bo));
bo = kzalloc(sizeof(struct amdgpu_bo), GFP_KERNEL);
if (bo == NULL) if (bo == NULL)
return -ENOMEM; return -ENOMEM;
drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size); drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size);
@ -577,8 +580,8 @@ static int amdgpu_bo_do_create(struct amdgpu_device *adev,
bo->tbo.priority = 1; bo->tbo.priority = 1;
r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type, r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type,
&bo->placement, page_align, &ctx, acc_size, &bo->placement, page_align, &ctx, NULL,
NULL, bp->resv, &amdgpu_bo_destroy); bp->resv, &amdgpu_bo_destroy);
if (unlikely(r != 0)) if (unlikely(r != 0))
return r; return r;
@ -639,6 +642,7 @@ static int amdgpu_bo_create_shadow(struct amdgpu_device *adev,
AMDGPU_GEM_CREATE_SHADOW; AMDGPU_GEM_CREATE_SHADOW;
bp.type = ttm_bo_type_kernel; bp.type = ttm_bo_type_kernel;
bp.resv = bo->tbo.base.resv; bp.resv = bo->tbo.base.resv;
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
r = amdgpu_bo_do_create(adev, &bp, &bo->shadow); r = amdgpu_bo_do_create(adev, &bp, &bo->shadow);
if (!r) { if (!r) {
@ -673,6 +677,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
int r; int r;
bp->flags = bp->flags & ~AMDGPU_GEM_CREATE_SHADOW; bp->flags = bp->flags & ~AMDGPU_GEM_CREATE_SHADOW;
r = amdgpu_bo_do_create(adev, bp, bo_ptr); r = amdgpu_bo_do_create(adev, bp, bo_ptr);
if (r) if (r)
return r; return r;
@ -694,6 +699,34 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
return r; 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 * amdgpu_bo_validate - validate an &amdgpu_bo buffer object
* @bo: pointer to the 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) int amdgpu_bo_init(struct amdgpu_device *adev)
{ {
/* reserve PAT memory space to WC for VRAM */ /* On A+A platform, VRAM can be mapped as WB */
arch_io_reserve_memtype_wc(adev->gmc.aper_base, if (!adev->gmc.xgmi.connected_to_cpu) {
adev->gmc.aper_size); /* 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", DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n",
adev->gmc.mc_vram_size >> 20, adev->gmc.mc_vram_size >> 20,
(unsigned long long)adev->gmc.aper_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) void amdgpu_bo_fini(struct amdgpu_device *adev)
{ {
amdgpu_ttm_fini(adev); amdgpu_ttm_fini(adev);
arch_phys_wc_del(adev->gmc.vram_mtrr); if (!adev->gmc.xgmi.connected_to_cpu) {
arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); 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);
} }
/** /**
@ -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) 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_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 && if (adev->family <= AMDGPU_FAMILY_CZ &&
AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6) AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6)
return -EINVAL; return -EINVAL;
bo->tiling_flags = tiling_flags; ubo = to_amdgpu_bo_user(bo);
ubo->tiling_flags = tiling_flags;
return 0; 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) 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); dma_resv_assert_held(bo->tbo.base.resv);
ubo = to_amdgpu_bo_user(bo);
if (tiling_flags) 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, int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
uint32_t metadata_size, uint64_t flags) uint32_t metadata_size, uint64_t flags)
{ {
struct amdgpu_bo_user *ubo;
void *buffer; void *buffer;
BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
ubo = to_amdgpu_bo_user(bo);
if (!metadata_size) { if (!metadata_size) {
if (bo->metadata_size) { if (ubo->metadata_size) {
kfree(bo->metadata); kfree(ubo->metadata);
bo->metadata = NULL; ubo->metadata = NULL;
bo->metadata_size = 0; ubo->metadata_size = 0;
} }
return 0; return 0;
} }
@ -1182,10 +1212,10 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata,
if (buffer == NULL) if (buffer == NULL)
return -ENOMEM; return -ENOMEM;
kfree(bo->metadata); kfree(ubo->metadata);
bo->metadata_flags = flags; ubo->metadata_flags = flags;
bo->metadata = buffer; ubo->metadata = buffer;
bo->metadata_size = metadata_size; ubo->metadata_size = metadata_size;
return 0; 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, size_t buffer_size, uint32_t *metadata_size,
uint64_t *flags) uint64_t *flags)
{ {
struct amdgpu_bo_user *ubo;
if (!buffer && !metadata_size) if (!buffer && !metadata_size)
return -EINVAL; return -EINVAL;
BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
ubo = to_amdgpu_bo_user(bo);
if (buffer) { if (buffer) {
if (buffer_size < bo->metadata_size) if (buffer_size < ubo->metadata_size)
return -EINVAL; return -EINVAL;
if (bo->metadata_size) if (ubo->metadata_size)
memcpy(buffer, bo->metadata, bo->metadata_size); memcpy(buffer, ubo->metadata, ubo->metadata_size);
} }
if (metadata_size) if (metadata_size)
*metadata_size = bo->metadata_size; *metadata_size = ubo->metadata_size;
if (flags) if (flags)
*flags = bo->metadata_flags; *flags = ubo->metadata_flags;
return 0; return 0;
} }

View File

@ -37,9 +37,12 @@
#define AMDGPU_BO_INVALID_OFFSET LONG_MAX #define AMDGPU_BO_INVALID_OFFSET LONG_MAX
#define AMDGPU_BO_MAX_PLACEMENTS 3 #define AMDGPU_BO_MAX_PLACEMENTS 3
#define to_amdgpu_bo_user(abo) container_of((abo), struct amdgpu_bo_user, bo)
struct amdgpu_bo_param { struct amdgpu_bo_param {
unsigned long size; unsigned long size;
int byte_align; int byte_align;
u32 bo_ptr_size;
u32 domain; u32 domain;
u32 preferred_domain; u32 preferred_domain;
u64 flags; u64 flags;
@ -89,10 +92,6 @@ struct amdgpu_bo {
struct ttm_buffer_object tbo; struct ttm_buffer_object tbo;
struct ttm_bo_kmap_obj kmap; struct ttm_bo_kmap_obj kmap;
u64 flags; u64 flags;
u64 tiling_flags;
u64 metadata_flags;
void *metadata;
u32 metadata_size;
unsigned prime_shared_count; unsigned prime_shared_count;
/* per VM structure for page tables and with virtual addresses */ /* per VM structure for page tables and with virtual addresses */
struct amdgpu_vm_bo_base *vm_bo; struct amdgpu_vm_bo_base *vm_bo;
@ -100,7 +99,6 @@ struct amdgpu_bo {
struct amdgpu_bo *parent; struct amdgpu_bo *parent;
struct amdgpu_bo *shadow; struct amdgpu_bo *shadow;
struct amdgpu_mn *mn;
#ifdef CONFIG_MMU_NOTIFIER #ifdef CONFIG_MMU_NOTIFIER
@ -112,6 +110,15 @@ struct amdgpu_bo {
struct kgd_mem *kfd_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) static inline struct amdgpu_bo *ttm_to_amdgpu_bo(struct ttm_buffer_object *tbo)
{ {
return container_of(tbo, struct amdgpu_bo, tbo); return container_of(tbo, struct amdgpu_bo, tbo);
@ -255,6 +262,9 @@ int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev, int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
uint64_t offset, uint64_t size, uint32_t domain, uint64_t offset, uint64_t size, uint32_t domain,
struct amdgpu_bo **bo_ptr, void **cpu_addr); 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 amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr,
void **cpu_addr); void **cpu_addr);
int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr); int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr);
@ -269,8 +279,6 @@ void amdgpu_bo_unpin(struct amdgpu_bo *bo);
int amdgpu_bo_evict_vram(struct amdgpu_device *adev); int amdgpu_bo_evict_vram(struct amdgpu_device *adev);
int amdgpu_bo_init(struct amdgpu_device *adev); int amdgpu_bo_init(struct amdgpu_device *adev);
void amdgpu_bo_fini(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); 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); void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags);
int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, 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); struct seq_file *m);
u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m); u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m);
#endif #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); bool amdgpu_bo_support_uswc(u64 bo_flags);

View File

@ -34,6 +34,7 @@
#include "psp_v10_0.h" #include "psp_v10_0.h"
#include "psp_v11_0.h" #include "psp_v11_0.h"
#include "psp_v12_0.h" #include "psp_v12_0.h"
#include "psp_v13_0.h"
#include "amdgpu_ras.h" #include "amdgpu_ras.h"
#include "amdgpu_securedisplay.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 * - Load XGMI/RAS/HDCP/DTM TA if any
* *
* This new sequence is required for * This new sequence is required for
* - Arcturus * - Arcturus and onwards
* - Navi12 and onwards * - Navi12 and onwards
*/ */
static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp) 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) if (adev->flags & AMD_IS_APU)
return; return;
if ((adev->asic_type == CHIP_ARCTURUS) || if ((adev->asic_type >= CHIP_ARCTURUS) ||
(adev->asic_type >= CHIP_NAVI12)) (adev->asic_type >= CHIP_NAVI12))
psp->pmfw_centralized_cstate_management = true; psp->pmfw_centralized_cstate_management = true;
} }
@ -109,6 +110,9 @@ static int psp_early_init(void *handle)
case CHIP_RENOIR: case CHIP_RENOIR:
psp_v12_0_set_psp_funcs(psp); psp_v12_0_set_psp_funcs(psp);
break; break;
case CHIP_ALDEBARAN:
psp_v13_0_set_psp_funcs(psp);
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -383,7 +387,7 @@ static int psp_tmr_init(struct psp_context *psp)
* Note: this memory need be reserved till the driver * Note: this memory need be reserved till the driver
* uninitializes. * uninitializes.
*/ */
tmr_size = PSP_TMR_SIZE; tmr_size = PSP_TMR_SIZE(psp->adev);
/* For ASICs support RLC autoload, psp will parse the toc /* For ASICs support RLC autoload, psp will parse the toc
* and calculate the total size of TMR needed */ * 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; 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, AMDGPU_GEM_DOMAIN_VRAM,
&psp->tmr_bo, &psp->tmr_mc_addr, pptr); &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; return ret;
} }
@ -542,6 +556,46 @@ int psp_get_fw_attestation_records_addr(struct psp_context *psp,
return ret; return ret;
} }
static int psp_boot_config_set(struct amdgpu_device *adev)
{
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, static void psp_prep_asd_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
uint64_t asd_mc, uint32_t size) 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 psp_gfx_cmd_resp *cmd;
struct amdgpu_device *adev = psp->adev; struct amdgpu_device *adev = psp->adev;
/* XGMI TA unload currently is not supported on Arcturus */ /* XGMI TA unload currently is not supported on Arcturus/Aldebaran A+A */
if (adev->asic_type == CHIP_ARCTURUS) if (adev->asic_type == CHIP_ARCTURUS ||
(adev->asic_type == CHIP_ALDEBARAN && adev->gmc.xgmi.connected_to_cpu))
return 0; return 0;
/* /*
@ -1561,6 +1616,7 @@ static int psp_rap_unload(struct psp_context *psp)
static int psp_rap_initialize(struct psp_context *psp) static int psp_rap_initialize(struct psp_context *psp)
{ {
int ret; int ret;
enum ta_rap_status status = TA_RAP_STATUS__SUCCESS;
/* /*
* TODO: bypass the initialize in sriov for now * TODO: bypass the initialize in sriov for now
@ -1584,8 +1640,8 @@ static int psp_rap_initialize(struct psp_context *psp)
if (ret) if (ret)
return ret; return ret;
ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE); ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE, &status);
if (ret != TA_RAP_STATUS__SUCCESS) { if (ret || status != TA_RAP_STATUS__SUCCESS) {
psp_rap_unload(psp); psp_rap_unload(psp);
amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo, 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; psp->rap_context.rap_initialized = false;
dev_warn(psp->adev->dev, "RAP TA initialize fail.\n"); dev_warn(psp->adev->dev, "RAP TA initialize fail (%d) status %d.\n",
return -EINVAL; ret, status);
return ret;
} }
return 0; return 0;
@ -1620,13 +1678,13 @@ static int psp_rap_terminate(struct psp_context *psp)
return ret; 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; struct ta_rap_shared_memory *rap_cmd;
int ret; int ret = 0;
if (!psp->rap_context.rap_initialized) if (!psp->rap_context.rap_initialized)
return -EINVAL; return 0;
if (ta_cmd_id != TA_CMD_RAP__INITIALIZE && if (ta_cmd_id != TA_CMD_RAP__INITIALIZE &&
ta_cmd_id != TA_CMD_RAP__VALIDATE_L0) 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; rap_cmd->validation_method_id = METHOD_A;
ret = psp_ta_invoke(psp, rap_cmd->cmd_id, psp->rap_context.session_id); ret = psp_ta_invoke(psp, rap_cmd->cmd_id, psp->rap_context.session_id);
if (ret) { if (ret)
mutex_unlock(&psp->rap_context.mutex); goto out_unlock;
return ret;
}
if (status)
*status = rap_cmd->rap_status;
out_unlock:
mutex_unlock(&psp->rap_context.mutex); mutex_unlock(&psp->rap_context.mutex);
return rap_cmd->rap_status; return ret;
} }
// RAP end // RAP end
@ -1870,6 +1930,11 @@ static int psp_hw_start(struct psp_context *psp)
return ret; return ret;
} }
ret = psp_boot_config_set(adev);
if (ret) {
DRM_WARN("PSP set boot config@\n");
}
ret = psp_tmr_init(psp); ret = psp_tmr_init(psp);
if (ret) { if (ret) {
DRM_ERROR("PSP tmr init failed!\n"); DRM_ERROR("PSP tmr init failed!\n");
@ -2104,9 +2169,13 @@ static int psp_load_smu_fw(struct psp_context *psp)
if (!ucode->fw || amdgpu_sriov_vf(psp->adev)) if (!ucode->fw || amdgpu_sriov_vf(psp->adev))
return 0; return 0;
if ((amdgpu_in_reset(adev) &&
if (amdgpu_in_reset(adev) && ras && ras->supported && ras && ras->supported &&
adev->asic_type == CHIP_ARCTURUS) { (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); ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD);
if (ret) { if (ret) {
DRM_WARN("Failed to set MP1 state prepare for reload\n"); DRM_WARN("Failed to set MP1 state prepare for reload\n");
@ -2159,6 +2228,22 @@ static bool fw_load_skip_check(struct psp_context *psp,
return false; 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) static int psp_np_fw_load(struct psp_context *psp)
{ {
int i, ret; int i, ret;
@ -2276,6 +2361,12 @@ skip_memalloc:
return ret; return ret;
} }
ret = psp_rl_load(adev);
if (ret) {
DRM_ERROR("PSP load RL failed!\n");
return ret;
}
if (psp->adev->psp.ta_fw) { if (psp->adev->psp.ta_fw) {
ret = psp_ras_initialize(psp); ret = psp_ras_initialize(psp);
if (ret) 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_bin_size = le32_to_cpu(sos_hdr_v1_3->spl_size_bytes);
adev->psp.spl_start_addr = (uint8_t *)adev->psp.sys_start_addr + adev->psp.spl_start_addr = (uint8_t *)adev->psp.sys_start_addr +
le32_to_cpu(sos_hdr_v1_3->spl_offset_bytes); le32_to_cpu(sos_hdr_v1_3->spl_offset_bytes);
adev->psp.rl_bin_size = le32_to_cpu(sos_hdr_v1_3->rl_size_bytes);
adev->psp.rl_start_addr = (uint8_t *)adev->psp.sys_start_addr +
le32_to_cpu(sos_hdr_v1_3->rl_offset_bytes);
} }
break; break;
default: default:
@ -2916,7 +3010,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev,
return ret; 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, 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, .rev = 0,
.funcs = &psp_ip_funcs, .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,
};

View File

@ -37,7 +37,7 @@
#define PSP_XGMI_SHARED_MEM_SIZE 0x4000 #define PSP_XGMI_SHARED_MEM_SIZE 0x4000
#define PSP_RAS_SHARED_MEM_SIZE 0x4000 #define PSP_RAS_SHARED_MEM_SIZE 0x4000
#define PSP_1_MEG 0x100000 #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_HDCP_SHARED_MEM_SIZE 0x4000
#define PSP_DTM_SHARED_MEM_SIZE 0x4000 #define PSP_DTM_SHARED_MEM_SIZE 0x4000
#define PSP_RAP_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 toc_bin_size;
uint32_t kdb_bin_size; uint32_t kdb_bin_size;
uint32_t spl_bin_size; uint32_t spl_bin_size;
uint32_t rl_bin_size;
uint8_t *sys_start_addr; uint8_t *sys_start_addr;
uint8_t *sos_start_addr; uint8_t *sos_start_addr;
uint8_t *toc_start_addr; uint8_t *toc_start_addr;
uint8_t *kdb_start_addr; uint8_t *kdb_start_addr;
uint8_t *spl_start_addr; uint8_t *spl_start_addr;
uint8_t *rl_start_addr;
/* tmr buffer */ /* tmr buffer */
struct amdgpu_bo *tmr_bo; 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 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_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, extern int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
uint32_t field_val, uint32_t mask, bool check_changed); 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_gpu_reset(struct amdgpu_device *adev);
int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx, int psp_update_vcn_sram(struct amdgpu_device *adev, int inst_idx,
uint64_t cmd_gpu_addr, int cmd_size); 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_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_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_securedisplay_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
int psp_rlc_autoload_start(struct psp_context *psp); 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, int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg,
uint32_t value); uint32_t value);
int psp_ring_cmd_submit(struct psp_context *psp, 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); const char *chip_name);
int psp_get_fw_attestation_records_addr(struct psp_context *psp, int psp_get_fw_attestation_records_addr(struct psp_context *psp,
uint64_t *output_ptr); uint64_t *output_ptr);
int psp_load_fw_list(struct psp_context *psp,
struct amdgpu_firmware_info **ucode_list, int ucode_count);
#endif #endif

View File

@ -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 ta_rap_cmd_output_data *rap_cmd_output;
struct drm_device *dev = adev_to_drm(adev); struct drm_device *dev = adev_to_drm(adev);
uint32_t op; uint32_t op;
enum ta_rap_status status;
int ret; int ret;
if (*pos || size != 2) if (*pos || size != 2)
@ -70,9 +71,8 @@ static ssize_t amdgpu_rap_debugfs_write(struct file *f, const char __user *buf,
switch (op) { switch (op) {
case 2: case 2:
ret = psp_rap_invoke(&adev->psp, op); ret = psp_rap_invoke(&adev->psp, op, &status);
if (!ret && status == TA_RAP_STATUS__SUCCESS) {
if (ret == TA_RAP_STATUS__SUCCESS) {
dev_info(adev->dev, "RAP L0 validate test success.\n"); dev_info(adev->dev, "RAP L0 validate test success.\n");
} else { } else {
rap_shared_mem = (struct ta_rap_shared_memory *) 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: default:
dev_info(adev->dev, "Unsupported op id: %d, ", op); dev_info(adev->dev, "Unsupported op id: %d, ", op);
dev_info(adev->dev, "Only support op 2(L0 validate test).\n"); dev_info(adev->dev, "Only support op 2(L0 validate test).\n");
break;
} }
amdgpu_gfx_off_ctrl(adev, true); amdgpu_gfx_off_ctrl(adev, true);

View File

@ -99,6 +99,49 @@ static bool amdgpu_ras_get_error_query_ready(struct amdgpu_device *adev)
return false; 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, static ssize_t amdgpu_ras_debugfs_read(struct file *f, char __user *buf,
size_t size, loff_t *pos) 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; ssize_t s;
char val[128]; char val[128];
if (amdgpu_ras_error_query(obj->adev, &info)) if (amdgpu_ras_query_error_status(obj->adev, &info))
return -EINVAL; return -EINVAL;
s = snprintf(val, sizeof(val), "%s: %lu\n%s: %lu\n", 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; op = 1;
else if (sscanf(str, "inject %32s %8s", block_name, err) == 2) else if (sscanf(str, "inject %32s %8s", block_name, err) == 2)
op = 2; op = 2;
else if (sscanf(str, "retire_page") == 0)
op = 3;
else if (str[0] && str[1] && str[2] && str[3]) else if (str[0] && str[1] && str[2] && str[3])
/* ascii string, but commands are not matched. */ /* ascii string, but commands are not matched. */
return -EINVAL; return -EINVAL;
if (op != -1) { 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)) if (amdgpu_ras_find_block_id_by_name(block_name, &block_id))
return -EINVAL; return -EINVAL;
@ -310,6 +367,16 @@ static ssize_t amdgpu_ras_debugfs_ctrl_write(struct file *f, const char __user *
if (ret) if (ret)
return -EINVAL; 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)) if (!amdgpu_ras_is_supported(adev, data.head.block))
return -EINVAL; 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)) if (!amdgpu_ras_get_error_query_ready(obj->adev))
return snprintf(buf, PAGE_SIZE, return sysfs_emit(buf, "Query currently inaccessible\n");
"Query currently inaccessible\n");
if (amdgpu_ras_error_query(obj->adev, &info)) if (amdgpu_ras_query_error_status(obj->adev, &info))
return -EINVAL; return -EINVAL;
return snprintf(buf, PAGE_SIZE, "%s: %lu\n%s: %lu\n", return sysfs_emit(buf, "%s: %lu\n%s: %lu\n", "ue", info.ue_count,
"ue", info.ue_count, "ce", info.ce_count);
"ce", info.ce_count);
} }
/* obj begin */ /* 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) static inline void put_obj(struct ras_manager *obj)
{ {
if (obj && --obj->use == 0) if (obj && (--obj->use == 0))
list_del(&obj->node); list_del(&obj->node);
if (obj && obj->use < 0) { if (obj && (obj->use < 0))
DRM_ERROR("RAS ERROR: Unbalance obj(%s) use\n", obj->head.name); DRM_ERROR("RAS ERROR: Unbalance obj(%s) use\n", obj->head.name);
}
} }
/* make one obj and return it. */ /* 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 amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_manager *obj; struct ras_manager *obj;
if (!con) if (!adev->ras_features || !con)
return NULL; return NULL;
if (head->block >= AMDGPU_RAS_BLOCK_COUNT) 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; struct ras_manager *obj;
int i; int i;
if (!con) if (!adev->ras_features || !con)
return NULL; return NULL;
if (head) { if (head) {
@ -590,7 +654,11 @@ static int __amdgpu_ras_feature_enable(struct amdgpu_device *adev,
con->features |= BIT(head->block); con->features |= BIT(head->block);
} else { } else {
if (obj && amdgpu_ras_is_feature_enabled(adev, head)) { if (obj && amdgpu_ras_is_feature_enabled(adev, head)) {
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); put_obj(obj);
} }
} }
@ -693,6 +761,10 @@ int amdgpu_ras_feature_enable_on_boot(struct amdgpu_device *adev,
if (ret) if (ret)
return 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); ret = amdgpu_ras_feature_enable(adev, head, 0);
} }
} else } else
@ -757,8 +829,8 @@ static int amdgpu_ras_enable_all_features(struct amdgpu_device *adev,
/* feature ctl end */ /* feature ctl end */
/* query/inject/cure begin */ /* query/inject/cure begin */
int amdgpu_ras_error_query(struct amdgpu_device *adev, int amdgpu_ras_query_error_status(struct amdgpu_device *adev,
struct ras_query_if *info) struct ras_query_if *info)
{ {
struct ras_manager *obj = amdgpu_ras_find_obj(adev, &info->head); struct ras_manager *obj = amdgpu_ras_find_obj(adev, &info->head);
struct ras_err_data err_data = {0, 0, 0, NULL}; 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) { switch (info->head.block) {
case AMDGPU_RAS_BLOCK__UMC: case AMDGPU_RAS_BLOCK__UMC:
if (adev->umc.funcs->query_ras_error_count) if (adev->umc.ras_funcs &&
adev->umc.funcs->query_ras_error_count(adev, &err_data); 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 /* umc query_ras_error_address is also responsible for clearing
* error status * error status
*/ */
if (adev->umc.funcs->query_ras_error_address) if (adev->umc.ras_funcs &&
adev->umc.funcs->query_ras_error_address(adev, &err_data); adev->umc.ras_funcs->query_ras_error_address)
adev->umc.ras_funcs->query_ras_error_address(adev, &err_data);
break; break;
case AMDGPU_RAS_BLOCK__SDMA: case AMDGPU_RAS_BLOCK__SDMA:
if (adev->sdma.funcs->query_ras_error_count) { if (adev->sdma.funcs->query_ras_error_count) {
@ -785,19 +859,32 @@ int amdgpu_ras_error_query(struct amdgpu_device *adev,
} }
break; break;
case AMDGPU_RAS_BLOCK__GFX: case AMDGPU_RAS_BLOCK__GFX:
if (adev->gfx.funcs->query_ras_error_count) if (adev->gfx.ras_funcs &&
adev->gfx.funcs->query_ras_error_count(adev, &err_data); 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; break;
case AMDGPU_RAS_BLOCK__MMHUB: case AMDGPU_RAS_BLOCK__MMHUB:
if (adev->mmhub.funcs->query_ras_error_count) if (adev->mmhub.ras_funcs &&
adev->mmhub.funcs->query_ras_error_count(adev, &err_data); 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; break;
case AMDGPU_RAS_BLOCK__PCIE_BIF: case AMDGPU_RAS_BLOCK__PCIE_BIF:
if (adev->nbio.funcs->query_ras_error_count) if (adev->nbio.ras_funcs &&
adev->nbio.funcs->query_ras_error_count(adev, &err_data); adev->nbio.ras_funcs->query_ras_error_count)
adev->nbio.ras_funcs->query_ras_error_count(adev, &err_data);
break; break;
case AMDGPU_RAS_BLOCK__XGMI_WAFL: 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; break;
default: default:
break; break;
@ -826,6 +913,38 @@ int amdgpu_ras_error_query(struct amdgpu_device *adev,
return 0; 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 */ /* Trigger XGMI/WAFL error */
static int amdgpu_ras_error_inject_xgmi(struct amdgpu_device *adev, static int amdgpu_ras_error_inject_xgmi(struct amdgpu_device *adev,
struct ta_ras_trigger_error_input *block_info) 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) { switch (info->head.block) {
case AMDGPU_RAS_BLOCK__GFX: case AMDGPU_RAS_BLOCK__GFX:
if (adev->gfx.funcs->ras_error_inject) if (adev->gfx.ras_funcs &&
ret = adev->gfx.funcs->ras_error_inject(adev, info); adev->gfx.ras_funcs->ras_error_inject)
ret = adev->gfx.ras_funcs->ras_error_inject(adev, info);
else else
ret = -EINVAL; ret = -EINVAL;
break; break;
case AMDGPU_RAS_BLOCK__UMC: case AMDGPU_RAS_BLOCK__UMC:
case AMDGPU_RAS_BLOCK__SDMA:
case AMDGPU_RAS_BLOCK__MMHUB: case AMDGPU_RAS_BLOCK__MMHUB:
case AMDGPU_RAS_BLOCK__PCIE_BIF: case AMDGPU_RAS_BLOCK__PCIE_BIF:
ret = psp_ras_trigger_error(&adev->psp, &block_info); 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_manager *obj;
struct ras_err_data data = {0, 0}; struct ras_err_data data = {0, 0};
if (!con) if (!adev->ras_features || !con)
return 0; return 0;
list_for_each_entry(obj, &con->head, node) { 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, .head = obj->head,
}; };
if (amdgpu_ras_error_query(adev, &info)) if (amdgpu_ras_query_error_status(adev, &info))
return 0; return 0;
data.ce_count += info.ce_count; data.ce_count += info.ce_count;
@ -1137,16 +1258,17 @@ static int amdgpu_ras_sysfs_remove_all(struct amdgpu_device *adev)
* *
*/ */
/* debugfs begin */ /* 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 amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct dentry *dir;
struct drm_minor *minor = adev_to_drm(adev)->primary; struct drm_minor *minor = adev_to_drm(adev)->primary;
con->dir = debugfs_create_dir(RAS_FS_NAME, minor->debugfs_root); dir = debugfs_create_dir(RAS_FS_NAME, minor->debugfs_root);
debugfs_create_file("ras_ctrl", S_IWUGO | S_IRUGO, con->dir, debugfs_create_file("ras_ctrl", S_IWUGO | S_IRUGO, dir, adev,
adev, &amdgpu_ras_debugfs_ctrl_ops); &amdgpu_ras_debugfs_ctrl_ops);
debugfs_create_file("ras_eeprom_reset", S_IWUGO | S_IRUGO, con->dir, debugfs_create_file("ras_eeprom_reset", S_IWUGO | S_IRUGO, dir, adev,
adev, &amdgpu_ras_debugfs_eeprom_ops); &amdgpu_ras_debugfs_eeprom_ops);
/* /*
* After one uncorrectable error happens, usually GPU recovery will * 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 * ERREVENT_ATHUB_INTERRUPT generated. Normal GPU recovery routine
* will never be called. * will never be called.
*/ */
debugfs_create_bool("auto_reboot", S_IWUGO | S_IRUGO, con->dir, debugfs_create_bool("auto_reboot", S_IWUGO | S_IRUGO, dir, &con->reboot);
&con->reboot);
/* /*
* User could set this not to clean up hardware's error count register * User could set this not to clean up hardware's error count register
* of RAS IPs during ras recovery. * of RAS IPs during ras recovery.
*/ */
debugfs_create_bool("disable_ras_err_cnt_harvest", 0644, debugfs_create_bool("disable_ras_err_cnt_harvest", 0644, dir,
con->dir, &con->disable_ras_err_cnt_harvest); &con->disable_ras_err_cnt_harvest);
return dir;
} }
static void amdgpu_ras_debugfs_create(struct amdgpu_device *adev, 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); struct ras_manager *obj = amdgpu_ras_find_obj(adev, &head->head);
if (!obj || obj->ent) if (!obj || !dir)
return; return;
get_obj(obj); get_obj(obj);
@ -1182,14 +1304,14 @@ static void amdgpu_ras_debugfs_create(struct amdgpu_device *adev,
head->debugfs_name, head->debugfs_name,
sizeof(obj->fs_data.debugfs_name)); sizeof(obj->fs_data.debugfs_name));
obj->ent = debugfs_create_file(obj->fs_data.debugfs_name, debugfs_create_file(obj->fs_data.debugfs_name, S_IWUGO | S_IRUGO, dir,
S_IWUGO | S_IRUGO, con->dir, obj, obj, &amdgpu_ras_debugfs_ops);
&amdgpu_ras_debugfs_ops);
} }
void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev) void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev)
{ {
struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct dentry *dir;
struct ras_manager *obj; struct ras_manager *obj;
struct ras_fs_if fs_info; 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) if (!IS_ENABLED(CONFIG_DEBUG_FS) || !con)
return; return;
amdgpu_ras_debugfs_create_ctrl_node(adev); dir = amdgpu_ras_debugfs_create_ctrl_node(adev);
list_for_each_entry(obj, &con->head, node) { list_for_each_entry(obj, &con->head, node) {
if (amdgpu_ras_is_supported(adev, obj->head.block) && 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", sprintf(fs_info.debugfs_name, "%s_err_inject",
ras_block_str(obj->head.block)); ras_block_str(obj->head.block));
fs_info.head = obj->head; 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 */ /* debugfs end */
/* ras fs */ /* 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) static int amdgpu_ras_fs_fini(struct amdgpu_device *adev)
{ {
if (IS_ENABLED(CONFIG_DEBUG_FS)) struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
amdgpu_ras_debugfs_remove_all(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); amdgpu_ras_sysfs_remove_all(adev);
return 0; 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 amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_manager *obj; struct ras_manager *obj;
if (!con) if (!adev->ras_features || !con)
return; return;
list_for_each_entry(obj, &con->head, node) { 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) if (info.head.block == AMDGPU_RAS_BLOCK__PCIE_BIF)
continue; 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) { switch (info->head.block) {
case AMDGPU_RAS_BLOCK__GFX: case AMDGPU_RAS_BLOCK__GFX:
if (adev->gfx.funcs->query_ras_error_status) if (adev->gfx.ras_funcs &&
adev->gfx.funcs->query_ras_error_status(adev); adev->gfx.ras_funcs->query_ras_error_status)
adev->gfx.ras_funcs->query_ras_error_status(adev);
break; break;
case AMDGPU_RAS_BLOCK__MMHUB: case AMDGPU_RAS_BLOCK__MMHUB:
if (adev->mmhub.funcs->query_ras_error_status) if (adev->mmhub.ras_funcs &&
adev->mmhub.funcs->query_ras_error_status(adev); adev->mmhub.ras_funcs->query_ras_error_status)
adev->mmhub.ras_funcs->query_ras_error_status(adev);
break; break;
default: default:
break; 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 amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_manager *obj; struct ras_manager *obj;
if (!con) if (!adev->ras_features || !con)
return; return;
list_for_each_entry(obj, &con->head, node) { 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; bool exc_err_limit = false;
int ret; int ret;
if (con) if (adev->ras_features && con)
data = &con->eh_data; data = &con->eh_data;
else else
return 0; 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(); max_eeprom_records_len = amdgpu_ras_eeprom_get_record_max_length();
amdgpu_ras_validate_threshold(adev, max_eeprom_records_len); 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); ret = amdgpu_ras_eeprom_init(&con->eeprom_control, &exc_err_limit);
/* /*
* This calling fails when exc_err_limit is true or * 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; 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 && return adev->asic_type == CHIP_VEGA10 ||
adev->asic_type != CHIP_VEGA20 && adev->asic_type == CHIP_VEGA20 ||
adev->asic_type != CHIP_ARCTURUS && adev->asic_type == CHIP_ARCTURUS ||
adev->asic_type != CHIP_SIENNA_CICHLID) adev->asic_type == CHIP_ALDEBARAN ||
return 1; adev->asic_type == CHIP_SIENNA_CICHLID;
else
return 0;
} }
/* /*
@ -1924,22 +2038,32 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev,
*supported = 0; *supported = 0;
if (amdgpu_sriov_vf(adev) || !adev->is_atom_fw || if (amdgpu_sriov_vf(adev) || !adev->is_atom_fw ||
amdgpu_ras_check_asic_type(adev)) !amdgpu_ras_asic_supported(adev))
return; return;
if (amdgpu_atomfirmware_mem_ecc_supported(adev)) { if (!adev->gmc.xgmi.connected_to_cpu) {
dev_info(adev->dev, "HBM ECC is active.\n"); if (amdgpu_atomfirmware_mem_ecc_supported(adev)) {
*hw_supported |= (1 << AMDGPU_RAS_BLOCK__UMC | dev_info(adev->dev, "MEM ECC is active.\n");
1 << AMDGPU_RAS_BLOCK__DF); *hw_supported |= (1 << AMDGPU_RAS_BLOCK__UMC |
} else 1 << AMDGPU_RAS_BLOCK__DF);
dev_info(adev->dev, "HBM ECC is not presented.\n"); } else {
dev_info(adev->dev, "MEM ECC is not presented.\n");
}
if (amdgpu_atomfirmware_sram_ecc_supported(adev)) { if (amdgpu_atomfirmware_sram_ecc_supported(adev)) {
dev_info(adev->dev, "SRAM ECC is active.\n"); dev_info(adev->dev, "SRAM ECC is active.\n");
*hw_supported |= ~(1 << AMDGPU_RAS_BLOCK__UMC | *hw_supported |= ~(1 << AMDGPU_RAS_BLOCK__UMC |
1 << AMDGPU_RAS_BLOCK__DF); 1 << AMDGPU_RAS_BLOCK__DF);
} else } else {
dev_info(adev->dev, "SRAM ECC is not presented.\n"); dev_info(adev->dev, "SRAM ECC is not presented.\n");
}
} 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 needs to be aligned with RAS block mask. */
*hw_supported &= AMDGPU_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, amdgpu_ras_check_supported(adev, &con->hw_supported,
&con->supported); &con->supported);
if (!con->hw_supported || (adev->asic_type == CHIP_VEGA10)) { 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; r = 0;
goto release_con; goto release_con;
} }
@ -1979,14 +2112,31 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
/* Might need get this flag from vbios. */ /* Might need get this flag from vbios. */
con->flags = RAS_DEFAULT_FLAGS; con->flags = RAS_DEFAULT_FLAGS;
if (adev->nbio.funcs->init_ras_controller_interrupt) { /* initialize nbio ras function ahead of any other
r = adev->nbio.funcs->init_ras_controller_interrupt(adev); * 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) if (r)
goto release_con; goto release_con;
} }
if (adev->nbio.funcs->init_ras_err_event_athub_interrupt) { if (adev->nbio.ras_funcs &&
r = adev->nbio.funcs->init_ras_err_event_athub_interrupt(adev); adev->nbio.ras_funcs->init_ras_err_event_athub_interrupt) {
r = adev->nbio.ras_funcs->init_ras_err_event_athub_interrupt(adev);
if (r) if (r)
goto release_con; goto release_con;
} }
@ -2007,6 +2157,32 @@ release_con:
return r; 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 */ /* helper function to handle common stuff in ip late init phase */
int amdgpu_ras_late_init(struct amdgpu_device *adev, int amdgpu_ras_late_init(struct amdgpu_device *adev,
struct ras_common_if *ras_block, struct ras_common_if *ras_block,
@ -2036,6 +2212,9 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev,
return r; 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 */ /* in resume phase, no need to create ras fs node */
if (adev->in_suspend || amdgpu_in_reset(adev)) if (adev->in_suspend || amdgpu_in_reset(adev))
return 0; return 0;
@ -2083,8 +2262,12 @@ void amdgpu_ras_resume(struct amdgpu_device *adev)
struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
struct ras_manager *obj, *tmp; struct ras_manager *obj, *tmp;
if (!con) if (!adev->ras_features || !con) {
/* clean ras context for VEGA20 Gaming after send ras disable cmd */
amdgpu_release_ras_context(adev);
return; return;
}
if (con->flags & AMDGPU_RAS_FLAG_INIT_BY_VBIOS) { if (con->flags & AMDGPU_RAS_FLAG_INIT_BY_VBIOS) {
/* Set up all other IPs which are not implemented. There is a /* 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); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
if (!con) if (!adev->ras_features || !con)
return; return;
amdgpu_ras_disable_all_features(adev, 0); 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); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
if (!con) if (!adev->ras_features || !con)
return 0; return 0;
/* Need disable ras on all IPs here before ip [hw/sw]fini */ /* Need disable ras on all IPs here before ip [hw/sw]fini */
@ -2152,7 +2335,7 @@ int amdgpu_ras_fini(struct amdgpu_device *adev)
{ {
struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
if (!con) if (!adev->ras_features || !con)
return 0; return 0;
amdgpu_ras_fs_fini(adev); amdgpu_ras_fs_fini(adev);
@ -2196,18 +2379,16 @@ bool amdgpu_ras_need_emergency_restart(struct amdgpu_device *adev)
return false; 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); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
bool exc_err_limit = false;
if (con && (amdgpu_bad_page_threshold != 0)) if (!con)
amdgpu_ras_eeprom_check_err_threshold(&con->eeprom_control, return;
&exc_err_limit);
/* if (!adev->ras_features && con->features & BIT(AMDGPU_RAS_BLOCK__GFX)) {
* We are only interested in variable exc_err_limit, con->features &= ~BIT(AMDGPU_RAS_BLOCK__GFX);
* as it says if GPU is in bad state or not. amdgpu_ras_set_context(adev, NULL);
*/ kfree(con);
return exc_err_limit; }
} }

View File

@ -318,8 +318,6 @@ struct amdgpu_ras {
uint32_t supported; uint32_t supported;
uint32_t features; uint32_t features;
struct list_head head; struct list_head head;
/* debugfs */
struct dentry *dir;
/* sysfs */ /* sysfs */
struct device_attribute features_attr; struct device_attribute features_attr;
struct bin_attribute badpages_attr; struct bin_attribute badpages_attr;
@ -395,8 +393,6 @@ struct ras_manager {
struct list_head node; struct list_head node;
/* the device */ /* the device */
struct amdgpu_device *adev; struct amdgpu_device *adev;
/* debugfs */
struct dentry *ent;
/* sysfs */ /* sysfs */
struct device_attribute sysfs_attr; struct device_attribute sysfs_attr;
int attr_inuse; 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, unsigned long amdgpu_ras_query_error_count(struct amdgpu_device *adev,
bool is_ce); bool is_ce);
bool amdgpu_ras_check_err_threshold(struct amdgpu_device *adev);
/* error handling functions */ /* error handling functions */
int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev,
struct eeprom_table_record *bps, int pages); 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); 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); 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, int amdgpu_ras_error_inject(struct amdgpu_device *adev,
struct ras_inject_if *info); 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); void amdgpu_ras_set_error_query_ready(struct amdgpu_device *adev, bool ready);
bool amdgpu_ras_need_emergency_restart(struct amdgpu_device *adev); bool amdgpu_ras_need_emergency_restart(struct amdgpu_device *adev);
void amdgpu_release_ras_context(struct amdgpu_device *adev);
#endif #endif

View File

@ -31,6 +31,7 @@
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS 0xA8 #define EEPROM_I2C_TARGET_ADDR_ARCTURUS 0xA8
#define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0xA0 #define EEPROM_I2C_TARGET_ADDR_ARCTURUS_D342 0xA0
#define EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID 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 * 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) || if ((adev->asic_type == CHIP_VEGA20) ||
(adev->asic_type == CHIP_ARCTURUS) || (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 true;
return false; return false;
@ -106,6 +108,10 @@ static bool __get_eeprom_i2c_addr(struct amdgpu_device *adev,
*i2c_addr = EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID; *i2c_addr = EEPROM_I2C_TARGET_ADDR_SIENNA_CICHLID;
break; break;
case CHIP_ALDEBARAN:
*i2c_addr = EEPROM_I2C_TARGET_ADDR_ALDEBARAN;
break;
default: default:
return false; return false;
} }
@ -434,47 +440,28 @@ static uint32_t __correct_eeprom_dest_address(uint32_t curr_address)
return curr_address; return curr_address;
} }
int amdgpu_ras_eeprom_check_err_threshold( bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev)
struct amdgpu_ras_eeprom_control *control,
bool *exceed_err_limit)
{ {
struct amdgpu_device *adev = to_amdgpu_device(control); struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
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;
if (!__is_ras_eeprom_supported(adev)) if (!__is_ras_eeprom_supported(adev))
return 0; return false;
/* read EEPROM table header */ /* skip check eeprom table for VEGA20 Gaming */
mutex_lock(&control->tbl_mutex); if (!con)
ret = i2c_transfer(&adev->pm.smu_i2c, &msg, 1); return false;
if (ret < 1) { else
dev_err(adev->dev, "Failed to read EEPROM table header.\n"); if (!(con->features & BIT(AMDGPU_RAS_BLOCK__UMC)))
goto err; return false;
}
__decode_table_header_from_buff(hdr, &buff[2]); if (con->eeprom_control.tbl_hdr.header == EEPROM_TABLE_HDR_BAD) {
if (hdr->header == EEPROM_TABLE_HDR_BAD) {
dev_warn(adev->dev, "This GPU is in BAD status."); dev_warn(adev->dev, "This GPU is in BAD status.");
dev_warn(adev->dev, "Please retire it or setting one bigger " dev_warn(adev->dev, "Please retire it or setting one bigger "
"threshold value when reloading driver.\n"); "threshold value when reloading driver.\n");
*exceed_err_limit = true; return true;
} }
err: return false;
mutex_unlock(&control->tbl_mutex);
return 0;
} }
int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control,

View File

@ -80,9 +80,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control,
bool *exceed_err_limit); bool *exceed_err_limit);
int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control); int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control);
int amdgpu_ras_eeprom_check_err_threshold( bool amdgpu_ras_eeprom_check_err_threshold(struct amdgpu_device *adev);
struct amdgpu_ras_eeprom_control *control,
bool *exceed_err_limit);
int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control, int amdgpu_ras_eeprom_process_recods(struct amdgpu_ras_eeprom_control *control,
struct eeprom_table_record *records, struct eeprom_table_record *records,

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -164,7 +164,8 @@ void amdgpu_ring_undo(struct amdgpu_ring *ring)
*/ */
int amdgpu_ring_init(struct amdgpu_device *adev, 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 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 r;
int sched_hw_submission = amdgpu_sched_hw_submission; 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->adev = adev;
ring->idx = adev->num_rings++; ring->idx = adev->num_rings++;
adev->rings[ring->idx] = ring; 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) if (r)
return r; return r;
} }

View File

@ -111,7 +111,8 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev);
void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring); void amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring);
int amdgpu_fence_driver_init_ring(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, int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
struct amdgpu_irq_src *irq_src, struct amdgpu_irq_src *irq_src,
unsigned irq_type); unsigned irq_type);
@ -282,7 +283,8 @@ void amdgpu_ring_commit(struct amdgpu_ring *ring);
void amdgpu_ring_undo(struct amdgpu_ring *ring); void amdgpu_ring_undo(struct amdgpu_ring *ring);
int amdgpu_ring_init(struct amdgpu_device *adev, 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 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_fini(struct amdgpu_ring *ring);
void amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring, void amdgpu_ring_emit_reg_write_reg_wait_helper(struct amdgpu_ring *ring,
uint32_t reg0, uint32_t val0, uint32_t reg0, uint32_t val0,

View File

@ -127,7 +127,8 @@ struct amdgpu_rlc_funcs {
void (*reset)(struct amdgpu_device *adev); void (*reset)(struct amdgpu_device *adev);
void (*start)(struct amdgpu_device *adev); void (*start)(struct amdgpu_device *adev);
void (*update_spm_vmid)(struct amdgpu_device *adev, unsigned vmid); 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); bool (*is_rlcg_access_range)(struct amdgpu_device *adev, uint32_t reg);
}; };

View File

@ -64,6 +64,11 @@ struct amdgpu_sdma {
struct amdgpu_irq_src trap_irq; struct amdgpu_irq_src trap_irq;
struct amdgpu_irq_src illegal_inst_irq; struct amdgpu_irq_src illegal_inst_irq;
struct amdgpu_irq_src ecc_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; int num_instances;
uint32_t srbm_soft_reset; uint32_t srbm_soft_reset;
bool has_page_queue; bool has_page_queue;

View File

@ -69,6 +69,9 @@ void psp_securedisplay_parse_resp_status(struct psp_context *psp,
case TA_SECUREDISPLAY_STATUS__READ_CRC_ERROR: case TA_SECUREDISPLAY_STATUS__READ_CRC_ERROR:
dev_err(psp->adev->dev, "Secure display: Failed to Read CRC"); dev_err(psp->adev->dev, "Secure display: Failed to Read CRC");
break; break;
case TA_SECUREDISPLAY_STATUS__I2C_INIT_ERROR:
dev_err(psp->adev->dev, "Secure display: Failed to initialize I2C.");
break;
default: default:
dev_err(psp->adev->dev, "Secure display: Failed to parse status: %d\n", status); 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); struct drm_device *dev = adev_to_drm(adev);
uint32_t phy_id; uint32_t phy_id;
uint32_t op; uint32_t op;
int i;
char str[64]; char str[64];
char i2c_output[256];
int ret; int ret;
if (*pos || size > sizeof(str) - 1) 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); ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
if (!ret) { if (!ret) {
if (securedisplay_cmd->status == TA_SECUREDISPLAY_STATUS__SUCCESS) { if (securedisplay_cmd->status == TA_SECUREDISPLAY_STATUS__SUCCESS) {
memset(i2c_output, 0, sizeof(i2c_output)); dev_info(adev->dev, "SECUREDISPLAY: I2C buffer out put is: %*ph\n",
for (i = 0; i < TA_SECUREDISPLAY_I2C_BUFFER_SIZE; i++) TA_SECUREDISPLAY_I2C_BUFFER_SIZE,
sprintf(i2c_output, "%s 0x%X", i2c_output, securedisplay_cmd->securedisplay_out_message.send_roi_crc.i2c_buf);
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);
} else { } else {
psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status); psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
} }

View File

@ -28,6 +28,8 @@ struct amdgpu_smuio_funcs {
u32 (*get_rom_data_offset)(struct amdgpu_device *adev); u32 (*get_rom_data_offset)(struct amdgpu_device *adev);
void (*update_rom_clock_gating)(struct amdgpu_device *adev, bool enable); void (*update_rom_clock_gating)(struct amdgpu_device *adev, bool enable);
void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags); void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags);
u32 (*get_die_id)(struct amdgpu_device *adev);
bool (*is_host_gpu_xgmi_supported)(struct amdgpu_device *adev);
}; };
struct amdgpu_smuio { struct amdgpu_smuio {

View File

@ -62,6 +62,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev)
bp.flags = 0; bp.flags = 0;
bp.type = ttm_bo_type_kernel; bp.type = ttm_bo_type_kernel;
bp.resv = NULL; bp.resv = NULL;
bp.bo_ptr_size = sizeof(struct amdgpu_bo);
r = amdgpu_bo_create(adev, &bp, &vram_obj); r = amdgpu_bo_create(adev, &bp, &vram_obj);
if (r) { if (r) {

View File

@ -47,7 +47,6 @@
#include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h> #include <drm/ttm/ttm_placement.h>
#include <drm/drm_debugfs.h>
#include <drm/amdgpu_drm.h> #include <drm/amdgpu_drm.h>
#include "amdgpu.h" #include "amdgpu.h"
@ -57,14 +56,15 @@
#include "amdgpu_sdma.h" #include "amdgpu_sdma.h"
#include "amdgpu_ras.h" #include "amdgpu_ras.h"
#include "amdgpu_atomfirmware.h" #include "amdgpu_atomfirmware.h"
#include "amdgpu_res_cursor.h"
#include "bif/bif_4_1_d.h" #include "bif/bif_4_1_d.h"
#define AMDGPU_TTM_VRAM_MAX_DW_READ (size_t)128 #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_tt *ttm,
struct ttm_resource *bo_mem); 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); struct ttm_tt *ttm);
static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev, 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); 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 * amdgpu_ttm_map_buffer - Map memory into the GART windows
* @bo: buffer object to map * @bo: buffer object to map
* @mem: memory 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 * @num_pages: number of pages to map
* @offset: offset into @mm_node where to start
* @window: which GART window to use * @window: which GART window to use
* @ring: DMA ring to use for the copy * @ring: DMA ring to use for the copy
* @tmz: if we should setup a TMZ enabled mapping * @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, static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
struct ttm_resource *mem, struct ttm_resource *mem,
struct drm_mm_node *mm_node, struct amdgpu_res_cursor *mm_cur,
unsigned num_pages, uint64_t offset, unsigned num_pages, unsigned window,
unsigned window, struct amdgpu_ring *ring, struct amdgpu_ring *ring, bool tmz,
bool tmz, uint64_t *addr) uint64_t *addr)
{ {
struct amdgpu_device *adev = ring->adev; struct amdgpu_device *adev = ring->adev;
struct amdgpu_job *job; 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 */ /* Map only what can't be accessed directly */
if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) { 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; return 0;
} }
*addr = adev->gmc.gart_start; *addr = adev->gmc.gart_start;
*addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE * *addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE *
AMDGPU_GPU_PAGE_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_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
num_bytes = num_pages * 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]; cpu_addr = &job->ibs[0].ptr[num_dw];
if (mem->mem_type == TTM_PL_TT) { 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]; dma_addr = &bo->ttm->dma_address[mm_cur->start >> PAGE_SHIFT];
r = amdgpu_gart_map(adev, 0, num_pages, dma_address, flags, r = amdgpu_gart_map(adev, 0, num_pages, dma_addr, flags,
cpu_addr); cpu_addr);
if (r) if (r)
goto error_free; goto error_free;
} else { } else {
dma_addr_t dma_address; 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; dma_address += adev->vm_manager.vram_base_offset;
for (i = 0; i < num_pages; ++i) { 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 * const uint32_t GTT_MAX_BYTES = (AMDGPU_GTT_MAX_TRANSFER_SIZE *
AMDGPU_GPU_PAGE_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 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; struct dma_fence *fence = NULL;
int r = 0; int r = 0;
@ -365,29 +322,13 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
return -EINVAL; return -EINVAL;
} }
src_offset = src->offset; amdgpu_res_first(src->mem, src->offset, size, &src_mm);
if (src->mem->mm_node) { amdgpu_res_first(dst->mem, dst->offset, size, &dst_mm);
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;
}
mutex_lock(&adev->mman.gtt_window_lock); mutex_lock(&adev->mman.gtt_window_lock);
while (src_mm.remaining) {
while (size) { uint32_t src_page_offset = src_mm.start & ~PAGE_MASK;
uint32_t src_page_offset = src_offset & ~PAGE_MASK; uint32_t dst_page_offset = dst_mm.start & ~PAGE_MASK;
uint32_t dst_page_offset = dst_offset & ~PAGE_MASK;
struct dma_fence *next; struct dma_fence *next;
uint32_t cur_size; uint32_t cur_size;
uint64_t from, to; 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 * begins at an offset, then adjust the size accordingly
*/ */
cur_size = max(src_page_offset, dst_page_offset); 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)); (uint64_t)(GTT_MAX_BYTES - cur_size));
/* Map src to window 0 and dst to window 1. */ /* 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), PFN_UP(cur_size + src_page_offset),
src_offset, 0, ring, tmz, &from); 0, ring, tmz, &from);
if (r) if (r)
goto error; 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), PFN_UP(cur_size + dst_page_offset),
dst_offset, 1, ring, tmz, &to); 1, ring, tmz, &to);
if (r) if (r)
goto error; goto error;
@ -420,27 +361,8 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
dma_fence_put(fence); dma_fence_put(fence);
fence = next; fence = next;
size -= cur_size; amdgpu_res_next(&src_mm, cur_size);
if (!size) amdgpu_res_next(&dst_mm, cur_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;
}
} }
error: error:
mutex_unlock(&adev->mman.gtt_window_lock); mutex_unlock(&adev->mman.gtt_window_lock);
@ -519,7 +441,8 @@ error:
static bool amdgpu_mem_visible(struct amdgpu_device *adev, static bool amdgpu_mem_visible(struct amdgpu_device *adev,
struct ttm_resource *mem) 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 || if (mem->mem_type == TTM_PL_SYSTEM ||
mem->mem_type == TTM_PL_TT) 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) if (mem->mem_type != TTM_PL_VRAM)
return false; return false;
amdgpu_res_first(mem, 0, mem_size, &cursor);
/* ttm_resource_ioremap only supports contiguous memory */ /* ttm_resource_ioremap only supports contiguous memory */
if (nodes->size != mem->num_pages) if (cursor.size != mem_size)
return false; return false;
return ((nodes->start + nodes->size) << PAGE_SHIFT) return cursor.start + cursor.size <= adev->gmc.visible_vram_size;
<= adev->gmc.visible_vram_size;
} }
/* /*
@ -646,7 +570,7 @@ out:
* *
* Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault() * 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 amdgpu_device *adev = amdgpu_ttm_adev(bdev);
struct drm_mm_node *mm_node = mem->mm_node; 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.offset += adev->gmc.aper_base;
mem->bus.is_iomem = true; 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; break;
default: default:
return -EINVAL; return -EINVAL;
@ -686,12 +613,10 @@ static unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
unsigned long page_offset) unsigned long page_offset)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
uint64_t offset = (page_offset << PAGE_SHIFT); struct amdgpu_res_cursor cursor;
struct drm_mm_node *mm;
mm = amdgpu_find_mm_node(&bo->mem, &offset); amdgpu_res_first(&bo->mem, (u64)page_offset << PAGE_SHIFT, 0, &cursor);
offset += adev->gmc.aper_base; return (adev->gmc.aper_base + cursor.start) >> PAGE_SHIFT;
return mm->start + (offset >> 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() * 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 ttm_tt *ttm)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
struct amdgpu_ttm_tt *gtt = (void *)ttm; struct amdgpu_ttm_tt *gtt = (void *)ttm;
int r;
int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY); int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
enum dma_data_direction direction = write ? enum dma_data_direction direction = write ?
DMA_BIDIRECTIONAL : DMA_TO_DEVICE; DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
int r;
/* Allocate an SG array and squash pages into it */ /* Allocate an SG array and squash pages into it */
r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0, 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 * 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 ttm_tt *ttm)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
struct amdgpu_ttm_tt *gtt = (void *)ttm; struct amdgpu_ttm_tt *gtt = (void *)ttm;
int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY); int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
enum dma_data_direction direction = write ? enum dma_data_direction direction = write ?
DMA_BIDIRECTIONAL : DMA_TO_DEVICE; DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
/* double check that we don't free the table twice */ /* double check that we don't free the table twice */
if (!ttm->sg->sgl) if (!ttm->sg || !ttm->sg->sgl)
return; return;
/* unmap the pages mapped to the device */ /* 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(). * Called by ttm_tt_bind() on behalf of ttm_bo_handle_move_mem().
* This handles binding GTT memory to the device address space. * 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_tt *ttm,
struct ttm_resource *bo_mem) 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 * Called by ttm_tt_unbind() on behalf of ttm_bo_move_ttm() and
* ttm_tt_destroy(). * 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 ttm_tt *ttm)
{ {
struct amdgpu_device *adev = amdgpu_ttm_adev(bdev); struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
struct amdgpu_ttm_tt *gtt = (void *)ttm; struct amdgpu_ttm_tt *gtt = (void *)ttm;
int r; int r;
if (!gtt->bound)
return;
/* if the pages have userptr pinning then clear that first */ /* if the pages have userptr pinning then clear that first */
if (gtt->userptr) if (gtt->userptr)
amdgpu_ttm_tt_unpin_userptr(bdev, ttm); amdgpu_ttm_tt_unpin_userptr(bdev, ttm);
if (!gtt->bound)
return;
if (gtt->offset == AMDGPU_BO_INVALID_OFFSET) if (gtt->offset == AMDGPU_BO_INVALID_OFFSET)
return; return;
@ -1180,7 +1103,7 @@ static void amdgpu_ttm_backend_unbind(struct ttm_bo_device *bdev,
gtt->bound = false; 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 ttm_tt *ttm)
{ {
struct amdgpu_ttm_tt *gtt = (void *)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 * Map the pages of a ttm_tt object to an address space visible
* to the underlying device. * 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_tt *ttm,
struct ttm_operation_ctx *ctx) 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 * Unmaps pages of a ttm_tt object from the device address space and
* unpopulates the page array backing it. * 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 ttm_tt *ttm)
{ {
struct amdgpu_ttm_tt *gtt = (void *)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; flags |= AMDGPU_PTE_SNOOPED;
} }
if (mem && mem->mem_type == TTM_PL_VRAM &&
mem->bus.caching == ttm_cached)
flags |= AMDGPU_PTE_SNOOPED;
return flags; return flags;
} }
@ -1469,7 +1396,7 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
const struct ttm_place *place) const struct ttm_place *place)
{ {
unsigned long num_pages = bo->mem.num_pages; 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_resv_list *flist;
struct dma_fence *f; struct dma_fence *f;
int i; int i;
@ -1501,13 +1428,15 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
case TTM_PL_VRAM: case TTM_PL_VRAM:
/* Check each drm MM node individually */ /* Check each drm MM node individually */
while (num_pages) { amdgpu_res_first(&bo->mem, 0, (u64)num_pages << PAGE_SHIFT,
if (place->fpfn < (node->start + node->size) && &cursor);
!(place->lpfn && place->lpfn <= node->start)) while (cursor.remaining) {
if (place->fpfn < PFN_DOWN(cursor.start + cursor.size)
&& !(place->lpfn &&
place->lpfn <= PFN_DOWN(cursor.start)))
return true; return true;
num_pages -= node->size; amdgpu_res_next(&cursor, cursor.size);
++node;
} }
return false; return false;
@ -1531,41 +1460,36 @@ static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
* access for debugging purposes. * access for debugging purposes.
*/ */
static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo, static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
unsigned long offset, unsigned long offset, void *buf, int len,
void *buf, int len, int write) int write)
{ {
struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo); struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); 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; uint32_t value = 0;
int ret = 0; int ret = 0;
uint64_t pos;
unsigned long flags;
if (bo->mem.mem_type != TTM_PL_VRAM) if (bo->mem.mem_type != TTM_PL_VRAM)
return -EIO; return -EIO;
pos = offset; amdgpu_res_first(&bo->mem, offset, len, &cursor);
nodes = amdgpu_find_mm_node(&abo->tbo.mem, &pos); while (cursor.remaining) {
pos += (nodes->start << PAGE_SHIFT); uint64_t aligned_pos = cursor.start & ~(uint64_t)3;
uint64_t bytes = 4 - (cursor.start & 3);
while (len && pos < adev->gmc.mc_vram_size) { uint32_t shift = (cursor.start & 3) * 8;
uint64_t aligned_pos = pos & ~(uint64_t)3;
uint64_t bytes = 4 - (pos & 3);
uint32_t shift = (pos & 3) * 8;
uint32_t mask = 0xffffffff << shift; uint32_t mask = 0xffffffff << shift;
if (len < bytes) { if (cursor.size < bytes) {
mask &= 0xffffffff >> (bytes - len) * 8; mask &= 0xffffffff >> (bytes - cursor.size) * 8;
bytes = len; bytes = cursor.size;
} }
if (mask != 0xffffffff) { if (mask != 0xffffffff) {
spin_lock_irqsave(&adev->mmio_idx_lock, flags); spin_lock_irqsave(&adev->mmio_idx_lock, flags);
WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t)aligned_pos) | 0x80000000); WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t)aligned_pos) | 0x80000000);
WREG32_NO_KIQ(mmMM_INDEX_HI, aligned_pos >> 31); 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) { if (write) {
value &= ~mask; value &= ~mask;
value |= (*(uint32_t *)buf << shift) & 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); memcpy(buf, &value, bytes);
} }
} else { } else {
bytes = (nodes->start + nodes->size) << PAGE_SHIFT; bytes = cursor.size & ~0x3ULL;
bytes = min(bytes - pos, (uint64_t)len & ~0x3ull); amdgpu_device_vram_access(adev, cursor.start,
(uint32_t *)buf, bytes,
amdgpu_device_vram_access(adev, pos, (uint32_t *)buf, write);
bytes, write);
} }
ret += bytes; ret += bytes;
buf = (uint8_t *)buf + bytes; buf = (uint8_t *)buf + bytes;
pos += bytes; amdgpu_res_next(&cursor, bytes);
len -= bytes;
if (pos >= (nodes->start + nodes->size) << PAGE_SHIFT) {
++nodes;
pos = (nodes->start << PAGE_SHIFT);
}
} }
return ret; return ret;
@ -1603,7 +1521,7 @@ amdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo)
amdgpu_bo_move_notify(bo, false, NULL); 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_create = &amdgpu_ttm_tt_create,
.ttm_tt_populate = &amdgpu_ttm_tt_populate, .ttm_tt_populate = &amdgpu_ttm_tt_populate,
.ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate, .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); (adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET);
ctx->train_data_size = ctx->train_data_size =
GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES; GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES;
DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n", DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n",
ctx->train_data_size, ctx->train_data_size,
ctx->p2c_train_data_offset, ctx->p2c_train_data_offset,
@ -1785,7 +1703,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
mutex_init(&adev->mman.gtt_window_lock); mutex_init(&adev->mman.gtt_window_lock);
/* No others user of address space so set it to 0 */ /* 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)->anon_inode->i_mapping,
adev_to_drm(adev)->vma_offset_manager, adev_to_drm(adev)->vma_offset_manager,
adev->need_swiotlb, 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 */ /* Change the size here instead of the init above so only lpfn is affected */
amdgpu_ttm_set_buffer_funcs_status(adev, false); amdgpu_ttm_set_buffer_funcs_status(adev, false);
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base, #ifdef CONFIG_X86
adev->gmc.visible_vram_size); 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 #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_GDS);
ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS); ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS);
ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA); 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; adev->mman.initialized = false;
DRM_INFO("amdgpu: ttm finalized\n"); DRM_INFO("amdgpu: ttm finalized\n");
} }
@ -2002,7 +1927,7 @@ unlock:
return ret; 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, .fault = amdgpu_ttm_fault,
.open = ttm_bo_vm_open, .open = ttm_bo_vm_open,
.close = ttm_bo_vm_close, .close = ttm_bo_vm_close,
@ -2053,7 +1978,8 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
return r; return r;
if (vm_needs_flush) { 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; job->vm_needs_flush = true;
} }
if (resv) { 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; uint32_t max_bytes = adev->mman.buffer_funcs->fill_max_bytes;
struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
struct drm_mm_node *mm_node; struct amdgpu_res_cursor cursor;
unsigned long num_pages;
unsigned int num_loops, num_dw; unsigned int num_loops, num_dw;
uint64_t num_bytes;
struct amdgpu_job *job; struct amdgpu_job *job;
int r; int r;
@ -2122,15 +2048,13 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
return r; return r;
} }
num_pages = bo->tbo.mem.num_pages; num_bytes = bo->tbo.mem.num_pages << PAGE_SHIFT;
mm_node = bo->tbo.mem.mm_node;
num_loops = 0; 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); amdgpu_res_first(&bo->tbo.mem, 0, num_bytes, &cursor);
num_pages -= mm_node->size; while (cursor.remaining) {
++mm_node; 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; 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; amdgpu_res_first(&bo->tbo.mem, 0, num_bytes, &cursor);
mm_node = bo->tbo.mem.mm_node; while (cursor.remaining) {
uint32_t cur_size = min_t(uint64_t, cursor.size, max_bytes);
uint64_t dst_addr = cursor.start;
while (num_pages) { dst_addr += amdgpu_ttm_domain_start(adev, bo->tbo.mem.mem_type);
uint64_t byte_count = mm_node->size << PAGE_SHIFT; amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data, dst_addr,
uint64_t dst_addr; cur_size);
dst_addr = amdgpu_mm_node_addr(&bo->tbo, mm_node, &bo->tbo.mem); amdgpu_res_next(&cursor, cur_size);
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_ring_pad_ib(ring, &job->ibs[0]); amdgpu_ring_pad_ib(ring, &job->ibs[0]);
@ -2191,36 +2104,74 @@ error_free:
#if defined(CONFIG_DEBUG_FS) #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; struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
unsigned ttm_pl = (uintptr_t)node->info_ent->data; struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev,
struct drm_device *dev = node->minor->dev; TTM_PL_VRAM);
struct amdgpu_device *adev = drm_to_adev(dev);
struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, ttm_pl);
struct drm_printer p = drm_seq_file_printer(m); struct drm_printer p = drm_seq_file_printer(m);
man->func->debug(man, &p); man->func->debug(man, &p);
return 0; 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 amdgpu_device *adev = (struct amdgpu_device *)m->private;
struct drm_device *dev = node->minor->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
return ttm_pool_debugfs(&adev->mman.bdev.pool, m); return ttm_pool_debugfs(&adev->mman.bdev.pool, m);
} }
static const struct drm_info_list amdgpu_ttm_debugfs_list[] = { static int amdgpu_mm_tt_table_show(struct seq_file *m, void *unused)
{"amdgpu_vram_mm", amdgpu_mm_dump_table, 0, (void *)TTM_PL_VRAM}, {
{"amdgpu_gtt_mm", amdgpu_mm_dump_table, 0, (void *)TTM_PL_TT}, struct amdgpu_device *adev = (struct amdgpu_device *)m->private;
{"amdgpu_gds_mm", amdgpu_mm_dump_table, 0, (void *)AMDGPU_PL_GDS}, struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev,
{"amdgpu_gws_mm", amdgpu_mm_dump_table, 0, (void *)AMDGPU_PL_GWS}, TTM_PL_TT);
{"amdgpu_oa_mm", amdgpu_mm_dump_table, 0, (void *)AMDGPU_PL_OA}, struct drm_printer p = drm_seq_file_printer(m);
{"ttm_page_pool", amdgpu_ttm_pool_debugfs, 0, NULL},
}; 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 * 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, .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 * 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 .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 #endif
int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev) void amdgpu_ttm_debugfs_init(struct amdgpu_device *adev)
{ {
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
unsigned count;
struct drm_minor *minor = adev_to_drm(adev)->primary; 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++) { debugfs_create_file_size("amdgpu_vram", 0444, root, adev,
ent = debugfs_create_file( &amdgpu_ttm_vram_fops, adev->gmc.mc_vram_size);
ttm_debugfs_entries[count].name, debugfs_create_file("amdgpu_iomem", 0444, root, adev,
S_IFREG | S_IRUGO, root, &amdgpu_ttm_iomem_fops);
adev, debugfs_create_file("amdgpu_vram_mm", 0444, root, adev,
ttm_debugfs_entries[count].fops); &amdgpu_mm_vram_table_fops);
if (IS_ERR(ent)) debugfs_create_file("amdgpu_gtt_mm", 0444, root, adev,
return PTR_ERR(ent); &amdgpu_mm_tt_table_fops);
if (ttm_debugfs_entries[count].domain == TTM_PL_VRAM) debugfs_create_file("amdgpu_gds_mm", 0444, root, adev,
i_size_write(ent->d_inode, adev->gmc.mc_vram_size); &amdgpu_mm_gds_table_fops);
else if (ttm_debugfs_entries[count].domain == TTM_PL_TT) debugfs_create_file("amdgpu_gws_mm", 0444, root, adev,
i_size_write(ent->d_inode, adev->gmc.gart_size); &amdgpu_mm_gws_table_fops);
adev->mman.debugfs_entries[count] = ent; debugfs_create_file("amdgpu_oa_mm", 0444, root, adev,
} &amdgpu_mm_oa_table_fops);
debugfs_create_file("ttm_page_pool", 0444, root, adev,
count = ARRAY_SIZE(amdgpu_ttm_debugfs_list); &amdgpu_ttm_page_pool_fops);
return amdgpu_debugfs_add_files(adev, amdgpu_ttm_debugfs_list, count);
#else
return 0;
#endif #endif
} }

View File

@ -60,14 +60,10 @@ struct amdgpu_gtt_mgr {
}; };
struct amdgpu_mman { struct amdgpu_mman {
struct ttm_bo_device bdev; struct ttm_device bdev;
bool initialized; bool initialized;
void __iomem *aper_base_kaddr; void __iomem *aper_base_kaddr;
#if defined(CONFIG_DEBUG_FS)
struct dentry *debugfs_entries[8];
#endif
/* buffer handling */ /* buffer handling */
const struct amdgpu_buffer_funcs *buffer_funcs; const struct amdgpu_buffer_funcs *buffer_funcs;
struct amdgpu_ring *buffer_funcs_ring; struct amdgpu_ring *buffer_funcs_ring;
@ -119,8 +115,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
struct device *dev, struct device *dev,
enum dma_data_direction dir, enum dma_data_direction dir,
struct sg_table **sgt); struct sg_table **sgt);
void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev, void amdgpu_vram_mgr_free_sgt(struct device *dev,
struct device *dev,
enum dma_data_direction dir, enum dma_data_direction dir,
struct sg_table *sgt); struct sg_table *sgt);
uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man); 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, uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
struct ttm_resource *mem); struct ttm_resource *mem);
int amdgpu_ttm_debugfs_init(struct amdgpu_device *adev); void amdgpu_ttm_debugfs_init(struct amdgpu_device *adev);
#endif #endif

Some files were not shown because too many files have changed in this diff Show More