Merge tag 'amd-drm-next-5.17-2021-12-16' of https://gitlab.freedesktop.org/agd5f/linux into drm-next

amdgpu:
- Add some display debugfs entries
- RAS fixes
- SR-IOV fixes
- W=1 fixes
- Documentation fixes
- IH timestamp fix
- Misc power fixes
- IP discovery fixes
- Large driver documentation updates
- Multi-GPU memory use reductions
- Misc display fixes and cleanups
- Add new SMU debug option

amdkfd:
- SVM fixes

radeon:
- Fix typo in comment

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211216202731.5900-1-alexander.deucher@amd.com
This commit is contained in:
Dave Airlie 2021-12-23 11:55:28 +10:00
commit b06103b532
204 changed files with 5797 additions and 2577 deletions

View File

@ -1,74 +0,0 @@
===================================
drm/amd/display - Display Core (DC)
===================================
*placeholder - general description of supported platforms, what dc is, etc.*
Because it is partially shared with other operating systems, the Display Core
Driver is divided in two pieces.
1. **Display Core (DC)** contains the OS-agnostic components. Things like
hardware programming and resource management are handled here.
2. **Display Manager (DM)** contains the OS-dependent components. Hooks to the
amdgpu base driver and DRM are implemented here.
It doesn't help that the entire package is frequently referred to as DC. But
with the context in mind, it should be clear.
When CONFIG_DRM_AMD_DC is enabled, DC will be initialized by default for
supported ASICs. To force disable, set `amdgpu.dc=0` on kernel command line.
Likewise, to force enable on unsupported ASICs, set `amdgpu.dc=1`.
To determine if DC is loaded, search dmesg for the following entry:
``Display Core initialized with <version number here>``
AMDgpu Display Manager
======================
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:doc: overview
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
:internal:
Lifecycle
---------
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:doc: DM Lifecycle
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:functions: dm_hw_init dm_hw_fini
Interrupts
----------
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
:doc: overview
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
:internal:
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:functions: register_hpd_handlers dm_crtc_high_irq dm_pflip_high_irq
Atomic Implementation
---------------------
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:doc: atomic
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:functions: amdgpu_dm_atomic_check amdgpu_dm_atomic_commit_tail
Display Core
============
**WIP**
FreeSync Video
--------------
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:doc: FreeSync Video

View File

@ -1,324 +0,0 @@
=========================
drm/amdgpu AMDgpu driver
=========================
The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core
Next (GCN) architecture.
Module Parameters
=================
The amdgpu driver supports the following module parameters:
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
Core Driver Infrastructure
==========================
This section covers core driver infrastructure.
.. _amdgpu_memory_domains:
Memory Domains
--------------
.. kernel-doc:: include/uapi/drm/amdgpu_drm.h
:doc: memory domains
Buffer Objects
--------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:doc: amdgpu_object
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:internal:
PRIME Buffer Sharing
--------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
:doc: PRIME Buffer Sharing
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
:internal:
MMU Notifier
------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:doc: MMU Notifier
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:internal:
AMDGPU Virtual Memory
---------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:doc: GPUVM
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:internal:
Interrupt Handling
------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:doc: Interrupt Handling
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:internal:
IP Blocks
------------------
.. kernel-doc:: drivers/gpu/drm/amd/include/amd_shared.h
:doc: IP Blocks
.. kernel-doc:: drivers/gpu/drm/amd/include/amd_shared.h
:identifiers: amd_ip_block_type amd_ip_funcs
AMDGPU XGMI Support
===================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
AMDGPU RAS Support
==================
The AMDGPU RAS interfaces are exposed via sysfs (for informational queries) and
debugfs (for error injection).
RAS debugfs/sysfs Control and Error Injection Interfaces
--------------------------------------------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS debugfs control interface
RAS Reboot Behavior for Unrecoverable Errors
--------------------------------------------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS Reboot Behavior for Unrecoverable Errors
RAS Error Count sysfs Interface
-------------------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS sysfs Error Count Interface
RAS EEPROM debugfs Interface
----------------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS debugfs EEPROM table reset interface
RAS VRAM Bad Pages sysfs Interface
----------------------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS sysfs gpu_vram_bad_pages Interface
Sample Code
-----------
Sample code for testing error injection can be found here:
https://cgit.freedesktop.org/mesa/drm/tree/tests/amdgpu/ras_tests.c
This is part of the libdrm amdgpu unit tests which cover several areas of the GPU.
There are four sets of tests:
RAS Basic Test
The test verifies the RAS feature enabled status and makes sure the necessary sysfs and debugfs files
are present.
RAS Query Test
This test checks the RAS availability and enablement status for each supported IP block as well as
the error counts.
RAS Inject Test
This test injects errors for each IP.
RAS Disable Test
This test tests disabling of RAS features for each IP block.
GPU Power/Thermal Controls and Monitoring
=========================================
This section covers hwmon and power/thermal controls.
HWMON Interfaces
----------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: hwmon
GPU sysfs Power State Interfaces
--------------------------------
GPU power controls are exposed via sysfs files.
power_dpm_state
~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: power_dpm_state
power_dpm_force_performance_level
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: power_dpm_force_performance_level
pp_table
~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_table
pp_od_clk_voltage
~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_od_clk_voltage
pp_dpm_*
~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk pp_dpm_pcie
pp_power_profile_mode
~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_power_profile_mode
\*_busy_percent
~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: gpu_busy_percent
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: mem_busy_percent
gpu_metrics
~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: gpu_metrics
GPU Product Information
=======================
Information about the GPU can be obtained on certain cards
via sysfs
product_name
------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: product_name
product_number
--------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: product_name
serial_number
-------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: serial_number
unique_id
---------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: unique_id
GPU Memory Usage Information
============================
Various memory accounting can be accessed via sysfs
mem_info_vram_total
-------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vram_total
mem_info_vram_used
------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vram_used
mem_info_vis_vram_total
-----------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vis_vram_total
mem_info_vis_vram_used
----------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vis_vram_used
mem_info_gtt_total
------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
:doc: mem_info_gtt_total
mem_info_gtt_used
-----------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
:doc: mem_info_gtt_used
PCIe Accounting Information
===========================
pcie_bw
-------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pcie_bw
pcie_replay_count
-----------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: pcie_replay_count
GPU SmartShift Information
==========================
GPU SmartShift information via sysfs
smartshift_apu_power
--------------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: smartshift_apu_power
smartshift_dgpu_power
---------------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: smartshift_dgpu_power
smartshift_bias
---------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: smartshift_bias

View File

@ -0,0 +1,87 @@
===============
AMDGPU Glossary
===============
Here you can find some generic acronyms used in the amdgpu driver. Notice that
we have a dedicated glossary for Display Core at
'Documentation/gpu/amdgpu/display/dc-glossary.rst'.
.. glossary::
CP
Command Processor
CPLIB
Content Protection Library
DFS
Digital Frequency Synthesizer
ECP
Enhanced Content Protection
EOP
End Of Pipe/Pipeline
GC
Graphics and Compute
GMC
Graphic Memory Controller
IH
Interrupt Handler
HQD
Hardware Queue Descriptor
IB
Indirect Buffer
IP
Intellectual Property blocks
KCQ
Kernel Compute Queue
KGQ
Kernel Graphics Queue
KIQ
Kernel Interface Queue
MEC
MicroEngine Compute
MES
MicroEngine Scheduler
MMHUB
Multi-Media HUB
MQD
Memory Queue Descriptor
PPLib
PowerPlay Library - PowerPlay is the power management component.
PSP
Platform Security Processor
RCL
RunList Controller
SDMA
System DMA
SMU
System Management Unit
SS
Spread Spectrum
VCE
Video Compression Engine
VCN
Video Codec Next

View File

@ -0,0 +1,414 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="144.63406mm"
height="66.596054mm"
viewBox="0 0 144.15195 66.596054"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="config_example.svg">
<defs
id="defs2">
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path4547"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend-3"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path4547-6"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend-3-5"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path4547-6-3"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend-3-5-0"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path4547-6-3-6"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Mend-3-5-7"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path4547-6-3-3"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.4,0,0,-0.4,-4,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="518.91791"
inkscape:cy="172.50112"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
viewbox-width="209.3"
inkscape:window-width="3840"
inkscape:window-height="1136"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid817"
originx="4.390216"
originy="-208.88856" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(4.4048992,-21.515392)">
<path
style="fill:none;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 20.816662,35.062492 h 23.8125 v -5.291667 h 5.291667 v 5.291667 h 10.583334 v -5.291667 h 5.291667 v 5.291667 h 2.645833 v -5.291667 h 5.291667 v 5.291667 h 66.14583"
id="path4522"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 20.816662,48.291659 h 7.9375 v -5.291667 h 5.291667 v 5.291667 h 58.208335 v -5.291667 h 5.291666 v 5.291667 h 42.33333"
id="path4524"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 20.816662,61.520826 h 26.458334 v -5.291667 h 44.979168 v 5.291667 h 47.624996"
id="path4526"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 20.816662,72.104159 H 139.87916"
id="path4528"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 20.816662,77.395826 H 139.87916"
id="path4530"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 20.816662,82.687493 H 139.87916"
id="path4532"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 20.816662,87.97916 H 139.87916"
id="path4534"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916668, 0.52916668;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
d="m 47.274996,29.770826 c 3.836215,14.933158 3.472151,27.586643 0.264583,41.010418"
id="path4536"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916669, 0.52916669;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Mend-3)"
d="m 63.149996,29.770826 c 3.836214,14.933158 5.059652,27.586642 1.852084,41.010418"
id="path4536-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.5291667, 0.5291667;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Mend-3-5)"
d="m 71.087496,29.770825 c 3.836214,14.933158 5.059652,27.586643 1.852084,41.010419"
id="path4536-7-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="59.359009"
y="24.195677"
id="text6572"><tspan
sodipodi:role="line"
x="59.359009"
y="24.195677"
style="font-size:3.52777791px;line-height:5.39999962;text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan6574">Configurations</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="46.825508"
y="28.542402"
id="text6572-6"><tspan
sodipodi:role="line"
x="46.825508"
y="28.542402"
style="font-size:3.52777815px;line-height:5.39999962;text-align:center;text-anchor:middle;fill:#008000;stroke-width:0.26458335"
id="tspan6574-2">A</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="62.8895"
y="28.825886"
id="text6572-6-2"><tspan
sodipodi:role="line"
x="62.8895"
y="28.825886"
style="font-size:3.52777839px;line-height:5.39999962;text-align:center;text-anchor:middle;fill:#0000ff;stroke-width:0.26458335"
id="tspan6574-2-7">B</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="70.827003"
y="29.109362"
id="text6572-6-2-3"><tspan
sodipodi:role="line"
x="70.827003"
y="29.109362"
style="font-size:3.52777863px;line-height:5.39999962;text-align:center;text-anchor:middle;fill:#c87137;stroke-width:0.26458335"
id="tspan6574-2-7-6">C</tspan></text>
<path
style="fill:none;stroke:#ff0000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916671, 0.52916671;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Mend-3-5-0)"
d="m 92.254164,42.999993 c 9.142136,12.745655 4.411987,28.608461 0.529167,38.364584"
id="path4536-7-5-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 47.274996,72.104159 v 5.291667"
id="path8053"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 64.472913,72.10416 v 5.291667"
id="path8053-6"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 72.410413,72.10416 v 5.291667"
id="path8053-6-1"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 92.254164,82.687494 v 5.291667"
id="path8053-6-1-8"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="55.802444"
y="76.167412"
id="text6572-6-7"><tspan
sodipodi:role="line"
x="55.802444"
y="76.167412"
style="font-size:3.52777839px;line-height:5.39999962;text-align:center;text-anchor:middle;fill:#008000;stroke-width:0.26458335"
id="tspan6574-2-9">A</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="68.559143"
y="75.883926"
id="text6572-6-2-2"><tspan
sodipodi:role="line"
x="68.559143"
y="75.883926"
style="font-size:3.52777863px;line-height:5.39999962;text-align:center;text-anchor:middle;fill:#0000ff;stroke-width:0.26458335"
id="tspan6574-2-7-0">B</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="84.812119"
y="75.883911"
id="text6572-6-2-3-2"><tspan
sodipodi:role="line"
x="84.812119"
y="75.883911"
style="font-size:3.52777863px;line-height:5.39999962;text-align:center;text-anchor:middle;fill:#c87137;stroke-width:0.26458335"
id="tspan6574-2-7-6-3">C</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="98.513756"
y="86.845222"
id="text6572-6-2-3-2-7"><tspan
sodipodi:role="line"
x="98.513756"
y="86.845222"
style="font-size:3.52777863px;line-height:5.39999962;text-align:center;text-anchor:middle;fill:#c87137;stroke-width:0.26458335"
id="tspan6574-2-7-6-3-5">C</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="35.452015"
y="75.694931"
id="text6572-9"><tspan
sodipodi:role="line"
x="35.452015"
y="75.694931"
style="font-size:3.52777815px;line-height:5.39999962;text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan6574-22">Old config</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="55.484753"
y="86.656235"
id="text6572-9-8"><tspan
sodipodi:role="line"
x="55.484753"
y="86.656235"
style="font-size:3.52777839px;line-height:5.39999962;text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan6574-22-9">Old config</tspan></text>
<path
style="fill:none;stroke:#ff0000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916671, 0.52916671;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#Arrow1Mend-3-5-7)"
d="m 92.254164,42.999993 c 4.233333,4.7625 2.645833,13.229167 0.79375,17.197917"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.58333397px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="3.7020128"
y="33.550579"
id="text6572-1"><tspan
sodipodi:role="line"
x="3.7020128"
y="42.914349"
style="font-size:3.52777815px;line-height:5.39999962;text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan15310" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17500019px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="13.366468"
y="46.590767"
id="text15316"><tspan
sodipodi:role="line"
x="13.366468"
y="46.590767"
style="text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan15318">VUpdate</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17500043px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="14.45245"
y="29.676321"
id="text15316-3"><tspan
sodipodi:role="line"
id="tspan15314-1"
x="14.45245"
y="29.676321"
style="text-align:center;text-anchor:middle;stroke-width:0.26458335">Update</tspan><tspan
sodipodi:role="line"
x="14.45245"
y="33.645073"
style="text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan15318-9">Lock</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17500043px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="7.5676007"
y="56.985115"
id="text15316-4"><tspan
sodipodi:role="line"
x="7.5676007"
y="56.985115"
style="text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan15318-7">Register update</tspan><tspan
sodipodi:role="line"
x="7.5676007"
y="60.953865"
style="text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan15361">Pending Status</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17500043px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="16.074829"
y="76.167404"
id="text15316-8"><tspan
sodipodi:role="line"
x="16.074829"
y="76.167404"
style="text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan15318-4">Buf 0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17500067px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335"
x="16.156994"
y="86.089279"
id="text15316-8-5"><tspan
sodipodi:role="line"
x="16.156994"
y="86.089279"
style="text-align:center;text-anchor:middle;stroke-width:0.26458335"
id="tspan15318-4-0">Buf 1</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,77 @@
========================
Display Core Debug tools
========================
DC Visual Confirmation
======================
Display core provides a feature named visual confirmation, which is a set of
bars added at the scanout time by the driver to convey some specific
information. In general, you can enable this debug option by using::
echo <N> > /sys/kernel/debug/dri/0/amdgpu_dm_visual_confirm
Where `N` is an integer number for some specific scenarios that the developer
wants to enable, you will see some of these debug cases in the following
subsection.
Multiple Planes Debug
---------------------
If you want to enable or debug multiple planes in a specific user-space
application, you can leverage a debug feature named visual confirm. For
enabling it, you will need::
echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_visual_confirm
You need to reload your GUI to see the visual confirmation. When the plane
configuration changes or a full update occurs there will be a colored bar at
the bottom of each hardware plane being drawn on the screen.
* The color indicates the format - For example, red is AR24 and green is NV12
* The height of the bar indicates the index of the plane
* Pipe split can be observed if there are two bars with a difference in height
covering the same plane
Consider the video playback case in which a video is played in a specific
plane, and the desktop is drawn in another plane. The video plane should
feature one or two green bars at the bottom of the video depending on pipe
split configuration.
* There should **not** be any visual corruption
* There should **not** be any underflow or screen flashes
* There should **not** be any black screens
* There should **not** be any cursor corruption
* Multiple plane **may** be briefly disabled during window transitions or
resizing but should come back after the action has finished
Pipe Split Debug
----------------
Sometimes we need to debug if DCN is splitting pipes correctly, and visual
confirmation is also handy for this case. Similar to the MPO case, you can use
the below command to enable visual confirmation::
echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_visual_confirm
In this case, if you have a pipe split, you will see one small red bar at the
bottom of the display covering the entire display width and another bar
covering the second pipe. In other words, you will see a bit high bar in the
second pipe.
DTN Debug
=========
DC (DCN) provides an extensive log that dumps multiple details from our
hardware configuration. Via debugfs, you can capture those status values by
using Display Test Next (DTN) log, which can be captured via debugfs by using::
cat /sys/kernel/debug/dri/0/amdgpu_dm_dtn_log
Since this log is updated accordingly with DCN status, you can also follow the
change in real-time by using something like::
sudo watch -d cat /sys/kernel/debug/dri/0/amdgpu_dm_dtn_log
When reporting a bug related to DC, consider attaching this log before and
after you reproduce the bug.

View File

@ -0,0 +1,237 @@
===========
DC Glossary
===========
On this page, we try to keep track of acronyms related to the display
component. If you do not find what you are looking for, look at the
'Documentation/gpu/amdgpu/amdgpu-glossary.rst'; if you cannot find it anywhere,
consider asking in the amdgfx and update this page.
.. glossary::
ABM
Adaptive Backlight Modulation
APU
Accelerated Processing Unit
ASIC
Application-Specific Integrated Circuit
ASSR
Alternate Scrambler Seed Reset
AZ
Azalia (HD audio DMA engine)
BPC
Bits Per Colour/Component
BPP
Bits Per Pixel
Clocks
* PCLK: Pixel Clock
* SYMCLK: Symbol Clock
* SOCCLK: GPU Engine Clock
* DISPCLK: Display Clock
* DPPCLK: DPP Clock
* DCFCLK: Display Controller Fabric Clock
* REFCLK: Real Time Reference Clock
* PPLL: Pixel PLL
* FCLK: Fabric Clock
* MCLK: Memory Clock
CRC
Cyclic Redundancy Check
CRTC
Cathode Ray Tube Controller - commonly called "Controller" - Generates
raw stream of pixels, clocked at pixel clock
CVT
Coordinated Video Timings
DAL
Display Abstraction layer
DC (Software)
Display Core
DC (Hardware)
Display Controller
DCC
Delta Colour Compression
DCE
Display Controller Engine
DCHUB
Display Controller HUB
ARB
Arbiter
VTG
Vertical Timing Generator
DCN
Display Core Next
DCCG
Display Clock Generator block
DDC
Display Data Channel
DIO
Display IO
DPP
Display Pipes and Planes
DSC
Display Stream Compression (Reduce the amount of bits to represent pixel
count while at the same pixel clock)
dGPU
discrete GPU
DMIF
Display Memory Interface
DML
Display Mode Library
DMCU
Display Micro-Controller Unit
DMCUB
Display Micro-Controller Unit, version B
DPCD
DisplayPort Configuration Data
DPM(S)
Display Power Management (Signaling)
DRR
Dynamic Refresh Rate
DWB
Display Writeback
FB
Frame Buffer
FBC
Frame Buffer Compression
FEC
Forward Error Correction
FRL
Fixed Rate Link
GCO
Graphical Controller Object
GSL
Global Swap Lock
iGPU
integrated GPU
ISR
Interrupt Service Request
ISV
Independent Software Vendor
KMD
Kernel Mode Driver
LB
Line Buffer
LFC
Low Framerate Compensation
LTTPR
Link Training Tunable Phy Repeater
LUT
Lookup Table
MALL
Memory Access at Last Level
MC
Memory Controller
MPC
Multiple pipes and plane combine
MPO
Multi Plane Overlay
MST
Multi Stream Transport
NBP State
Northbridge Power State
NBIO
North Bridge Input/Output
ODM
Output Data Mapping
OPM
Output Protection Manager
OPP
Output Plane Processor
OPTC
Output Pipe Timing Combiner
OTG
Output Timing Generator
PCON
Power Controller
PGFSM
Power Gate Finite State Machine
PSR
Panel Self Refresh
SCL
Scaler
SDP
Scalable Data Port
SLS
Single Large Surface
SST
Single Stream Transport
TMDS
Transition-Minimized Differential Signaling
TMZ
Trusted Memory Zone
TTU
Time to Underflow
VRR
Variable Refresh Rate
UVD
Unified Video Decoder

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -0,0 +1,171 @@
=======================
Display Core Next (DCN)
=======================
To equip our readers with the basic knowledge of how AMD Display Core Next
(DCN) works, we need to start with an overview of the hardware pipeline. Below
you can see a picture that provides a DCN overview, keep in mind that this is a
generic diagram, and we have variations per ASIC.
.. kernel-figure:: dc_pipeline_overview.svg
Based on this diagram, we can pass through each block and briefly describe
them:
* **Display Controller Hub (DCHUB)**: This is the gateway between the Scalable
Data Port (SDP) and DCN. This component has multiple features, such as memory
arbitration, rotation, and cursor manipulation.
* **Display Pipe and Plane (DPP)**: This block provides pre-blend pixel
processing such as color space conversion, linearization of pixel data, tone
mapping, and gamut mapping.
* **Multiple Pipe/Plane Combined (MPC)**: This component performs blending of
multiple planes, using global or per-pixel alpha.
* **Output Pixel Processing (OPP)**: Process and format pixels to be sent to
the display.
* **Output Pipe Timing Combiner (OPTC)**: It generates time output to combine
streams or divide capabilities. CRC values are generated in this block.
* **Display Output (DIO)**: Codify the output to the display connected to our
GPU.
* **Display Writeback (DWB)**: It provides the ability to write the output of
the display pipe back to memory as video frames.
* **Multi-Media HUB (MMHUBBUB)**: Memory controller interface for DMCUB and DWB
(Note that DWB is not hooked yet).
* **DCN Management Unit (DMU)**: It provides registers with access control and
interrupts the controller to the SOC host interrupt unit. This block includes
the Display Micro-Controller Unit - version B (DMCUB), which is handled via
firmware.
* **DCN Clock Generator Block (DCCG)**: It provides the clocks and resets
for all of the display controller clock domains.
* **Azalia (AZ)**: Audio engine.
The above diagram is an architecture generalization of DCN, which means that
every ASIC has variations around this base model. Notice that the display
pipeline is connected to the Scalable Data Port (SDP) via DCHUB; you can see
the SDP as the element from our Data Fabric that feeds the display pipe.
Always approach the DCN architecture as something flexible that can be
configured and reconfigured in multiple ways; in other words, each block can be
setup or ignored accordingly with userspace demands. For example, if we
want to drive an 8k@60Hz with a DSC enabled, our DCN may require 4 DPP and 2
OPP. It is DC's responsibility to drive the best configuration for each
specific scenario. Orchestrate all of these components together requires a
sophisticated communication interface which is highlighted in the diagram by
the edges that connect each block; from the chart, each connection between
these blocks represents:
1. Pixel data interface (red): Represents the pixel data flow;
2. Global sync signals (green): It is a set of synchronization signals composed
by VStartup, VUpdate, and VReady;
3. Config interface: Responsible to configure blocks;
4. Sideband signals: All other signals that do not fit the previous one.
These signals are essential and play an important role in DCN. Nevertheless,
the Global Sync deserves an extra level of detail described in the next
section.
All of these components are represented by a data structure named dc_state.
From DCHUB to MPC, we have a representation called dc_plane; from MPC to OPTC,
we have dc_stream, and the output (DIO) is handled by dc_link. Keep in mind
that HUBP accesses a surface using a specific format read from memory, and our
dc_plane should work to convert all pixels in the plane to something that can
be sent to the display via dc_stream and dc_link.
Front End and Back End
----------------------
Display pipeline can be broken down into two components that are usually
referred as **Front End (FE)** and **Back End (BE)**, where FE consists of:
* DCHUB (Mainly referring to a subcomponent named HUBP)
* DPP
* MPC
On the other hand, BE consist of
* OPP
* OPTC
* DIO (DP/HDMI stream encoder and link encoder)
OPP and OPTC are two joining blocks between FE and BE. On a side note, this is
a one-to-one mapping of the link encoder to PHY, but we can configure the DCN
to choose which link encoder to connect to which PHY. FE's main responsibility
is to change, blend and compose pixel data, while BE's job is to frame a
generic pixel stream to a specific display's pixel stream.
Data Flow
---------
Initially, data is passed in from VRAM through Data Fabric (DF) in native pixel
formats. Such data format stays through till HUBP in DCHUB, where HUBP unpacks
different pixel formats and outputs them to DPP in uniform streams through 4
channels (1 for alpha + 3 for colors).
The Converter and Cursor (CNVC) in DPP would then normalize the data
representation and convert them to a DCN specific floating-point format (i.e.,
different from the IEEE floating-point format). In the process, CNVC also
applies a degamma function to transform the data from non-linear to linear
space to relax the floating-point calculations following. Data would stay in
this floating-point format from DPP to OPP.
Starting OPP, because color transformation and blending have been completed
(i.e alpha can be dropped), and the end sinks do not require the precision and
dynamic range that floating points provide (i.e. all displays are in integer
depth format), bit-depth reduction/dithering would kick in. In OPP, we would
also apply a regamma function to introduce the gamma removed earlier back.
Eventually, we output data in integer format at DIO.
Global Sync
-----------
Many DCN registers are double buffered, most importantly the surface address.
This allows us to update DCN hardware atomically for page flips, as well as
for most other updates that don't require enabling or disabling of new pipes.
(Note: There are many scenarios when DC will decide to reserve extra pipes
in order to support outputs that need a very high pixel clock, or for
power saving purposes.)
These atomic register updates are driven by global sync signals in DCN. In
order to understand how atomic updates interact with DCN hardware, and how DCN
signals page flip and vblank events it is helpful to understand how global sync
is programmed.
Global sync consists of three signals, VSTARTUP, VUPDATE, and VREADY. These are
calculated by the Display Mode Library - DML (drivers/gpu/drm/amd/display/dc/dml)
based on a large number of parameters and ensure our hardware is able to feed
the DCN pipeline without underflows or hangs in any given system configuration.
The global sync signals always happen during VBlank, are independent from the
VSync signal, and do not overlap each other.
VUPDATE is the only signal that is of interest to the rest of the driver stack
or userspace clients as it signals the point at which hardware latches to
atomically programmed (i.e. double buffered) registers. Even though it is
independent of the VSync signal we use VUPDATE to signal the VSync event as it
provides the best indication of how atomic commits and hardware interact.
Since DCN hardware is double-buffered the DC driver is able to program the
hardware at any point during the frame.
The below picture illustrates the global sync signals:
.. kernel-figure:: global_sync_vblank.svg
These signals affect core DCN behavior. Programming them incorrectly will lead
to a number of negative consequences, most of them quite catastrophic.
The following picture shows how global sync allows for a mailbox style of
updates, i.e. it allows for multiple re-configurations between VUpdate
events where only the last configuration programmed before the VUpdate signal
becomes effective.
.. kernel-figure:: config_example.svg

View File

@ -0,0 +1,42 @@
======================
AMDgpu Display Manager
======================
.. contents:: Table of Contents
:depth: 3
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:doc: overview
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
:internal:
Lifecycle
=========
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:doc: DM Lifecycle
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:functions: dm_hw_init dm_hw_fini
Interrupts
==========
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
:doc: overview
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
:internal:
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:functions: register_hpd_handlers dm_crtc_high_irq dm_pflip_high_irq
Atomic Implementation
=====================
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:doc: atomic
.. kernel-doc:: drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
:functions: amdgpu_dm_atomic_check amdgpu_dm_atomic_commit_tail

View File

@ -0,0 +1,485 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="232.24133mm"
height="96.174995mm"
viewBox="0 0 232.24133 96.174995"
version="1.1"
id="svg8"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
sodipodi:docname="global_sync_vblank.svg">
<defs
id="defs2">
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path862"
style="fill:#800080;fill-opacity:1;fill-rule:evenodd;stroke:#800080;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0"
refX="0"
id="Arrow2Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path868"
style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.3,0,0,-0.3,0.69,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Lend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path856"
style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="marker1719"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1717"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="marker1661"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1659"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker1311"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1309"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker1253"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1251"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lend"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path838"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.8,0,0,-0.8,-10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0"
refX="0"
id="Arrow1Lstart"
style="overflow:visible"
inkscape:isstock="true"
inkscape:collect="always">
<path
id="path835"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,10,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path850"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Sstart"
orient="auto"
refY="0"
refX="0"
id="Arrow2Sstart"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path865"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(0.3,0,0,0.3,-0.69,0)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-2"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path862-3"
style="fill:#800080;fill-opacity:1;fill-rule:evenodd;stroke:#800080;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-2-5"
style="overflow:visible"
inkscape:isstock="true">
<path
inkscape:connector-curvature="0"
id="path862-3-9"
style="fill:#800080;fill-opacity:1;fill-rule:evenodd;stroke:#800080;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="747.52324"
inkscape:cy="319.84503"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="3840"
inkscape:window-height="2096"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0">
<inkscape:grid
type="xygrid"
id="grid815"
originx="15.282997"
originy="-184.54792" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(15.282998,-16.277083)">
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.875,27.125001 V 16.541666 H 26.458333 V 27.125001 H 177.27084 V 16.541666 h 10.58333 v 10.583335 h 29.10416"
id="path817"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.875,37.708334 H 44.979166 V 48.291667 H 100.54167 V 37.708334 H 206.375 v 10.583333 h 10.58333"
id="path819"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 15.875,66.8125 h 97.89583 V 56.229167 h 7.9375 V 66.8125 h 92.60417"
id="path821"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 15.875,85.333334 c 0,0 132.29166,0 132.29166,0 V 74.75 h 15.875 v 10.583334 h 47.625"
id="path823"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.875,101.20833 H 187.85416 V 90.625 h 10.58334 v 10.58333 h 10.58333"
id="path825"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916667, 0.52916667;stroke-dashoffset:0;stroke-opacity:1"
d="M 100.54167,48.291667 V 111.79167"
id="path827"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916667, 0.52916667;stroke-dashoffset:0;stroke-opacity:1"
d="m 113.77083,66.8125 v 44.97917"
id="path829"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.52916667, 0.52916667;stroke-dashoffset:0;stroke-opacity:1"
d="M 206.375,48.291667 V 109.14583"
id="path831"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
d="m 100.54167,106.5 h 13.22916"
id="path833"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker1253);marker-end:url(#marker1311)"
d="M 113.77083,106.5 H 206.375"
id="path1243"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="105.83333"
y="111.79166"
id="text1405"><tspan
sodipodi:role="line"
id="tspan1403"
x="105.83333"
y="111.79166"
style="stroke-width:0.26458332">To</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="145.52083"
y="111.79166"
id="text1409"><tspan
sodipodi:role="line"
id="tspan1407"
x="145.52083"
y="111.79166"
style="stroke-width:0.26458332">VStartup Period</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="156.01123"
y="78.71875"
id="text1413"><tspan
sodipodi:role="line"
x="156.01123"
y="78.71875"
style="font-weight:bold;text-align:center;text-anchor:middle;stroke-width:0.26458332"
id="tspan1415">VUpdate</tspan><tspan
sodipodi:role="line"
x="156.01123"
y="82.6875"
style="font-weight:bold;text-align:center;text-anchor:middle;stroke-width:0.26458332"
id="tspan1440">Width</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="173.77611"
y="92.703873"
id="text1413-3"><tspan
sodipodi:role="line"
id="tspan1411-6"
x="173.77611"
y="92.703873"
style="font-weight:bold;text-align:center;text-anchor:middle;stroke-width:0.26458332">VReady</tspan><tspan
sodipodi:role="line"
x="173.77611"
y="96.672623"
style="font-weight:bold;text-align:center;text-anchor:middle;stroke-width:0.26458332"
id="tspan1415-7">Offset</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="135.78951"
y="70.78125"
id="text1413-5"><tspan
sodipodi:role="line"
x="135.78951"
y="70.78125"
style="font-weight:bold;text-align:center;text-anchor:middle;stroke-width:0.26458332"
id="tspan1440-5">VUpdate</tspan><tspan
sodipodi:role="line"
x="135.78951"
y="74.75"
style="font-weight:bold;text-align:center;text-anchor:middle;stroke-width:0.26458332"
id="tspan1465">Offset</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="137.39433"
y="48.291664"
id="text1479"><tspan
sodipodi:role="line"
id="tspan1477"
x="137.39433"
y="48.291664"
style="font-weight:bold;stroke-width:0.26458332">VSTARTUP_START</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="-5.4806676"
y="22.778271"
id="text1479-1"><tspan
sodipodi:role="line"
id="tspan1477-2"
x="-5.4806676"
y="22.778271"
style="font-weight:bold;font-size:4.93888903px;stroke-width:0.26458332">VSYNC</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="-9.3767252"
y="45.64584"
id="text1479-1-7"><tspan
sodipodi:role="line"
id="tspan1477-2-0"
x="-9.3767252"
y="45.64584"
style="font-weight:bold;font-size:5.64444447px;stroke-width:0.26458332">VBlank</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="-15.310558"
y="64.92263"
id="text1479-1-7-9"><tspan
sodipodi:role="line"
id="tspan1477-2-0-3"
x="-15.310558"
y="64.92263"
style="font-weight:bold;font-size:5.64444447px;stroke-width:0.26458332">VStartup</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="-14.17781"
y="85.144356"
id="text1479-1-7-9-6"><tspan
sodipodi:role="line"
id="tspan1477-2-0-3-0"
x="-14.17781"
y="85.144356"
style="font-weight:bold;font-size:5.64444447px;stroke-width:0.26458332">VUpdate</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:3.17499995px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="-11.052421"
y="101.39733"
id="text1479-1-7-9-6-6"><tspan
sodipodi:role="line"
id="tspan1477-2-0-3-0-2"
x="-11.052421"
y="101.39733"
style="font-weight:bold;font-size:5.64444447px;stroke-width:0.26458332">VReady</tspan></text>
<g
id="g5189"
transform="translate(269.875,-14.287499)">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path5143"
d="m -202.40625,45.645828 3.96875,-7.9375"
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path5143-2"
d="m -199.76042,45.645828 3.96874,-7.937499"
style="fill:none;stroke:#000000;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
id="g5189-3"
transform="translate(268.55209,7.9375003)">
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path5143-6"
d="m -202.40625,45.645828 3.96875,-7.9375"
style="fill:none;stroke:#000000;stroke-width:0.5291667;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path5143-2-1"
d="m -199.76042,45.645828 3.96874,-7.937499"
style="fill:none;stroke:#000000;stroke-width:0.52916676;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,31 @@
.. _amdgpu-display-core:
===================================
drm/amd/display - Display Core (DC)
===================================
AMD display engine is partially shared with other operating systems; for this
reason, our Display Core Driver is divided into two pieces:
1. **Display Core (DC)** contains the OS-agnostic components. Things like
hardware programming and resource management are handled here.
2. **Display Manager (DM)** contains the OS-dependent components. Hooks to the
amdgpu base driver and DRM are implemented here.
The display pipe is responsible for "scanning out" a rendered frame from the
GPU memory (also called VRAM, FrameBuffer, etc.) to a display. In other words,
it would:
1. Read frame information from memory;
2. Perform required transformation;
3. Send pixel data to sink devices.
If you want to learn more about our driver details, take a look at the below
table of content:
.. toctree::
display-manager.rst
dc-debug.rst
dcn-overview.rst
dc-glossary.rst

View File

@ -0,0 +1,182 @@
============================
Core Driver Infrastructure
============================
GPU Hardware Structure
======================
Each ASIC is a collection of hardware blocks. We refer to them as
"IPs" (Intellectual Property blocks). Each IP encapsulates certain
functionality. IPs are versioned and can also be mixed and matched.
E.g., you might have two different ASICs that both have System DMA (SDMA) 5.x IPs.
The driver is arranged by IPs. There are driver components to handle
the initialization and operation of each IP. There are also a bunch
of smaller IPs that don't really need much if any driver interaction.
Those end up getting lumped into the common stuff in the soc files.
The soc files (e.g., vi.c, soc15.c nv.c) contain code for aspects of
the SoC itself rather than specific IPs. E.g., things like GPU resets
and register access functions are SoC dependent.
An APU contains more than just CPU and GPU, it also contains all of
the platform stuff (audio, usb, gpio, etc.). Also, a lot of
components are shared between the CPU, platform, and the GPU (e.g.,
SMU, PSP, etc.). Specific components (CPU, GPU, etc.) usually have
their interface to interact with those common components. For things
like S0i3 there is a ton of coordination required across all the
components, but that is probably a bit beyond the scope of this
section.
With respect to the GPU, we have the following major IPs:
GMC (Graphics Memory Controller)
This was a dedicated IP on older pre-vega chips, but has since
become somewhat decentralized on vega and newer chips. They now
have dedicated memory hubs for specific IPs or groups of IPs. We
still treat it as a single component in the driver however since
the programming model is still pretty similar. This is how the
different IPs on the GPU get the memory (VRAM or system memory).
It also provides the support for per process GPU virtual address
spaces.
IH (Interrupt Handler)
This is the interrupt controller on the GPU. All of the IPs feed
their interrupts into this IP and it aggregates them into a set of
ring buffers that the driver can parse to handle interrupts from
different IPs.
PSP (Platform Security Processor)
This handles security policy for the SoC and executes trusted
applications, and validates and loads firmwares for other blocks.
SMU (System Management Unit)
This is the power management microcontroller. It manages the entire
SoC. The driver interacts with it to control power management
features like clocks, voltages, power rails, etc.
DCN (Display Controller Next)
This is the display controller. It handles the display hardware.
It is described in more details in :ref:`Display Core <amdgpu-display-core>`.
SDMA (System DMA)
This is a multi-purpose DMA engine. The kernel driver uses it for
various things including paging and GPU page table updates. It's also
exposed to userspace for use by user mode drivers (OpenGL, Vulkan,
etc.)
GC (Graphics and Compute)
This is the graphics and compute engine, i.e., the block that
encompasses the 3D pipeline and and shader blocks. This is by far the
largest block on the GPU. The 3D pipeline has tons of sub-blocks. In
addition to that, it also contains the CP microcontrollers (ME, PFP,
CE, MEC) and the RLC microcontroller. It's exposed to userspace for
user mode drivers (OpenGL, Vulkan, OpenCL, etc.)
VCN (Video Core Next)
This is the multi-media engine. It handles video and image encode and
decode. It's exposed to userspace for user mode drivers (VA-API,
OpenMAX, etc.)
Graphics and Compute Microcontrollers
-------------------------------------
CP (Command Processor)
The name for the hardware block that encompasses the front end of the
GFX/Compute pipeline. Consists mainly of a bunch of microcontrollers
(PFP, ME, CE, MEC). The firmware that runs on these microcontrollers
provides the driver interface to interact with the GFX/Compute engine.
MEC (MicroEngine Compute)
This is the microcontroller that controls the compute queues on the
GFX/compute engine.
MES (MicroEngine Scheduler)
This is a new engine for managing queues. This is currently unused.
RLC (RunList Controller)
This is another microcontroller in the GFX/Compute engine. It handles
power management related functionality within the GFX/Compute engine.
The name is a vestige of old hardware where it was originally added
and doesn't really have much relation to what the engine does now.
Driver Structure
================
In general, the driver has a list of all of the IPs on a particular
SoC and for things like init/fini/suspend/resume, more or less just
walks the list and handles each IP.
Some useful constructs:
KIQ (Kernel Interface Queue)
This is a control queue used by the kernel driver to manage other gfx
and compute queues on the GFX/compute engine. You can use it to
map/unmap additional queues, etc.
IB (Indirect Buffer)
A command buffer for a particular engine. Rather than writing
commands directly to the queue, you can write the commands into a
piece of memory and then put a pointer to the memory into the queue.
The hardware will then follow the pointer and execute the commands in
the memory, then returning to the rest of the commands in the ring.
.. _amdgpu_memory_domains:
Memory Domains
==============
.. kernel-doc:: include/uapi/drm/amdgpu_drm.h
:doc: memory domains
Buffer Objects
==============
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:doc: amdgpu_object
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
:internal:
PRIME Buffer Sharing
====================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
:doc: PRIME Buffer Sharing
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
:internal:
MMU Notifier
============
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:doc: MMU Notifier
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
:internal:
AMDGPU Virtual Memory
=====================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:doc: GPUVM
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
:internal:
Interrupt Handling
==================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:doc: Interrupt Handling
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
:internal:
IP Blocks
=========
.. kernel-doc:: drivers/gpu/drm/amd/include/amd_shared.h
:doc: IP Blocks
.. kernel-doc:: drivers/gpu/drm/amd/include/amd_shared.h
:identifiers: amd_ip_block_type amd_ip_funcs

View File

@ -0,0 +1,112 @@
================================
Misc AMDGPU driver information
================================
GPU Product Information
=======================
Information about the GPU can be obtained on certain cards
via sysfs
product_name
------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: product_name
product_number
--------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: product_name
serial_number
-------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: serial_number
unique_id
---------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: unique_id
GPU Memory Usage Information
============================
Various memory accounting can be accessed via sysfs
mem_info_vram_total
-------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vram_total
mem_info_vram_used
------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vram_used
mem_info_vis_vram_total
-----------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vis_vram_total
mem_info_vis_vram_used
----------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
:doc: mem_info_vis_vram_used
mem_info_gtt_total
------------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
:doc: mem_info_gtt_total
mem_info_gtt_used
-----------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
:doc: mem_info_gtt_used
PCIe Accounting Information
===========================
pcie_bw
-------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pcie_bw
pcie_replay_count
-----------------
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
:doc: pcie_replay_count
GPU SmartShift Information
==========================
GPU SmartShift information via sysfs
smartshift_apu_power
--------------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: smartshift_apu_power
smartshift_dgpu_power
---------------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: smartshift_dgpu_power
smartshift_bias
---------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: smartshift_bias

View File

@ -0,0 +1,17 @@
==========================
drm/amdgpu AMDgpu driver
==========================
The drm/amdgpu driver supports all AMD Radeon GPUs based on the Graphics Core
Next (GCN) architecture.
.. toctree::
module-parameters
driver-core
display/index
xgmi
ras
thermal
driver-misc
amdgpu-glossary

View File

@ -0,0 +1,7 @@
===================
Module Parameters
===================
The amdgpu driver supports the following module parameters:
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c

View File

@ -0,0 +1,62 @@
====================
AMDGPU RAS Support
====================
The AMDGPU RAS interfaces are exposed via sysfs (for informational queries) and
debugfs (for error injection).
RAS debugfs/sysfs Control and Error Injection Interfaces
========================================================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS debugfs control interface
RAS Reboot Behavior for Unrecoverable Errors
============================================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS Reboot Behavior for Unrecoverable Errors
RAS Error Count sysfs Interface
===============================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS sysfs Error Count Interface
RAS EEPROM debugfs Interface
============================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS debugfs EEPROM table reset interface
RAS VRAM Bad Pages sysfs Interface
==================================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
:doc: AMDGPU RAS sysfs gpu_vram_bad_pages Interface
Sample Code
===========
Sample code for testing error injection can be found here:
https://cgit.freedesktop.org/mesa/drm/tree/tests/amdgpu/ras_tests.c
This is part of the libdrm amdgpu unit tests which cover several areas of the GPU.
There are four sets of tests:
RAS Basic Test
The test verifies the RAS feature enabled status and makes sure the necessary sysfs and debugfs files
are present.
RAS Query Test
This test checks the RAS availability and enablement status for each supported IP block as well as
the error counts.
RAS Inject Test
This test injects errors for each IP.
RAS Disable Test
This test tests disabling of RAS features for each IP block.

View File

@ -0,0 +1,65 @@
===========================================
GPU Power/Thermal Controls and Monitoring
===========================================
HWMON Interfaces
================
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: hwmon
GPU sysfs Power State Interfaces
================================
GPU power controls are exposed via sysfs files.
power_dpm_state
---------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: power_dpm_state
power_dpm_force_performance_level
---------------------------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: power_dpm_force_performance_level
pp_table
--------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_table
pp_od_clk_voltage
-----------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_od_clk_voltage
pp_dpm_*
--------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_dpm_sclk pp_dpm_mclk pp_dpm_socclk pp_dpm_fclk pp_dpm_dcefclk pp_dpm_pcie
pp_power_profile_mode
---------------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: pp_power_profile_mode
\*_busy_percent
---------------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: gpu_busy_percent
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: mem_busy_percent
gpu_metrics
-----------
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
:doc: gpu_metrics

View File

@ -0,0 +1,5 @@
=====================
AMDGPU XGMI Support
=====================
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c

View File

@ -4,8 +4,7 @@ GPU Driver Documentation
.. toctree::
amdgpu
amdgpu-dc
amdgpu/index
i915
mcde
meson

View File

@ -1095,7 +1095,9 @@ struct amdgpu_device {
pci_channel_state_t pci_channel_state;
struct amdgpu_reset_control *reset_cntl;
uint32_t ip_versions[HW_ID_MAX][HWIP_MAX_INSTANCE];
uint32_t ip_versions[MAX_HWIP][HWIP_MAX_INSTANCE];
bool ram_is_direct_mapped;
};
static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev)
@ -1316,6 +1318,8 @@ void amdgpu_device_flush_hdp(struct amdgpu_device *adev,
void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev,
struct amdgpu_ring *ring);
void amdgpu_device_halt(struct amdgpu_device *adev);
/* atpx handler */
#if defined(CONFIG_VGA_SWITCHEROO)
void amdgpu_register_atpx_handler(void);
@ -1359,8 +1363,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon);
u32 amdgpu_get_vblank_counter_kms(struct drm_crtc *crtc);
int amdgpu_enable_vblank_kms(struct drm_crtc *crtc);
void amdgpu_disable_vblank_kms(struct drm_crtc *crtc);
long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
int amdgpu_info_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp);

View File

@ -708,10 +708,12 @@ static int kfd_mem_attach(struct amdgpu_device *adev, struct kgd_mem *mem,
pr_debug("\t add VA 0x%llx - 0x%llx to vm %p\n", va,
va + bo_size, vm);
if (adev == bo_adev || (mem->domain == AMDGPU_GEM_DOMAIN_VRAM &&
amdgpu_xgmi_same_hive(adev, bo_adev))) {
/* Mappings on the local GPU and VRAM mappings in the
* local hive share the original BO
if (adev == bo_adev ||
(amdgpu_ttm_tt_get_usermm(mem->bo->tbo.ttm) && adev->ram_is_direct_mapped) ||
(mem->domain == AMDGPU_GEM_DOMAIN_VRAM && amdgpu_xgmi_same_hive(adev, bo_adev))) {
/* Mappings on the local GPU, or VRAM mappings in the
* local hive, or userptr mapping IOMMU direct map mode
* share the original BO
*/
attachment[i]->type = KFD_MEM_ATT_SHARED;
bo[i] = mem->bo;
@ -1559,12 +1561,7 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
ret = init_user_pages(*mem, user_addr);
if (ret)
goto allocate_init_user_pages_failed;
}
if (offset)
*offset = amdgpu_bo_mmap_offset(bo);
if (flags & (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL |
} else if (flags & (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL |
KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP)) {
ret = amdgpu_amdkfd_gpuvm_pin_bo(bo, AMDGPU_GEM_DOMAIN_GTT);
if (ret) {
@ -1575,11 +1572,14 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT;
}
if (offset)
*offset = amdgpu_bo_mmap_offset(bo);
return 0;
allocate_init_user_pages_failed:
remove_kgd_mem_from_kfd_bo_list(*mem, avm->process_info);
err_pin_bo:
remove_kgd_mem_from_kfd_bo_list(*mem, avm->process_info);
drm_vma_node_revoke(&gobj->vma_node, drm_priv);
err_node_allow:
/* Don't unreserve system mem limit twice */

View File

@ -470,8 +470,8 @@ bool amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device *ade
/**
* amdgpu_atomfirmware_ras_rom_addr -- Get the RAS EEPROM addr from VBIOS
* adev: amdgpu_device pointer
* i2c_address: pointer to u8; if not NULL, will contain
* @adev: amdgpu_device pointer
* @i2c_address: pointer to u8; if not NULL, will contain
* the RAS EEPROM address if the function returns true
*
* Return true if VBIOS supports RAS EEPROM address reporting,

View File

@ -11,6 +11,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include "amdgpu.h"
#include "amd_acpi.h"
#define AMDGPU_PX_QUIRK_FORCE_ATPX (1 << 0)
@ -165,7 +166,7 @@ static void amdgpu_atpx_parse_functions(struct amdgpu_atpx_functions *f, u32 mas
}
/**
* amdgpu_atpx_validate_functions - validate ATPX functions
* amdgpu_atpx_validate - validate ATPX functions
*
* @atpx: amdgpu atpx struct
*

View File

@ -108,7 +108,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_HDMIB:
if (amdgpu_connector->use_digital) {
if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
if (connector->display_info.is_hdmi) {
if (connector->display_info.bpc)
bpc = connector->display_info.bpc;
}
@ -116,7 +116,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
break;
case DRM_MODE_CONNECTOR_DVID:
case DRM_MODE_CONNECTOR_HDMIA:
if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
if (connector->display_info.is_hdmi) {
if (connector->display_info.bpc)
bpc = connector->display_info.bpc;
}
@ -125,7 +125,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
dig_connector = amdgpu_connector->con_priv;
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
connector->display_info.is_hdmi) {
if (connector->display_info.bpc)
bpc = connector->display_info.bpc;
}
@ -149,7 +149,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector)
break;
}
if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
if (connector->display_info.is_hdmi) {
/*
* Pre DCE-8 hw can't handle > 12 bpc, and more than 12 bpc doesn't make
* much sense without support for > 12 bpc framebuffers. RGB 4:4:4 at
@ -315,8 +315,10 @@ static void amdgpu_connector_get_edid(struct drm_connector *connector)
if (!amdgpu_connector->edid) {
/* some laptops provide a hardcoded edid in rom for LCDs */
if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) ||
(connector->connector_type == DRM_MODE_CONNECTOR_eDP)))
(connector->connector_type == DRM_MODE_CONNECTOR_eDP))) {
amdgpu_connector->edid = amdgpu_connector_get_hardcoded_edid(adev);
drm_connector_update_edid_property(connector, amdgpu_connector->edid);
}
}
}
@ -326,6 +328,7 @@ static void amdgpu_connector_free_edid(struct drm_connector *connector)
kfree(amdgpu_connector->edid);
amdgpu_connector->edid = NULL;
drm_connector_update_edid_property(connector, NULL);
}
static int amdgpu_connector_ddc_get_modes(struct drm_connector *connector)
@ -387,6 +390,9 @@ amdgpu_connector_lcd_native_mode(struct drm_encoder *encoder)
native_mode->vdisplay != 0 &&
native_mode->clock != 0) {
mode = drm_mode_duplicate(dev, native_mode);
if (!mode)
return NULL;
mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
drm_mode_set_name(mode);
@ -401,6 +407,9 @@ amdgpu_connector_lcd_native_mode(struct drm_encoder *encoder)
* simpler.
*/
mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
if (!mode)
return NULL;
mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name);
}
@ -1171,7 +1180,7 @@ static enum drm_mode_status amdgpu_connector_dvi_mode_valid(struct drm_connector
(amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D) ||
(amdgpu_connector->connector_object_id == CONNECTOR_OBJECT_ID_HDMI_TYPE_B)) {
return MODE_OK;
} else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
} else if (connector->display_info.is_hdmi) {
/* HDMI 1.3+ supports max clock of 340 Mhz */
if (mode->clock > 340000)
return MODE_CLOCK_HIGH;
@ -1463,7 +1472,7 @@ static enum drm_mode_status amdgpu_connector_dp_mode_valid(struct drm_connector
(amdgpu_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
return amdgpu_atombios_dp_mode_valid_helper(connector, mode);
} else {
if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
if (connector->display_info.is_hdmi) {
/* HDMI 1.3+ supports max clock of 340 Mhz */
if (mode->clock > 340000)
return MODE_CLOCK_HIGH;

View File

@ -1618,6 +1618,9 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
if (!debugfs_initialized())
return 0;
debugfs_create_x32("amdgpu_smu_debug", 0600, root,
&adev->pm.smu_debug_mask);
ent = debugfs_create_file("amdgpu_preempt_ib", 0600, root, adev,
&fops_ib_preempt);
if (IS_ERR(ent)) {

View File

@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/console.h>
#include <linux/slab.h>
#include <linux/iommu.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h>
@ -331,7 +332,7 @@ void amdgpu_device_mm_access(struct amdgpu_device *adev, loff_t pos,
}
/**
* amdgpu_device_vram_access - access vram by vram aperature
* amdgpu_device_aper_access - access vram by vram aperature
*
* @adev: amdgpu_device pointer
* @pos: offset of the buffer in vram
@ -550,11 +551,11 @@ void amdgpu_device_wreg(struct amdgpu_device *adev,
trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
}
/*
/**
* amdgpu_mm_wreg_mmio_rlc - write register either with mmio or with RLC path if in range
*
* this function is invoked only the debugfs register access
* */
*/
void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
uint32_t reg, uint32_t v)
{
@ -2657,6 +2658,36 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev)
return 0;
}
/**
* amdgpu_device_smu_fini_early - smu hw_fini wrapper
*
* @adev: amdgpu_device pointer
*
* For ASICs need to disable SMC first
*/
static void amdgpu_device_smu_fini_early(struct amdgpu_device *adev)
{
int i, r;
if (adev->ip_versions[GC_HWIP][0] > IP_VERSION(9, 0, 0))
return;
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.hw)
continue;
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev);
/* XXX handle errors */
if (r) {
DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
}
adev->ip_blocks[i].status.hw = false;
break;
}
}
}
static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
{
int i, r;
@ -2677,21 +2708,8 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
/* need to disable SMC first */
for (i = 0; i < adev->num_ip_blocks; i++) {
if (!adev->ip_blocks[i].status.hw)
continue;
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev);
/* XXX handle errors */
if (r) {
DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
}
adev->ip_blocks[i].status.hw = false;
break;
}
}
/* Workaroud for ASICs need to disable SMC first */
amdgpu_device_smu_fini_early(adev);
for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
if (!adev->ip_blocks[i].status.hw)
@ -2733,8 +2751,6 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
if (amdgpu_sriov_vf(adev) && adev->virt.ras_init_done)
amdgpu_virt_release_ras_err_handler_data(adev);
amdgpu_ras_pre_fini(adev);
if (adev->gmc.xgmi.num_physical_nodes > 1)
amdgpu_xgmi_remove_device(adev);
@ -3367,6 +3383,22 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
return ret;
}
/**
* amdgpu_device_check_iommu_direct_map - check if RAM direct mapped to GPU
*
* @adev: amdgpu_device pointer
*
* RAM direct mapped to GPU if IOMMU is not enabled or is pass through mode
*/
static void amdgpu_device_check_iommu_direct_map(struct amdgpu_device *adev)
{
struct iommu_domain *domain;
domain = iommu_get_domain_for_dev(adev->dev);
if (!domain || domain->type == IOMMU_DOMAIN_IDENTITY)
adev->ram_is_direct_mapped = true;
}
static const struct attribute *amdgpu_dev_attributes[] = {
&dev_attr_product_name.attr,
&dev_attr_product_number.attr,
@ -3770,6 +3802,8 @@ fence_driver_init:
queue_delayed_work(system_wq, &mgpu_info.delayed_reset_work,
msecs_to_jiffies(AMDGPU_RESUME_MS));
amdgpu_device_check_iommu_direct_map(adev);
return 0;
release_ras_con:
@ -3803,7 +3837,7 @@ static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev)
}
/**
* amdgpu_device_fini - tear down the driver
* amdgpu_device_fini_hw - tear down the driver
*
* @adev: amdgpu_device pointer
*
@ -3844,6 +3878,9 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
amdgpu_ucode_sysfs_fini(adev);
sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes);
/* disable ras feature must before hw fini */
amdgpu_ras_pre_fini(adev);
amdgpu_device_ip_fini_early(adev);
amdgpu_irq_fini_hw(adev);
@ -4284,6 +4321,9 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
bool from_hypervisor)
{
int r;
struct amdgpu_hive_info *hive = NULL;
amdgpu_amdkfd_pre_reset(adev);
amdgpu_amdkfd_pre_reset(adev);
@ -4312,8 +4352,19 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
if (r)
goto error;
hive = amdgpu_get_xgmi_hive(adev);
/* Update PSP FW topology after reset */
if (hive && adev->gmc.xgmi.num_physical_nodes > 1)
r = amdgpu_xgmi_update_topology(hive, adev);
if (hive)
amdgpu_put_xgmi_hive(hive);
if (!r) {
amdgpu_irq_gpu_reset_resume_helper(adev);
r = amdgpu_ib_ring_tests(adev);
amdgpu_amdkfd_post_reset(adev);
}
error:
if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) {
@ -4745,7 +4796,7 @@ static int amdgpu_device_lock_hive_adev(struct amdgpu_device *adev, struct amdgp
{
struct amdgpu_device *tmp_adev = NULL;
if (adev->gmc.xgmi.num_physical_nodes > 1) {
if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1)) {
if (!hive) {
dev_err(adev->dev, "Hive is NULL while device has multiple xgmi nodes");
return -ENODEV;
@ -4957,6 +5008,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
* We always reset all schedulers for device and all devices for XGMI
* hive so that should take care of them too.
*/
if (!amdgpu_sriov_vf(adev))
hive = amdgpu_get_xgmi_hive(adev);
if (hive) {
if (atomic_cmpxchg(&hive->in_reset, 0, 1) != 0) {
@ -4998,7 +5050,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
* to put adev in the 1st position.
*/
INIT_LIST_HEAD(&device_list);
if (adev->gmc.xgmi.num_physical_nodes > 1) {
if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1)) {
list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head)
list_add_tail(&tmp_adev->reset_list, &device_list);
if (!list_is_first(&adev->reset_list, &device_list))
@ -5632,3 +5684,42 @@ void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev,
amdgpu_asic_invalidate_hdp(adev, ring);
}
/**
* amdgpu_device_halt() - bring hardware to some kind of halt state
*
* @adev: amdgpu_device pointer
*
* Bring hardware to some kind of halt state so that no one can touch it
* any more. It will help to maintain error context when error occurred.
* Compare to a simple hang, the system will keep stable at least for SSH
* access. Then it should be trivial to inspect the hardware state and
* see what's going on. Implemented as following:
*
* 1. drm_dev_unplug() makes device inaccessible to user space(IOCTLs, etc),
* clears all CPU mappings to device, disallows remappings through page faults
* 2. amdgpu_irq_disable_all() disables all interrupts
* 3. amdgpu_fence_driver_hw_fini() signals all HW fences
* 4. set adev->no_hw_access to avoid potential crashes after setp 5
* 5. amdgpu_device_unmap_mmio() clears all MMIO mappings
* 6. pci_disable_device() and pci_wait_for_pending_transaction()
* flush any in flight DMA operations
*/
void amdgpu_device_halt(struct amdgpu_device *adev)
{
struct pci_dev *pdev = adev->pdev;
struct drm_device *ddev = adev_to_drm(adev);
drm_dev_unplug(ddev);
amdgpu_irq_disable_all(adev);
amdgpu_fence_driver_hw_fini(adev);
adev->no_hw_access = true;
amdgpu_device_unmap_mmio(adev);
pci_disable_device(pdev);
pci_wait_for_pending_transaction(pdev);
}

View File

@ -67,7 +67,8 @@
#include "smuio_v11_0_6.h"
#include "smuio_v13_0.h"
MODULE_FIRMWARE("amdgpu/ip_discovery.bin");
#define FIRMWARE_IP_DISCOVERY "amdgpu/ip_discovery.bin"
MODULE_FIRMWARE(FIRMWARE_IP_DISCOVERY);
#define mmRCC_CONFIG_MEMSIZE 0xde3
#define mmMM_INDEX 0x0
@ -179,7 +180,7 @@ static int hw_id_map[MAX_HWIP] = {
[DCI_HWIP] = DCI_HWID,
};
static int amdgpu_discovery_read_binary(struct amdgpu_device *adev, uint8_t *binary)
static int amdgpu_discovery_read_binary_from_vram(struct amdgpu_device *adev, uint8_t *binary)
{
uint64_t vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20;
uint64_t pos = vram_size - DISCOVERY_TMR_OFFSET;
@ -189,6 +190,34 @@ static int amdgpu_discovery_read_binary(struct amdgpu_device *adev, uint8_t *bin
return 0;
}
static int amdgpu_discovery_read_binary_from_file(struct amdgpu_device *adev, uint8_t *binary)
{
const struct firmware *fw;
const char *fw_name;
int r;
switch (amdgpu_discovery) {
case 2:
fw_name = FIRMWARE_IP_DISCOVERY;
break;
default:
dev_warn(adev->dev, "amdgpu_discovery is not set properly\n");
return -EINVAL;
}
r = request_firmware(&fw, fw_name, adev->dev);
if (r) {
dev_err(adev->dev, "can't load firmware \"%s\"\n",
fw_name);
return r;
}
memcpy((u8 *)binary, (u8 *)fw->data, adev->mman.discovery_tmr_size);
release_firmware(fw);
return 0;
}
static uint16_t amdgpu_discovery_calculate_checksum(uint8_t *data, uint32_t size)
{
uint16_t checksum = 0;
@ -206,13 +235,20 @@ static inline bool amdgpu_discovery_verify_checksum(uint8_t *data, uint32_t size
return !!(amdgpu_discovery_calculate_checksum(data, size) == expected);
}
static inline bool amdgpu_discovery_verify_binary_signature(uint8_t *binary)
{
struct binary_header *bhdr;
bhdr = (struct binary_header *)binary;
return (le32_to_cpu(bhdr->binary_signature) == BINARY_SIGNATURE);
}
static int amdgpu_discovery_init(struct amdgpu_device *adev)
{
struct table_info *info;
struct binary_header *bhdr;
struct ip_discovery_header *ihdr;
struct gpu_info_header *ghdr;
const struct firmware *fw;
uint16_t offset;
uint16_t size;
uint16_t checksum;
@ -223,31 +259,32 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
if (!adev->mman.discovery_bin)
return -ENOMEM;
if (amdgpu_discovery == 2) {
r = request_firmware(&fw, "amdgpu/ip_discovery.bin", adev->dev);
if (r)
goto get_from_vram;
dev_info(adev->dev, "Using IP discovery from file\n");
memcpy((u8 *)adev->mman.discovery_bin, (u8 *)fw->data,
adev->mman.discovery_tmr_size);
release_firmware(fw);
} else {
get_from_vram:
r = amdgpu_discovery_read_binary(adev, adev->mman.discovery_bin);
r = amdgpu_discovery_read_binary_from_vram(adev, adev->mman.discovery_bin);
if (r) {
DRM_ERROR("failed to read ip discovery binary\n");
dev_err(adev->dev, "failed to read ip discovery binary from vram\n");
r = -EINVAL;
goto out;
}
if(!amdgpu_discovery_verify_binary_signature(adev->mman.discovery_bin)) {
dev_warn(adev->dev, "get invalid ip discovery binary signature from vram\n");
/* retry read ip discovery binary from file */
r = amdgpu_discovery_read_binary_from_file(adev, adev->mman.discovery_bin);
if (r) {
dev_err(adev->dev, "failed to read ip discovery binary from file\n");
r = -EINVAL;
goto out;
}
/* check the ip discovery binary signature */
if(!amdgpu_discovery_verify_binary_signature(adev->mman.discovery_bin)) {
dev_warn(adev->dev, "get invalid ip discovery binary signature from file\n");
r = -EINVAL;
goto out;
}
}
bhdr = (struct binary_header *)adev->mman.discovery_bin;
if (le32_to_cpu(bhdr->binary_signature) != BINARY_SIGNATURE) {
DRM_ERROR("invalid ip discovery binary signature\n");
r = -EINVAL;
goto out;
}
offset = offsetof(struct binary_header, binary_checksum) +
sizeof(bhdr->binary_checksum);
size = le16_to_cpu(bhdr->binary_size) - offset;
@ -255,7 +292,7 @@ get_from_vram:
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
size, checksum)) {
DRM_ERROR("invalid ip discovery binary checksum\n");
dev_err(adev->dev, "invalid ip discovery binary checksum\n");
r = -EINVAL;
goto out;
}
@ -266,14 +303,14 @@ get_from_vram:
ihdr = (struct ip_discovery_header *)(adev->mman.discovery_bin + offset);
if (le32_to_cpu(ihdr->signature) != DISCOVERY_TABLE_SIGNATURE) {
DRM_ERROR("invalid ip discovery data table signature\n");
dev_err(adev->dev, "invalid ip discovery data table signature\n");
r = -EINVAL;
goto out;
}
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
le16_to_cpu(ihdr->size), checksum)) {
DRM_ERROR("invalid ip discovery data table checksum\n");
dev_err(adev->dev, "invalid ip discovery data table checksum\n");
r = -EINVAL;
goto out;
}
@ -285,7 +322,7 @@ get_from_vram:
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
le32_to_cpu(ghdr->size), checksum)) {
DRM_ERROR("invalid gc data table checksum\n");
dev_err(adev->dev, "invalid gc data table checksum\n");
r = -EINVAL;
goto out;
}
@ -379,8 +416,18 @@ int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
ip->major, ip->minor,
ip->revision);
if (le16_to_cpu(ip->hw_id) == VCN_HWID)
if (le16_to_cpu(ip->hw_id) == VCN_HWID) {
/* Bit [5:0]: original revision value
* Bit [7:6]: en/decode capability:
* 0b00 : VCN function normally
* 0b10 : encode is disabled
* 0b01 : decode is disabled
*/
adev->vcn.vcn_config[adev->vcn.num_vcn_inst] =
ip->revision & 0xc0;
ip->revision &= ~0xc0;
adev->vcn.num_vcn_inst++;
}
if (le16_to_cpu(ip->hw_id) == SDMA0_HWID ||
le16_to_cpu(ip->hw_id) == SDMA1_HWID ||
le16_to_cpu(ip->hw_id) == SDMA2_HWID ||
@ -472,14 +519,6 @@ int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, int n
return -EINVAL;
}
int amdgpu_discovery_get_vcn_version(struct amdgpu_device *adev, int vcn_instance,
int *major, int *minor, int *revision)
{
return amdgpu_discovery_get_ip_version(adev, VCN_HWID,
vcn_instance, major, minor, revision);
}
void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
{
struct binary_header *bhdr;
@ -917,7 +956,6 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
break;
case IP_VERSION(3, 0, 0):
case IP_VERSION(3, 0, 16):
case IP_VERSION(3, 0, 64):
case IP_VERSION(3, 1, 1):
case IP_VERSION(3, 0, 2):
case IP_VERSION(3, 0, 192):

View File

@ -33,8 +33,6 @@ void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev);
int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, int number_instance,
int *major, int *minor, int *revision);
int amdgpu_discovery_get_vcn_version(struct amdgpu_device *adev, int vcn_instance,
int *major, int *minor, int *revision);
int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev);
int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev);

View File

@ -1360,7 +1360,7 @@ bool amdgpu_display_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
if ((!(mode->flags & DRM_MODE_FLAG_INTERLACE)) &&
((amdgpu_encoder->underscan_type == UNDERSCAN_ON) ||
((amdgpu_encoder->underscan_type == UNDERSCAN_AUTO) &&
drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
connector->display_info.is_hdmi &&
amdgpu_display_is_hdtv_mode(mode)))) {
if (amdgpu_encoder->underscan_hborder != 0)
amdgpu_crtc->h_border = amdgpu_encoder->underscan_hborder;

View File

@ -313,9 +313,12 @@ module_param_named(dpm, amdgpu_dpm, int, 0444);
/**
* DOC: fw_load_type (int)
* Set different firmware loading type for debugging (0 = direct, 1 = SMU, 2 = PSP). The default is -1 (auto).
* Set different firmware loading type for debugging, if supported.
* Set to 0 to force direct loading if supported by the ASIC. Set
* to -1 to select the default loading mode for the ASIC, as defined
* by the driver. The default is -1 (auto).
*/
MODULE_PARM_DESC(fw_load_type, "firmware loading type (0 = direct, 1 = SMU, 2 = PSP, -1 = auto)");
MODULE_PARM_DESC(fw_load_type, "firmware loading type (0 = force direct if supported, -1 = auto)");
module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444);
/**

View File

@ -45,4 +45,7 @@
long amdgpu_drm_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
long amdgpu_kms_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
#endif

View File

@ -222,7 +222,7 @@ bool amdgpu_dig_monitor_is_duallink(struct drm_encoder *encoder,
case DRM_MODE_CONNECTOR_HDMIB:
if (amdgpu_connector->use_digital) {
/* HDMI 1.3 supports up to 340 Mhz over single link */
if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
if (connector->display_info.is_hdmi) {
if (pixel_clock > 340000)
return true;
else
@ -244,7 +244,7 @@ bool amdgpu_dig_monitor_is_duallink(struct drm_encoder *encoder,
return false;
else {
/* HDMI 1.3 supports up to 340 Mhz over single link */
if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector))) {
if (connector->display_info.is_hdmi) {
if (pixel_clock > 340000)
return true;
else

View File

@ -350,6 +350,7 @@ static inline uint64_t amdgpu_gmc_fault_key(uint64_t addr, uint16_t pasid)
* amdgpu_gmc_filter_faults - filter VM faults
*
* @adev: amdgpu device structure
* @ih: interrupt ring that the fault received from
* @addr: address of the VM fault
* @pasid: PASID of the process causing the fault
* @timestamp: timestamp of the fault
@ -358,7 +359,8 @@ static inline uint64_t amdgpu_gmc_fault_key(uint64_t addr, uint16_t pasid)
* True if the fault was filtered and should not be processed further.
* False if the fault is a new one and needs to be handled.
*/
bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih, uint64_t addr,
uint16_t pasid, uint64_t timestamp)
{
struct amdgpu_gmc *gmc = &adev->gmc;
@ -366,6 +368,10 @@ bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
struct amdgpu_gmc_fault *fault;
uint32_t hash;
/* Stale retry fault if timestamp goes backward */
if (amdgpu_ih_ts_after(timestamp, ih->processed_timestamp))
return true;
/* If we don't have space left in the ring buffer return immediately */
stamp = max(timestamp, AMDGPU_GMC_FAULT_TIMEOUT + 1) -
AMDGPU_GMC_FAULT_TIMEOUT;

View File

@ -316,7 +316,8 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev,
struct amdgpu_gmc *mc);
void amdgpu_gmc_agp_location(struct amdgpu_device *adev,
struct amdgpu_gmc *mc);
bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, uint64_t addr,
bool amdgpu_gmc_filter_faults(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih, uint64_t addr,
uint16_t pasid, uint64_t timestamp);
void amdgpu_gmc_filter_faults_remove(struct amdgpu_device *adev, uint64_t addr,
uint16_t pasid);

View File

@ -164,52 +164,32 @@ 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;
/* check ring is empty to workaround missing wptr overflow flag */
return cur_rptr >= checkpoint_wptr ||
(cur_rptr & ih->ptr_mask) == amdgpu_ih_get_wptr(adev, ih);
}
/**
* amdgpu_ih_wait_on_checkpoint_process - wait to process IVs up to checkpoint
* amdgpu_ih_wait_on_checkpoint_process_ts - 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,
int amdgpu_ih_wait_on_checkpoint_process_ts(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih)
{
uint32_t checkpoint_wptr, rptr;
uint32_t checkpoint_wptr;
uint64_t checkpoint_ts;
long timeout = HZ;
if (!ih->enabled || adev->shutdown)
return -ENODEV;
checkpoint_wptr = amdgpu_ih_get_wptr(adev, ih);
/* Order wptr with rptr. */
/* Order wptr with ring data. */
rmb();
rptr = READ_ONCE(ih->rptr);
checkpoint_ts = amdgpu_ih_decode_iv_ts(adev, ih, checkpoint_wptr, -1);
/* 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));
return wait_event_interruptible_timeout(ih->wait_process,
amdgpu_ih_ts_after(checkpoint_ts, ih->processed_timestamp) ||
ih->rptr == amdgpu_ih_get_wptr(adev, ih), timeout);
}
/**
@ -299,3 +279,18 @@ void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
/* wptr/rptr are in bytes! */
ih->rptr += 32;
}
uint64_t amdgpu_ih_decode_iv_ts_helper(struct amdgpu_ih_ring *ih, u32 rptr,
signed int offset)
{
uint32_t iv_size = 32;
uint32_t ring_index;
uint32_t dw1, dw2;
rptr += iv_size * offset;
ring_index = (rptr & ih->ptr_mask) >> 2;
dw1 = le32_to_cpu(ih->ring[ring_index + 1]);
dw2 = le32_to_cpu(ih->ring[ring_index + 2]);
return dw1 | ((u64)(dw2 & 0xffff) << 32);
}

View File

@ -68,20 +68,30 @@ struct amdgpu_ih_ring {
/* For waiting on IH processing at checkpoint. */
wait_queue_head_t wait_process;
uint64_t processed_timestamp;
};
/* return true if time stamp t2 is after t1 with 48bit wrap around */
#define amdgpu_ih_ts_after(t1, t2) \
(((int64_t)((t2) << 16) - (int64_t)((t1) << 16)) > 0LL)
/* provided by the ih block */
struct amdgpu_ih_funcs {
/* ring read/write ptr handling, called from interrupt context */
u32 (*get_wptr)(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
void (*decode_iv)(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
struct amdgpu_iv_entry *entry);
uint64_t (*decode_iv_ts)(struct amdgpu_ih_ring *ih, u32 rptr,
signed int offset);
void (*set_rptr)(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
};
#define amdgpu_ih_get_wptr(adev, ih) (adev)->irq.ih_funcs->get_wptr((adev), (ih))
#define amdgpu_ih_decode_iv(adev, iv) \
(adev)->irq.ih_funcs->decode_iv((adev), (ih), (iv))
#define amdgpu_ih_decode_iv_ts(adev, ih, rptr, offset) \
(WARN_ON_ONCE(!(adev)->irq.ih_funcs->decode_iv_ts) ? 0 : \
(adev)->irq.ih_funcs->decode_iv_ts((ih), (rptr), (offset)))
#define amdgpu_ih_set_rptr(adev, ih) (adev)->irq.ih_funcs->set_rptr((adev), (ih))
int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
@ -89,10 +99,12 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih,
void amdgpu_ih_ring_fini(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
void amdgpu_ih_ring_write(struct amdgpu_ih_ring *ih, const uint32_t *iv,
unsigned int num_dw);
int amdgpu_ih_wait_on_checkpoint_process(struct amdgpu_device *adev,
int amdgpu_ih_wait_on_checkpoint_process_ts(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih);
int amdgpu_ih_process(struct amdgpu_device *adev, struct amdgpu_ih_ring *ih);
void amdgpu_ih_decode_iv_helper(struct amdgpu_device *adev,
struct amdgpu_ih_ring *ih,
struct amdgpu_iv_entry *entry);
uint64_t amdgpu_ih_decode_iv_ts_helper(struct amdgpu_ih_ring *ih, u32 rptr,
signed int offset);
#endif

View File

@ -1,4 +1,4 @@
/**
/*
* \file amdgpu_ioc32.c
*
* 32-bit ioctl compatibility routines for the AMDGPU DRM.
@ -37,12 +37,9 @@
long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned int nr = DRM_IOCTL_NR(cmd);
int ret;
if (nr < DRM_COMMAND_BASE)
return drm_compat_ioctl(filp, cmd, arg);
ret = amdgpu_drm_ioctl(filp, cmd, arg);
return ret;
return amdgpu_drm_ioctl(filp, cmd, arg);
}

View File

@ -390,7 +390,7 @@ void amdgpu_irq_fini_hw(struct amdgpu_device *adev)
}
/**
* amdgpu_irq_fini - shut down interrupt handling
* amdgpu_irq_fini_sw - shut down interrupt handling
*
* @adev: amdgpu device pointer
*
@ -528,6 +528,9 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
/* Send it to amdkfd as well if it isn't already handled */
if (!handled)
amdgpu_amdkfd_interrupt(adev, entry.iv_entry);
if (amdgpu_ih_ts_after(ih->processed_timestamp, entry.timestamp))
ih->processed_timestamp = entry.timestamp;
}
/**

View File

@ -69,6 +69,7 @@ static void amdgpu_pll_reduce_ratio(unsigned *nom, unsigned *den,
/**
* amdgpu_pll_get_fb_ref_div - feedback and ref divider calculation
*
* @adev: amdgpu_device pointer
* @nom: nominator
* @den: denominator
* @post_div: post divider
@ -106,6 +107,7 @@ static void amdgpu_pll_get_fb_ref_div(struct amdgpu_device *adev, unsigned int n
/**
* amdgpu_pll_compute - compute PLL paramaters
*
* @adev: amdgpu_device pointer
* @pll: information about the PLL
* @freq: requested frequency
* @dot_clock_p: resulting pixel clock

View File

@ -233,6 +233,10 @@ static void amdgpu_perf_start(struct perf_event *event, int flags)
if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
return;
if ((!pe->adev->df.funcs) ||
(!pe->adev->df.funcs->pmc_start))
return;
WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
hwc->state = 0;
@ -268,6 +272,10 @@ static void amdgpu_perf_read(struct perf_event *event)
pmu);
u64 count, prev;
if ((!pe->adev->df.funcs) ||
(!pe->adev->df.funcs->pmc_get_count))
return;
do {
prev = local64_read(&hwc->prev_count);
@ -297,6 +305,10 @@ static void amdgpu_perf_stop(struct perf_event *event, int flags)
if (hwc->state & PERF_HES_UPTODATE)
return;
if ((!pe->adev->df.funcs) ||
(!pe->adev->df.funcs->pmc_stop))
return;
switch (hwc->config_base) {
case AMDGPU_PMU_EVENT_CONFIG_TYPE_DF:
case AMDGPU_PMU_EVENT_CONFIG_TYPE_XGMI:
@ -326,6 +338,10 @@ static int amdgpu_perf_add(struct perf_event *event, int flags)
struct amdgpu_pmu_entry,
pmu);
if ((!pe->adev->df.funcs) ||
(!pe->adev->df.funcs->pmc_start))
return -EINVAL;
switch (pe->pmu_perf_type) {
case AMDGPU_PMU_PERF_TYPE_DF:
hwc->config_base = AMDGPU_PMU_EVENT_CONFIG_TYPE_DF;
@ -371,6 +387,9 @@ static void amdgpu_perf_del(struct perf_event *event, int flags)
struct amdgpu_pmu_entry *pe = container_of(event->pmu,
struct amdgpu_pmu_entry,
pmu);
if ((!pe->adev->df.funcs) ||
(!pe->adev->df.funcs->pmc_stop))
return;
amdgpu_perf_stop(event, PERF_EF_UPDATE);

View File

@ -59,7 +59,7 @@ static DEVICE_ATTR_RO(mem_info_preempt_used);
* @man: TTM memory type manager
* @tbo: TTM BO we need this range for
* @place: placement flags and restrictions
* @mem: the resulting mem object
* @res: TTM memory object
*
* Dummy, just count the space used without allocating resources or any limit.
*/
@ -85,7 +85,7 @@ static int amdgpu_preempt_mgr_new(struct ttm_resource_manager *man,
* amdgpu_preempt_mgr_del - free ranges
*
* @man: TTM memory type manager
* @mem: TTM memory object
* @res: TTM memory object
*
* Free the allocated GTT again.
*/

View File

@ -518,7 +518,7 @@ static struct psp_gfx_cmd_resp *acquire_psp_cmd_buf(struct psp_context *psp)
return cmd;
}
void release_psp_cmd_buf(struct psp_context *psp)
static void release_psp_cmd_buf(struct psp_context *psp)
{
mutex_unlock(&psp->mutex);
}
@ -2017,12 +2017,16 @@ static int psp_hw_start(struct psp_context *psp)
return ret;
}
if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev))
goto skip_pin_bo;
ret = psp_tmr_init(psp);
if (ret) {
DRM_ERROR("PSP tmr init failed!\n");
return ret;
}
skip_pin_bo:
/*
* For ASICs with DF Cstate management centralized
* to PMFW, TMR setup should be performed after PMFW
@ -2452,6 +2456,18 @@ skip_memalloc:
return ret;
}
if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) {
if (adev->gmc.xgmi.num_physical_nodes > 1) {
ret = psp_xgmi_initialize(psp, false, true);
/* Warning the XGMI seesion initialize failure
* Instead of stop driver initialization
*/
if (ret)
dev_err(psp->adev->dev,
"XGMI: Failed to initialize XGMI session\n");
}
}
if (psp->ta_fw) {
ret = psp_ras_initialize(psp);
if (ret)

View File

@ -867,7 +867,7 @@ static int amdgpu_ras_enable_all_features(struct amdgpu_device *adev,
/* feature ctl end */
void amdgpu_ras_mca_query_error_status(struct amdgpu_device *adev,
static void amdgpu_ras_mca_query_error_status(struct amdgpu_device *adev,
struct ras_common_if *ras_block,
struct ras_err_data *err_data)
{
@ -1161,9 +1161,9 @@ int amdgpu_ras_error_inject(struct amdgpu_device *adev,
/**
* amdgpu_ras_query_error_count -- Get error counts of all IPs
* adev: pointer to AMD GPU device
* ce_count: pointer to an integer to be set to the count of correctible errors.
* ue_count: pointer to an integer to be set to the count of uncorrectible
* @adev: pointer to AMD GPU device
* @ce_count: pointer to an integer to be set to the count of correctible errors.
* @ue_count: pointer to an integer to be set to the count of uncorrectible
* errors.
*
* If set, @ce_count or @ue_count, count and return the corresponding
@ -1747,6 +1747,16 @@ static void amdgpu_ras_log_on_err_counter(struct amdgpu_device *adev)
if (info.head.block == AMDGPU_RAS_BLOCK__PCIE_BIF)
continue;
/*
* this is a workaround for aldebaran, skip send msg to
* smu to get ecc_info table due to smu handle get ecc
* info table failed temporarily.
* should be removed until smu fix handle ecc_info table.
*/
if ((info.head.block == AMDGPU_RAS_BLOCK__UMC) &&
(adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 2)))
continue;
amdgpu_ras_query_error_status(adev, &info);
}
}
@ -2362,7 +2372,11 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
}
/* Init poison supported flag, the default value is false */
if (adev->df.funcs &&
if (adev->gmc.xgmi.connected_to_cpu) {
/* enabled by default when GPU is connected to CPU */
con->poison_supported = true;
}
else if (adev->df.funcs &&
adev->df.funcs->query_ras_poison_mode &&
adev->umc.ras_funcs &&
adev->umc.ras_funcs->query_ras_poison_mode) {
@ -2503,7 +2517,6 @@ void amdgpu_ras_late_fini(struct amdgpu_device *adev,
amdgpu_ras_sysfs_remove(adev, ras_block);
if (ih_info->cb)
amdgpu_ras_interrupt_remove_handler(adev, ih_info);
amdgpu_ras_feature_enable(adev, ras_block, 0);
}
/* do some init work after IP late init as dependence.

View File

@ -434,7 +434,6 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
*
* @ring: ring we should submit the msg to
* @handle: VCE session handle to use
* @bo: amdgpu object for which we query the offset
* @fence: optional fence to return
*
* Open up a stream for HW test

View File

@ -286,20 +286,13 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev)
bool amdgpu_vcn_is_disabled_vcn(struct amdgpu_device *adev, enum vcn_ring_type type, uint32_t vcn_instance)
{
bool ret = false;
int vcn_config = adev->vcn.vcn_config[vcn_instance];
int major;
int minor;
int revision;
/* if cannot find IP data, then this VCN does not exist */
if (amdgpu_discovery_get_vcn_version(adev, vcn_instance, &major, &minor, &revision) != 0)
return true;
if ((type == VCN_ENCODE_RING) && (revision & VCN_BLOCK_ENCODE_DISABLE_MASK)) {
if ((type == VCN_ENCODE_RING) && (vcn_config & VCN_BLOCK_ENCODE_DISABLE_MASK)) {
ret = true;
} else if ((type == VCN_DECODE_RING) && (revision & VCN_BLOCK_DECODE_DISABLE_MASK)) {
} else if ((type == VCN_DECODE_RING) && (vcn_config & VCN_BLOCK_DECODE_DISABLE_MASK)) {
ret = true;
} else if ((type == VCN_UNIFIED_RING) && (revision & VCN_BLOCK_QUEUE_DISABLE_MASK)) {
} else if ((type == VCN_UNIFIED_RING) && (vcn_config & VCN_BLOCK_QUEUE_DISABLE_MASK)) {
ret = true;
}

View File

@ -235,6 +235,7 @@ struct amdgpu_vcn {
uint8_t num_vcn_inst;
struct amdgpu_vcn_inst inst[AMDGPU_MAX_VCN_INSTANCES];
uint8_t vcn_config[AMDGPU_MAX_VCN_INSTANCES];
struct amdgpu_vcn_reg internal;
struct mutex vcn_pg_lock;
struct mutex vcn1_jpeg1_workaround;

View File

@ -16,6 +16,8 @@
#include "ivsrcid/ivsrcid_vislands30.h"
#include "amdgpu_vkms.h"
#include "amdgpu_display.h"
#include "atom.h"
#include "amdgpu_irq.h"
/**
* DOC: amdgpu_vkms
@ -41,16 +43,16 @@ static const u32 amdgpu_vkms_formats[] = {
static enum hrtimer_restart amdgpu_vkms_vblank_simulate(struct hrtimer *timer)
{
struct amdgpu_vkms_output *output = container_of(timer,
struct amdgpu_vkms_output,
vblank_hrtimer);
struct drm_crtc *crtc = &output->crtc;
struct amdgpu_crtc *amdgpu_crtc = container_of(timer, struct amdgpu_crtc, vblank_timer);
struct drm_crtc *crtc = &amdgpu_crtc->base;
struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);
u64 ret_overrun;
bool ret;
ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
ret_overrun = hrtimer_forward_now(&amdgpu_crtc->vblank_timer,
output->period_ns);
WARN_ON(ret_overrun != 1);
if (ret_overrun != 1)
DRM_WARN("%s: vblank timer overrun\n", __func__);
ret = drm_crtc_handle_vblank(crtc);
if (!ret)
@ -65,22 +67,21 @@ static int amdgpu_vkms_enable_vblank(struct drm_crtc *crtc)
unsigned int pipe = drm_crtc_index(crtc);
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
struct amdgpu_vkms_output *out = drm_crtc_to_amdgpu_vkms_output(crtc);
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
drm_calc_timestamping_constants(crtc, &crtc->mode);
hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
out->vblank_hrtimer.function = &amdgpu_vkms_vblank_simulate;
out->period_ns = ktime_set(0, vblank->framedur_ns);
hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL);
hrtimer_start(&amdgpu_crtc->vblank_timer, out->period_ns, HRTIMER_MODE_REL);
return 0;
}
static void amdgpu_vkms_disable_vblank(struct drm_crtc *crtc)
{
struct amdgpu_vkms_output *out = drm_crtc_to_amdgpu_vkms_output(crtc);
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
hrtimer_cancel(&out->vblank_hrtimer);
hrtimer_cancel(&amdgpu_crtc->vblank_timer);
}
static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
@ -92,13 +93,14 @@ static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
unsigned int pipe = crtc->index;
struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
if (!READ_ONCE(vblank->enabled)) {
*vblank_time = ktime_get();
return true;
}
*vblank_time = READ_ONCE(output->vblank_hrtimer.node.expires);
*vblank_time = READ_ONCE(amdgpu_crtc->vblank_timer.node.expires);
if (WARN_ON(*vblank_time == vblank->time))
return true;
@ -165,6 +167,8 @@ static const struct drm_crtc_helper_funcs amdgpu_vkms_crtc_helper_funcs = {
static int amdgpu_vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *primary, struct drm_plane *cursor)
{
struct amdgpu_device *adev = drm_to_adev(dev);
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
int ret;
ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor,
@ -176,6 +180,17 @@ static int amdgpu_vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
drm_crtc_helper_add(crtc, &amdgpu_vkms_crtc_helper_funcs);
amdgpu_crtc->crtc_id = drm_crtc_index(crtc);
adev->mode_info.crtcs[drm_crtc_index(crtc)] = amdgpu_crtc;
amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
amdgpu_crtc->encoder = NULL;
amdgpu_crtc->connector = NULL;
amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
hrtimer_init(&amdgpu_crtc->vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
amdgpu_crtc->vblank_timer.function = &amdgpu_vkms_vblank_simulate;
return ret;
}
@ -375,6 +390,7 @@ static struct drm_plane *amdgpu_vkms_plane_init(struct drm_device *dev,
int index)
{
struct drm_plane *plane;
uint64_t modifiers[] = {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID};
int ret;
plane = kzalloc(sizeof(*plane), GFP_KERNEL);
@ -385,7 +401,7 @@ static struct drm_plane *amdgpu_vkms_plane_init(struct drm_device *dev,
&amdgpu_vkms_plane_funcs,
amdgpu_vkms_formats,
ARRAY_SIZE(amdgpu_vkms_formats),
NULL, type, NULL);
modifiers, type, NULL);
if (ret) {
kfree(plane);
return ERR_PTR(ret);
@ -396,12 +412,12 @@ static struct drm_plane *amdgpu_vkms_plane_init(struct drm_device *dev,
return plane;
}
int amdgpu_vkms_output_init(struct drm_device *dev,
struct amdgpu_vkms_output *output, int index)
static int amdgpu_vkms_output_init(struct drm_device *dev, struct
amdgpu_vkms_output *output, int index)
{
struct drm_connector *connector = &output->connector;
struct drm_encoder *encoder = &output->encoder;
struct drm_crtc *crtc = &output->crtc;
struct drm_crtc *crtc = &output->crtc.base;
struct drm_plane *primary, *cursor = NULL;
int ret;
@ -465,6 +481,11 @@ static int amdgpu_vkms_sw_init(void *handle)
int r, i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
adev->amdgpu_vkms_output = kcalloc(adev->mode_info.num_crtc,
sizeof(struct amdgpu_vkms_output), GFP_KERNEL);
if (!adev->amdgpu_vkms_output)
return -ENOMEM;
adev_to_drm(adev)->max_vblank_count = 0;
adev_to_drm(adev)->mode_config.funcs = &amdgpu_vkms_mode_funcs;
@ -481,10 +502,6 @@ static int amdgpu_vkms_sw_init(void *handle)
if (r)
return r;
adev->amdgpu_vkms_output = kcalloc(adev->mode_info.num_crtc, sizeof(struct amdgpu_vkms_output), GFP_KERNEL);
if (!adev->amdgpu_vkms_output)
return -ENOMEM;
/* allocate crtcs, encoders, connectors */
for (i = 0; i < adev->mode_info.num_crtc; i++) {
r = amdgpu_vkms_output_init(adev_to_drm(adev), &adev->amdgpu_vkms_output[i], i);
@ -504,15 +521,16 @@ static int amdgpu_vkms_sw_fini(void *handle)
int i = 0;
for (i = 0; i < adev->mode_info.num_crtc; i++)
if (adev->amdgpu_vkms_output[i].vblank_hrtimer.function)
hrtimer_cancel(&adev->amdgpu_vkms_output[i].vblank_hrtimer);
if (adev->mode_info.crtcs[i])
hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer);
drm_kms_helper_poll_fini(adev_to_drm(adev));
drm_mode_config_cleanup(adev_to_drm(adev));
adev->mode_info.mode_config_initialized = false;
kfree(adev->mode_info.bios_hardcoded_edid);
kfree(adev->amdgpu_vkms_output);
drm_kms_helper_poll_fini(adev_to_drm(adev));
adev->mode_info.mode_config_initialized = false;
return 0;
}

View File

@ -10,15 +10,14 @@
#define YRES_MAX 16384
#define drm_crtc_to_amdgpu_vkms_output(target) \
container_of(target, struct amdgpu_vkms_output, crtc)
container_of(target, struct amdgpu_vkms_output, crtc.base)
extern const struct amdgpu_ip_block_version amdgpu_vkms_ip_block;
struct amdgpu_vkms_output {
struct drm_crtc crtc;
struct amdgpu_crtc crtc;
struct drm_encoder encoder;
struct drm_connector connector;
struct hrtimer vblank_hrtimer;
ktime_t period_ns;
struct drm_pending_vblank_event *event;
};

View File

@ -53,7 +53,7 @@
* can be mapped as snooped (cached system pages) or unsnooped
* (uncached system pages).
* Each VM has an ID associated with it and there is a page table
* associated with each VMID. When execting a command buffer,
* associated with each VMID. When executing a command buffer,
* the kernel tells the the ring what VMID to use for that command
* buffer. VMIDs are allocated dynamically as commands are submitted.
* The userspace drivers maintain their own address space and the kernel

View File

@ -265,6 +265,11 @@ static ssize_t amdgpu_xgmi_show_error(struct device *dev,
ficaa_pie_ctl_in = AMDGPU_XGMI_SET_FICAA(0x200);
ficaa_pie_status_in = AMDGPU_XGMI_SET_FICAA(0x208);
if ((!adev->df.funcs) ||
(!adev->df.funcs->get_fica) ||
(!adev->df.funcs->set_fica))
return -EINVAL;
fica_out = adev->df.funcs->get_fica(adev, ficaa_pie_ctl_in);
if (fica_out != 0x1f)
pr_err("xGMI error counters not enabled!\n");

View File

@ -469,7 +469,7 @@ int amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder *encoder)
if (amdgpu_connector->use_digital &&
(amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE))
return ATOM_ENCODER_MODE_HDMI;
else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
else if (connector->display_info.is_hdmi &&
(amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
return ATOM_ENCODER_MODE_HDMI;
else if (amdgpu_connector->use_digital)
@ -488,7 +488,7 @@ int amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder *encoder)
if (amdgpu_audio != 0) {
if (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE)
return ATOM_ENCODER_MODE_HDMI;
else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
else if (connector->display_info.is_hdmi &&
(amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
return ATOM_ENCODER_MODE_HDMI;
else
@ -506,7 +506,7 @@ int amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder *encoder)
} else if (amdgpu_audio != 0) {
if (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE)
return ATOM_ENCODER_MODE_HDMI;
else if (drm_detect_hdmi_monitor(amdgpu_connector_edid(connector)) &&
else if (connector->display_info.is_hdmi &&
(amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
return ATOM_ENCODER_MODE_HDMI;
else

View File

@ -3070,7 +3070,7 @@ static void gfx_v9_0_init_pg(struct amdgpu_device *adev)
AMD_PG_SUPPORT_CP |
AMD_PG_SUPPORT_GDS |
AMD_PG_SUPPORT_RLC_SMU_HS)) {
WREG32(mmRLC_JUMP_TABLE_RESTORE,
WREG32_SOC15(GC, 0, mmRLC_JUMP_TABLE_RESTORE,
adev->gfx.rlc.cp_table_gpu_addr >> 8);
gfx_v9_0_init_gfx_power_gating(adev);
}

View File

@ -162,7 +162,6 @@ static void gfxhub_v1_0_init_tlb_regs(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC);/* XXX for emulation. */
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);

View File

@ -196,7 +196,6 @@ static void gfxhub_v2_0_init_tlb_regs(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC); /* UC, uncached */

View File

@ -197,7 +197,6 @@ static void gfxhub_v2_1_init_tlb_regs(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, GCMC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC); /* UC, uncached */

View File

@ -107,7 +107,7 @@ static int gmc_v10_0_process_interrupt(struct amdgpu_device *adev,
/* Process it onyl if it's the first fault for this address */
if (entry->ih != &adev->irq.ih_soft &&
amdgpu_gmc_filter_faults(adev, addr, entry->pasid,
amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid,
entry->timestamp))
return 1;
@ -992,10 +992,14 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev)
return -EINVAL;
}
if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev))
goto skip_pin_bo;
r = amdgpu_gart_table_vram_pin(adev);
if (r)
return r;
skip_pin_bo:
r = adev->gfxhub.funcs->gart_enable(adev);
if (r)
return r;

View File

@ -523,7 +523,7 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev,
/* Process it onyl if it's the first fault for this address */
if (entry->ih != &adev->irq.ih_soft &&
amdgpu_gmc_filter_faults(adev, addr, entry->pasid,
amdgpu_gmc_filter_faults(adev, entry->ih, addr, entry->pasid,
entry->timestamp))
return 1;
@ -1294,7 +1294,8 @@ static int gmc_v9_0_late_init(void *handle)
if (!amdgpu_sriov_vf(adev) &&
(adev->ip_versions[UMC_HWIP][0] == IP_VERSION(6, 0, 0))) {
if (!(adev->ras_enabled & (1 << AMDGPU_RAS_BLOCK__UMC))) {
if (adev->df.funcs->enable_ecc_force_par_wr_rmw)
if (adev->df.funcs &&
adev->df.funcs->enable_ecc_force_par_wr_rmw)
adev->df.funcs->enable_ecc_force_par_wr_rmw(adev, false);
}
}
@ -1505,10 +1506,12 @@ static int gmc_v9_0_sw_init(void *handle)
chansize = 64;
else
chansize = 128;
if (adev->df.funcs &&
adev->df.funcs->get_hbm_channel_number) {
numchan = adev->df.funcs->get_hbm_channel_number(adev);
adev->gmc.vram_width = numchan * chansize;
}
}
adev->gmc.vram_type = vram_type;
adev->gmc.vram_vendor = vram_vendor;
@ -1714,10 +1717,14 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev)
return -EINVAL;
}
if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev))
goto skip_pin_bo;
r = amdgpu_gart_table_vram_pin(adev);
if (r)
return r;
skip_pin_bo:
r = adev->gfxhub.funcs->gart_enable(adev);
if (r)
return r;
@ -1742,7 +1749,7 @@ static int gmc_v9_0_hw_init(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
bool value;
int r, i;
int i;
/* The sequence of these two function calls matters.*/
gmc_v9_0_init_golden_registers(adev);
@ -1777,9 +1784,7 @@ static int gmc_v9_0_hw_init(void *handle)
if (adev->umc.funcs && adev->umc.funcs->init_registers)
adev->umc.funcs->init_registers(adev);
r = gmc_v9_0_gart_enable(adev);
return r;
return gmc_v9_0_gart_enable(adev);
}
/**
@ -1808,6 +1813,14 @@ static int gmc_v9_0_hw_fini(void *handle)
return 0;
}
/*
* Pair the operations did in gmc_v9_0_hw_init and thus maintain
* a correct cached state for GMC. Otherwise, the "gate" again
* operation on S3 resuming will fail due to wrong cached state.
*/
if (adev->mmhub.funcs->update_power_gating)
adev->mmhub.funcs->update_power_gating(adev, false);
amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0);
amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0);

View File

@ -145,7 +145,6 @@ static void mmhub_v1_0_init_tlb_regs(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC);/* XXX for emulation. */
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);
@ -302,10 +301,10 @@ static void mmhub_v1_0_update_power_gating(struct amdgpu_device *adev,
if (amdgpu_sriov_vf(adev))
return;
if (enable && adev->pg_flags & AMD_PG_SUPPORT_MMHUB) {
amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GMC, true);
}
if (adev->pg_flags & AMD_PG_SUPPORT_MMHUB)
amdgpu_dpm_set_powergating_by_smu(adev,
AMD_IP_BLOCK_TYPE_GMC,
enable);
}
static int mmhub_v1_0_gart_enable(struct amdgpu_device *adev)

View File

@ -165,7 +165,6 @@ static void mmhub_v1_7_init_tlb_regs(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC);/* XXX for emulation. */
tmp = REG_SET_FIELD(tmp, MC_VM_MX_L1_TLB_CNTL, ATC_EN, 1);

View File

@ -267,7 +267,6 @@ static void mmhub_v2_0_init_tlb_regs(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC); /* UC, uncached */

View File

@ -194,7 +194,6 @@ static void mmhub_v2_3_init_tlb_regs(struct amdgpu_device *adev)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL, ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, MMMC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC); /* UC, uncached */

View File

@ -189,8 +189,6 @@ static void mmhub_v9_4_init_tlb_regs(struct amdgpu_device *adev, int hubid)
ENABLE_ADVANCED_DRIVER_MODEL, 1);
tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
SYSTEM_APERTURE_UNMAPPED_ACCESS, 0);
tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
ECO_BITS, 0);
tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,
MTYPE, MTYPE_UC);/* XXX for emulation. */
tmp = REG_SET_FIELD(tmp, VMSHAREDVC0_MC_VM_MX_L1_TLB_CNTL,

View File

@ -252,11 +252,12 @@ static void xgpu_ai_mailbox_flr_work(struct work_struct *work)
* otherwise the mailbox msg will be ruined/reseted by
* the VF FLR.
*/
if (!down_write_trylock(&adev->reset_sem))
if (atomic_cmpxchg(&adev->in_gpu_reset, 0, 1) != 0)
return;
down_write(&adev->reset_sem);
amdgpu_virt_fini_data_exchange(adev);
atomic_set(&adev->in_gpu_reset, 1);
xgpu_ai_mailbox_trans_msg(adev, IDH_READY_TO_RESET, 0, 0, 0);

View File

@ -26,7 +26,7 @@
#define AI_MAILBOX_POLL_ACK_TIMEDOUT 500
#define AI_MAILBOX_POLL_MSG_TIMEDOUT 6000
#define AI_MAILBOX_POLL_FLR_TIMEDOUT 5000
#define AI_MAILBOX_POLL_FLR_TIMEDOUT 10000
#define AI_MAILBOX_POLL_MSG_REP_MAX 11
enum idh_request {

View File

@ -281,11 +281,12 @@ static void xgpu_nv_mailbox_flr_work(struct work_struct *work)
* otherwise the mailbox msg will be ruined/reseted by
* the VF FLR.
*/
if (!down_write_trylock(&adev->reset_sem))
if (atomic_cmpxchg(&adev->in_gpu_reset, 0, 1) != 0)
return;
down_write(&adev->reset_sem);
amdgpu_virt_fini_data_exchange(adev);
atomic_set(&adev->in_gpu_reset, 1);
xgpu_nv_mailbox_trans_msg(adev, IDH_READY_TO_RESET, 0, 0, 0);

View File

@ -716,6 +716,7 @@ static const struct amd_ip_funcs navi10_ih_ip_funcs = {
static const struct amdgpu_ih_funcs navi10_ih_funcs = {
.get_wptr = navi10_ih_get_wptr,
.decode_iv = amdgpu_ih_decode_iv_helper,
.decode_iv_ts = amdgpu_ih_decode_iv_ts_helper,
.set_rptr = navi10_ih_set_rptr
};

View File

@ -481,8 +481,6 @@ static void sdma_v5_0_ring_emit_ib(struct amdgpu_ring *ring,
* sdma_v5_0_ring_emit_mem_sync - flush the IB by graphics cache rinse
*
* @ring: amdgpu ring pointer
* @job: job to retrieve vmid from
* @ib: IB object to schedule
*
* flush the IB by graphics cache rinse.
*/

View File

@ -368,8 +368,6 @@ static void sdma_v5_2_ring_emit_ib(struct amdgpu_ring *ring,
* sdma_v5_2_ring_emit_mem_sync - flush the IB by graphics cache rinse
*
* @ring: amdgpu ring pointer
* @job: job to retrieve vmid from
* @ib: IB object to schedule
*
* flush the IB by graphics cache rinse.
*/

View File

@ -744,7 +744,7 @@ static void soc15_reg_base_init(struct amdgpu_device *adev)
vega10_reg_base_init(adev);
break;
case CHIP_RENOIR:
/* It's safe to do ip discovery here for Renior,
/* It's safe to do ip discovery here for Renoir,
* it doesn't support SRIOV. */
if (amdgpu_discovery) {
r = amdgpu_discovery_reg_base_init(adev);
@ -1238,6 +1238,8 @@ static int soc15_common_sw_init(void *handle)
if (amdgpu_sriov_vf(adev))
xgpu_ai_mailbox_add_irq_id(adev);
if (adev->df.funcs &&
adev->df.funcs->sw_init)
adev->df.funcs->sw_init(adev);
return 0;
@ -1250,6 +1252,9 @@ static int soc15_common_sw_fini(void *handle)
if (adev->nbio.ras_funcs &&
adev->nbio.ras_funcs->ras_fini)
adev->nbio.ras_funcs->ras_fini(adev);
if (adev->df.funcs &&
adev->df.funcs->sw_fini)
adev->df.funcs->sw_fini(adev);
return 0;
}

View File

@ -640,6 +640,7 @@ const struct amd_ip_funcs vega10_ih_ip_funcs = {
static const struct amdgpu_ih_funcs vega10_ih_funcs = {
.get_wptr = vega10_ih_get_wptr,
.decode_iv = amdgpu_ih_decode_iv_helper,
.decode_iv_ts = amdgpu_ih_decode_iv_ts_helper,
.set_rptr = vega10_ih_set_rptr
};

View File

@ -688,6 +688,7 @@ const struct amd_ip_funcs vega20_ih_ip_funcs = {
static const struct amdgpu_ih_funcs vega20_ih_funcs = {
.get_wptr = vega20_ih_get_wptr,
.decode_iv = amdgpu_ih_decode_iv_helper,
.decode_iv_ts = amdgpu_ih_decode_iv_ts_helper,
.set_rptr = vega20_ih_set_rptr
};

View File

@ -53,680 +53,242 @@ extern const struct kfd2kgd_calls aldebaran_kfd2kgd;
extern const struct kfd2kgd_calls gfx_v10_kfd2kgd;
extern const struct kfd2kgd_calls gfx_v10_3_kfd2kgd;
#ifdef KFD_SUPPORT_IOMMU_V2
static const struct kfd_device_info kaveri_device_info = {
.asic_name = "kaveri",
.gfx_target_version = 70000,
.max_pasid_bits = 16,
/* max num of queues for KV.TODO should be a dynamic value */
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = false,
.needs_iommu_device = true,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info carrizo_device_info = {
.asic_name = "carrizo",
.gfx_target_version = 80001,
.max_pasid_bits = 16,
/* max num of queues for CZ.TODO should be a dynamic value */
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = true,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info raven_device_info = {
.asic_name = "raven",
.gfx_target_version = 90002,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = true,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 2,
};
#endif
#ifdef CONFIG_DRM_AMDGPU_CIK
static const struct kfd_device_info hawaii_device_info = {
.asic_name = "hawaii",
.gfx_target_version = 70001,
.max_pasid_bits = 16,
/* max num of queues for KV.TODO should be a dynamic value */
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = false,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
#endif
static const struct kfd_device_info tonga_device_info = {
.asic_name = "tonga",
.gfx_target_version = 80002,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = false,
.needs_iommu_device = false,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info fiji_device_info = {
.asic_name = "fiji",
.gfx_target_version = 80003,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info fiji_vf_device_info = {
.asic_name = "fiji",
.gfx_target_version = 80003,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info polaris10_device_info = {
.asic_name = "polaris10",
.gfx_target_version = 80003,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info polaris10_vf_device_info = {
.asic_name = "polaris10",
.gfx_target_version = 80003,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info polaris11_device_info = {
.asic_name = "polaris11",
.gfx_target_version = 80003,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info polaris12_device_info = {
.asic_name = "polaris12",
.gfx_target_version = 80003,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info vegam_device_info = {
.asic_name = "vegam",
.gfx_target_version = 80003,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 4,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_cik,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info vega10_device_info = {
.asic_name = "vega10",
.gfx_target_version = 90000,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info vega10_vf_device_info = {
.asic_name = "vega10",
.gfx_target_version = 90000,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info vega12_device_info = {
.asic_name = "vega12",
.gfx_target_version = 90004,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info vega20_device_info = {
.asic_name = "vega20",
.gfx_target_version = 90006,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info arcturus_device_info = {
.asic_name = "arcturus",
.gfx_target_version = 90008,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info aldebaran_device_info = {
.asic_name = "aldebaran",
.gfx_target_version = 90010,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info renoir_device_info = {
.asic_name = "renoir",
.gfx_target_version = 90012,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.supports_cwsr = true,
.needs_iommu_device = false,
.needs_pci_atomics = false,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info navi10_device_info = {
.asic_name = "navi10",
.gfx_target_version = 100100,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 145,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info navi12_device_info = {
.asic_name = "navi12",
.gfx_target_version = 100101,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 145,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info navi14_device_info = {
.asic_name = "navi14",
.gfx_target_version = 100102,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 145,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info sienna_cichlid_device_info = {
.asic_name = "sienna_cichlid",
.gfx_target_version = 100300,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 92,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info navy_flounder_device_info = {
.asic_name = "navy_flounder",
.gfx_target_version = 100301,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 92,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info vangogh_device_info = {
.asic_name = "vangogh",
.gfx_target_version = 100303,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 92,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info dimgrey_cavefish_device_info = {
.asic_name = "dimgrey_cavefish",
.gfx_target_version = 100302,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 92,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info beige_goby_device_info = {
.asic_name = "beige_goby",
.gfx_target_version = 100304,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 92,
.num_sdma_queues_per_engine = 8,
};
static const struct kfd_device_info yellow_carp_device_info = {
.asic_name = "yellow_carp",
.gfx_target_version = 100305,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.no_atomic_fw_version = 92,
.num_sdma_queues_per_engine = 2,
};
static const struct kfd_device_info cyan_skillfish_device_info = {
.asic_name = "cyan_skillfish",
.gfx_target_version = 100103,
.max_pasid_bits = 16,
.max_no_of_hqd = 24,
.doorbell_size = 8,
.ih_ring_entry_size = 8 * sizeof(uint32_t),
.event_interrupt_class = &event_interrupt_class_v9,
.num_of_watch_points = 4,
.mqd_size_aligned = MQD_SIZE_ALIGNED,
.needs_iommu_device = false,
.supports_cwsr = true,
.needs_pci_atomics = true,
.num_sdma_queues_per_engine = 8,
};
static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
unsigned int chunk_size);
static void kfd_gtt_sa_fini(struct kfd_dev *kfd);
static int kfd_resume(struct kfd_dev *kfd);
static void kfd_device_info_init(struct kfd_dev *kfd,
bool vf, uint32_t gfx_target_version)
{
uint32_t gc_version = KFD_GC_VERSION(kfd);
uint32_t sdma_version = kfd->adev->ip_versions[SDMA0_HWIP][0];
uint32_t asic_type = kfd->adev->asic_type;
kfd->device_info.max_pasid_bits = 16;
kfd->device_info.max_no_of_hqd = 24;
kfd->device_info.num_of_watch_points = 4;
kfd->device_info.mqd_size_aligned = MQD_SIZE_ALIGNED;
kfd->device_info.gfx_target_version = gfx_target_version;
if (KFD_IS_SOC15(kfd)) {
kfd->device_info.doorbell_size = 8;
kfd->device_info.ih_ring_entry_size = 8 * sizeof(uint32_t);
kfd->device_info.event_interrupt_class = &event_interrupt_class_v9;
kfd->device_info.supports_cwsr = true;
if ((sdma_version >= IP_VERSION(4, 0, 0) &&
sdma_version <= IP_VERSION(4, 2, 0)) ||
sdma_version == IP_VERSION(5, 2, 1) ||
sdma_version == IP_VERSION(5, 2, 3))
kfd->device_info.num_sdma_queues_per_engine = 2;
else
kfd->device_info.num_sdma_queues_per_engine = 8;
/* Raven */
if (gc_version == IP_VERSION(9, 1, 0) ||
gc_version == IP_VERSION(9, 2, 2))
kfd->device_info.needs_iommu_device = true;
if (gc_version < IP_VERSION(11, 0, 0)) {
/* Navi2x+, Navi1x+ */
if (gc_version >= IP_VERSION(10, 3, 0))
kfd->device_info.no_atomic_fw_version = 92;
else if (gc_version >= IP_VERSION(10, 1, 1))
kfd->device_info.no_atomic_fw_version = 145;
/* Navi1x+ */
if (gc_version >= IP_VERSION(10, 1, 1))
kfd->device_info.needs_pci_atomics = true;
}
} else {
kfd->device_info.doorbell_size = 4;
kfd->device_info.ih_ring_entry_size = 4 * sizeof(uint32_t);
kfd->device_info.event_interrupt_class = &event_interrupt_class_cik;
kfd->device_info.num_sdma_queues_per_engine = 2;
if (asic_type != CHIP_KAVERI &&
asic_type != CHIP_HAWAII &&
asic_type != CHIP_TONGA)
kfd->device_info.supports_cwsr = true;
if (asic_type == CHIP_KAVERI ||
asic_type == CHIP_CARRIZO)
kfd->device_info.needs_iommu_device = true;
if (asic_type != CHIP_HAWAII && !vf)
kfd->device_info.needs_pci_atomics = true;
}
}
struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
{
struct kfd_dev *kfd;
const struct kfd_device_info *device_info;
const struct kfd2kgd_calls *f2g;
struct kfd_dev *kfd = NULL;
const struct kfd2kgd_calls *f2g = NULL;
struct pci_dev *pdev = adev->pdev;
uint32_t gfx_target_version = 0;
switch (adev->asic_type) {
#ifdef KFD_SUPPORT_IOMMU_V2
#ifdef CONFIG_DRM_AMDGPU_CIK
case CHIP_KAVERI:
if (vf)
device_info = NULL;
else
device_info = &kaveri_device_info;
gfx_target_version = 70000;
if (!vf)
f2g = &gfx_v7_kfd2kgd;
break;
#endif
case CHIP_CARRIZO:
if (vf)
device_info = NULL;
else
device_info = &carrizo_device_info;
gfx_target_version = 80001;
if (!vf)
f2g = &gfx_v8_kfd2kgd;
break;
#endif
#ifdef CONFIG_DRM_AMDGPU_CIK
case CHIP_HAWAII:
if (vf)
device_info = NULL;
else
device_info = &hawaii_device_info;
gfx_target_version = 70001;
if (!amdgpu_exp_hw_support)
pr_info(
"KFD support on Hawaii is experimental. See modparam exp_hw_support\n"
);
else if (!vf)
f2g = &gfx_v7_kfd2kgd;
break;
#endif
case CHIP_TONGA:
if (vf)
device_info = NULL;
else
device_info = &tonga_device_info;
gfx_target_version = 80002;
if (!vf)
f2g = &gfx_v8_kfd2kgd;
break;
case CHIP_FIJI:
if (vf)
device_info = &fiji_vf_device_info;
else
device_info = &fiji_device_info;
gfx_target_version = 80003;
f2g = &gfx_v8_kfd2kgd;
break;
case CHIP_POLARIS10:
if (vf)
device_info = &polaris10_vf_device_info;
else
device_info = &polaris10_device_info;
gfx_target_version = 80003;
f2g = &gfx_v8_kfd2kgd;
break;
case CHIP_POLARIS11:
if (vf)
device_info = NULL;
else
device_info = &polaris11_device_info;
gfx_target_version = 80003;
if (!vf)
f2g = &gfx_v8_kfd2kgd;
break;
case CHIP_POLARIS12:
if (vf)
device_info = NULL;
else
device_info = &polaris12_device_info;
gfx_target_version = 80003;
if (!vf)
f2g = &gfx_v8_kfd2kgd;
break;
case CHIP_VEGAM:
if (vf)
device_info = NULL;
else
device_info = &vegam_device_info;
gfx_target_version = 80003;
if (!vf)
f2g = &gfx_v8_kfd2kgd;
break;
default:
switch (adev->ip_versions[GC_HWIP][0]) {
/* Vega 10 */
case IP_VERSION(9, 0, 1):
if (vf)
device_info = &vega10_vf_device_info;
else
device_info = &vega10_device_info;
gfx_target_version = 90000;
f2g = &gfx_v9_kfd2kgd;
break;
#ifdef KFD_SUPPORT_IOMMU_V2
/* Raven */
case IP_VERSION(9, 1, 0):
case IP_VERSION(9, 2, 2):
if (vf)
device_info = NULL;
else
device_info = &raven_device_info;
gfx_target_version = 90002;
if (!vf)
f2g = &gfx_v9_kfd2kgd;
break;
#endif
/* Vega12 */
case IP_VERSION(9, 2, 1):
if (vf)
device_info = NULL;
else
device_info = &vega12_device_info;
gfx_target_version = 90004;
if (!vf)
f2g = &gfx_v9_kfd2kgd;
break;
/* Renoir */
case IP_VERSION(9, 3, 0):
if (vf)
device_info = NULL;
else
device_info = &renoir_device_info;
gfx_target_version = 90012;
if (!vf)
f2g = &gfx_v9_kfd2kgd;
break;
/* Vega20 */
case IP_VERSION(9, 4, 0):
if (vf)
device_info = NULL;
else
device_info = &vega20_device_info;
gfx_target_version = 90006;
if (!vf)
f2g = &gfx_v9_kfd2kgd;
break;
/* Arcturus */
case IP_VERSION(9, 4, 1):
device_info = &arcturus_device_info;
gfx_target_version = 90008;
f2g = &arcturus_kfd2kgd;
break;
/* Aldebaran */
case IP_VERSION(9, 4, 2):
device_info = &aldebaran_device_info;
gfx_target_version = 90010;
f2g = &aldebaran_kfd2kgd;
break;
/* Navi10 */
case IP_VERSION(10, 1, 10):
if (vf)
device_info = NULL;
else
device_info = &navi10_device_info;
gfx_target_version = 100100;
if (!vf)
f2g = &gfx_v10_kfd2kgd;
break;
/* Navi12 */
case IP_VERSION(10, 1, 2):
device_info = &navi12_device_info;
gfx_target_version = 100101;
f2g = &gfx_v10_kfd2kgd;
break;
/* Navi14 */
case IP_VERSION(10, 1, 1):
if (vf)
device_info = NULL;
else
device_info = &navi14_device_info;
gfx_target_version = 100102;
if (!vf)
f2g = &gfx_v10_kfd2kgd;
break;
/* Cyan Skillfish */
case IP_VERSION(10, 1, 3):
if (vf)
device_info = NULL;
else
device_info = &cyan_skillfish_device_info;
gfx_target_version = 100103;
if (!vf)
f2g = &gfx_v10_kfd2kgd;
break;
/* Sienna Cichlid */
case IP_VERSION(10, 3, 0):
device_info = &sienna_cichlid_device_info;
gfx_target_version = 100300;
f2g = &gfx_v10_3_kfd2kgd;
break;
/* Navy Flounder */
case IP_VERSION(10, 3, 2):
device_info = &navy_flounder_device_info;
gfx_target_version = 100301;
f2g = &gfx_v10_3_kfd2kgd;
break;
/* Van Gogh */
case IP_VERSION(10, 3, 1):
if (vf)
device_info = NULL;
else
device_info = &vangogh_device_info;
gfx_target_version = 100303;
if (!vf)
f2g = &gfx_v10_3_kfd2kgd;
break;
/* Dimgrey Cavefish */
case IP_VERSION(10, 3, 4):
device_info = &dimgrey_cavefish_device_info;
gfx_target_version = 100302;
f2g = &gfx_v10_3_kfd2kgd;
break;
/* Beige Goby */
case IP_VERSION(10, 3, 5):
device_info = &beige_goby_device_info;
gfx_target_version = 100304;
f2g = &gfx_v10_3_kfd2kgd;
break;
/* Yellow Carp */
case IP_VERSION(10, 3, 3):
if (vf)
device_info = NULL;
else
device_info = &yellow_carp_device_info;
gfx_target_version = 100305;
if (!vf)
f2g = &gfx_v10_3_kfd2kgd;
break;
default:
return NULL;
break;
}
break;
}
if (!device_info || !f2g) {
if (!f2g) {
if (adev->ip_versions[GC_HWIP][0])
dev_err(kfd_device, "GC IP %06x %s not supported in kfd\n",
adev->ip_versions[GC_HWIP][0], vf ? "VF" : "");
@ -741,7 +303,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
return NULL;
kfd->adev = adev;
kfd->device_info = device_info;
kfd_device_info_init(kfd, vf, gfx_target_version);
kfd->pdev = pdev;
kfd->init_complete = false;
kfd->kfd2kgd = f2g;
@ -760,7 +322,7 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
static void kfd_cwsr_init(struct kfd_dev *kfd)
{
if (cwsr_enable && kfd->device_info->supports_cwsr) {
if (cwsr_enable && kfd->device_info.supports_cwsr) {
if (KFD_GC_VERSION(kfd) < IP_VERSION(9, 0, 1)) {
BUILD_BUG_ON(sizeof(cwsr_trap_gfx8_hex) > PAGE_SIZE);
kfd->cwsr_isa = cwsr_trap_gfx8_hex;
@ -844,14 +406,14 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
*/
kfd->pci_atomic_requested = amdgpu_amdkfd_have_atomics_support(kfd->adev);
if (!kfd->pci_atomic_requested &&
kfd->device_info->needs_pci_atomics &&
(!kfd->device_info->no_atomic_fw_version ||
kfd->mec_fw_version < kfd->device_info->no_atomic_fw_version)) {
kfd->device_info.needs_pci_atomics &&
(!kfd->device_info.no_atomic_fw_version ||
kfd->mec_fw_version < kfd->device_info.no_atomic_fw_version)) {
dev_info(kfd_device,
"skipped device %x:%x, PCI rejects atomics %d<%d\n",
kfd->pdev->vendor, kfd->pdev->device,
kfd->mec_fw_version,
kfd->device_info->no_atomic_fw_version);
kfd->device_info.no_atomic_fw_version);
return false;
}
@ -868,7 +430,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
/* calculate max size of mqds needed for queues */
size = max_num_of_queues_per_device *
kfd->device_info->mqd_size_aligned;
kfd->device_info.mqd_size_aligned;
/*
* calculate max size of runlist packet.
@ -1143,7 +705,7 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
if (!kfd->init_complete)
return;
if (kfd->device_info->ih_ring_entry_size > sizeof(patched_ihre)) {
if (kfd->device_info.ih_ring_entry_size > sizeof(patched_ihre)) {
dev_err_once(kfd_device, "Ring entry too small\n");
return;
}

View File

@ -108,13 +108,13 @@ static unsigned int get_num_all_sdma_engines(struct device_queue_manager *dqm)
unsigned int get_num_sdma_queues(struct device_queue_manager *dqm)
{
return kfd_get_num_sdma_engines(dqm->dev) *
dqm->dev->device_info->num_sdma_queues_per_engine;
dqm->dev->device_info.num_sdma_queues_per_engine;
}
unsigned int get_num_xgmi_sdma_queues(struct device_queue_manager *dqm)
{
return kfd_get_num_xgmi_sdma_engines(dqm->dev) *
dqm->dev->device_info->num_sdma_queues_per_engine;
dqm->dev->device_info.num_sdma_queues_per_engine;
}
void program_sh_mem_settings(struct device_queue_manager *dqm,
@ -1838,7 +1838,7 @@ static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm)
struct kfd_mem_obj *mem_obj = &dqm->hiq_sdma_mqd;
uint32_t size = dqm->mqd_mgrs[KFD_MQD_TYPE_SDMA]->mqd_size *
get_num_all_sdma_engines(dqm) *
dev->device_info->num_sdma_queues_per_engine +
dev->device_info.num_sdma_queues_per_engine +
dqm->mqd_mgrs[KFD_MQD_TYPE_HIQ]->mqd_size;
retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, size,
@ -2082,7 +2082,7 @@ int dqm_debugfs_hqds(struct seq_file *m, void *data)
for (pipe = 0; pipe < get_num_all_sdma_engines(dqm); pipe++) {
for (queue = 0;
queue < dqm->dev->device_info->num_sdma_queues_per_engine;
queue < dqm->dev->device_info.num_sdma_queues_per_engine;
queue++) {
r = dqm->dev->kfd2kgd->hqd_sdma_dump(
dqm->dev->adev, pipe, queue, &dump, &n_regs);

View File

@ -48,7 +48,7 @@
/* # of doorbell bytes allocated for each process. */
size_t kfd_doorbell_process_slice(struct kfd_dev *kfd)
{
return roundup(kfd->device_info->doorbell_size *
return roundup(kfd->device_info.doorbell_size *
KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
PAGE_SIZE);
}
@ -180,7 +180,7 @@ void __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
return NULL;
inx *= kfd->device_info->doorbell_size / sizeof(u32);
inx *= kfd->device_info.doorbell_size / sizeof(u32);
/*
* Calculating the kernel doorbell offset using the first
@ -201,7 +201,7 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr)
unsigned int inx;
inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr)
* sizeof(u32) / kfd->device_info->doorbell_size;
* sizeof(u32) / kfd->device_info.doorbell_size;
mutex_lock(&kfd->doorbell_mutex);
__clear_bit(inx, kfd->doorbell_available_index);
@ -239,7 +239,7 @@ unsigned int kfd_get_doorbell_dw_offset_in_bar(struct kfd_dev *kfd,
return kfd->doorbell_base_dw_offset +
pdd->doorbell_index
* kfd_doorbell_process_slice(kfd) / sizeof(u32) +
doorbell_id * kfd->device_info->doorbell_size / sizeof(u32);
doorbell_id * kfd->device_info.doorbell_size / sizeof(u32);
}
uint64_t kfd_get_number_elems(struct kfd_dev *kfd)

View File

@ -135,7 +135,7 @@ static bool event_interrupt_isr_v9(struct kfd_dev *dev,
*patched_flag = true;
memcpy(patched_ihre, ih_ring_entry,
dev->device_info->ih_ring_entry_size);
dev->device_info.ih_ring_entry_size);
pasid = dev->dqm->vmid_pasid[vmid];

View File

@ -54,7 +54,7 @@ int kfd_interrupt_init(struct kfd_dev *kfd)
int r;
r = kfifo_alloc(&kfd->ih_fifo,
KFD_IH_NUM_ENTRIES * kfd->device_info->ih_ring_entry_size,
KFD_IH_NUM_ENTRIES * kfd->device_info.ih_ring_entry_size,
GFP_KERNEL);
if (r) {
dev_err(kfd_chardev(), "Failed to allocate IH fifo\n");
@ -114,8 +114,8 @@ bool enqueue_ih_ring_entry(struct kfd_dev *kfd, const void *ih_ring_entry)
int count;
count = kfifo_in(&kfd->ih_fifo, ih_ring_entry,
kfd->device_info->ih_ring_entry_size);
if (count != kfd->device_info->ih_ring_entry_size) {
kfd->device_info.ih_ring_entry_size);
if (count != kfd->device_info.ih_ring_entry_size) {
dev_err_ratelimited(kfd_chardev(),
"Interrupt ring overflow, dropping interrupt %d\n",
count);
@ -133,11 +133,11 @@ static bool dequeue_ih_ring_entry(struct kfd_dev *kfd, void *ih_ring_entry)
int count;
count = kfifo_out(&kfd->ih_fifo, ih_ring_entry,
kfd->device_info->ih_ring_entry_size);
kfd->device_info.ih_ring_entry_size);
WARN_ON(count && count != kfd->device_info->ih_ring_entry_size);
WARN_ON(count && count != kfd->device_info.ih_ring_entry_size);
return count == kfd->device_info->ih_ring_entry_size;
return count == kfd->device_info.ih_ring_entry_size;
}
static void interrupt_wq(struct work_struct *work)
@ -146,13 +146,13 @@ static void interrupt_wq(struct work_struct *work)
interrupt_work);
uint32_t ih_ring_entry[KFD_MAX_RING_ENTRY_SIZE];
if (dev->device_info->ih_ring_entry_size > sizeof(ih_ring_entry)) {
if (dev->device_info.ih_ring_entry_size > sizeof(ih_ring_entry)) {
dev_err_once(kfd_chardev(), "Ring entry too small\n");
return;
}
while (dequeue_ih_ring_entry(dev, ih_ring_entry))
dev->device_info->event_interrupt_class->interrupt_wq(dev,
dev->device_info.event_interrupt_class->interrupt_wq(dev,
ih_ring_entry);
}
@ -163,7 +163,7 @@ bool interrupt_is_wanted(struct kfd_dev *dev,
/* integer and bitwise OR so there is no boolean short-circuiting */
unsigned int wanted = 0;
wanted |= dev->device_info->event_interrupt_class->interrupt_isr(dev,
wanted |= dev->device_info.event_interrupt_class->interrupt_isr(dev,
ih_ring_entry, patched_ihre, flag);
return wanted != 0;

View File

@ -89,7 +89,7 @@ int kfd_iommu_device_init(struct kfd_dev *kfd)
}
pasid_limit = min_t(unsigned int,
(unsigned int)(1 << kfd->device_info->max_pasid_bits),
(unsigned int)(1 << kfd->device_info.max_pasid_bits),
iommu_info.max_pasids);
if (!kfd_set_pasid_limit(pasid_limit)) {

View File

@ -111,7 +111,7 @@ static bool kq_initialize(struct kernel_queue *kq, struct kfd_dev *dev,
kq->rptr_kernel = kq->rptr_mem->cpu_ptr;
kq->rptr_gpu_addr = kq->rptr_mem->gpu_addr;
retval = kfd_gtt_sa_allocate(dev, dev->device_info->doorbell_size,
retval = kfd_gtt_sa_allocate(dev, dev->device_info.doorbell_size,
&kq->wptr_mem);
if (retval != 0)
@ -297,7 +297,7 @@ void kq_submit_packet(struct kernel_queue *kq)
}
pr_debug("\n");
#endif
if (kq->dev->device_info->doorbell_size == 8) {
if (kq->dev->device_info.doorbell_size == 8) {
*kq->wptr64_kernel = kq->pending_wptr64;
write_kernel_doorbell64(kq->queue->properties.doorbell_ptr,
kq->pending_wptr64);
@ -310,7 +310,7 @@ void kq_submit_packet(struct kernel_queue *kq)
void kq_rollback_packet(struct kernel_queue *kq)
{
if (kq->dev->device_info->doorbell_size == 8) {
if (kq->dev->device_info.doorbell_size == 8) {
kq->pending_wptr64 = *kq->wptr64_kernel;
kq->pending_wptr = *kq->wptr_kernel %
(kq->queue->properties.queue_size / 4);

View File

@ -108,8 +108,8 @@ error_free:
* svm_migrate_copy_memory_gart - sdma copy data between ram and vram
*
* @adev: amdgpu device the sdma ring running
* @src: source page address array
* @dst: destination page address array
* @sys: system DMA pointer to be copied
* @vram: vram destination DMA pointer
* @npages: number of pages to copy
* @direction: enum MIGRATION_COPY_DIR
* @mfence: output, sdma fence to signal after sdma is done

View File

@ -71,7 +71,7 @@ struct kfd_mem_obj *allocate_sdma_mqd(struct kfd_dev *dev,
return NULL;
offset = (q->sdma_engine_id *
dev->device_info->num_sdma_queues_per_engine +
dev->device_info.num_sdma_queues_per_engine +
q->sdma_queue_id) *
dev->dqm->mqd_mgrs[KFD_MQD_TYPE_SDMA]->mqd_size;

View File

@ -110,7 +110,7 @@ static int pm_runlist_vi(struct packet_manager *pm, uint32_t *buffer,
return 0;
}
int pm_set_resources_vi(struct packet_manager *pm, uint32_t *buffer,
static int pm_set_resources_vi(struct packet_manager *pm, uint32_t *buffer,
struct scheduling_resources *res)
{
struct pm4_mes_set_resources *packet;

View File

@ -195,7 +195,6 @@ struct kfd_event_interrupt_class {
};
struct kfd_device_info {
const char *asic_name;
uint32_t gfx_target_version;
const struct kfd_event_interrupt_class *event_interrupt_class;
unsigned int max_pasid_bits;
@ -231,7 +230,7 @@ struct kfd_vmid_info {
struct kfd_dev {
struct amdgpu_device *adev;
const struct kfd_device_info *device_info;
struct kfd_device_info device_info;
struct pci_dev *pdev;
struct drm_device *ddev;

View File

@ -251,14 +251,13 @@ cleanup:
}
/**
* @kfd_get_cu_occupancy - Collect number of waves in-flight on this device
* kfd_get_cu_occupancy - Collect number of waves in-flight on this device
* by current process. Translates acquired wave count into number of compute units
* that are occupied.
*
* @atr: Handle of attribute that allows reporting of wave count. The attribute
* @attr: Handle of attribute that allows reporting of wave count. The attribute
* handle encapsulates GPU device it is associated with, thereby allowing collection
* of waves in flight, etc
*
* @buffer: Handle of user provided buffer updated with wave count
*
* Return: Number of bytes written to user buffer or an error value
@ -1011,7 +1010,7 @@ static void kfd_process_destroy_pdds(struct kfd_process *p)
free_pages((unsigned long)pdd->qpd.cwsr_kaddr,
get_order(KFD_CWSR_TBA_TMA_SIZE));
kfree(pdd->qpd.doorbell_bitmap);
bitmap_free(pdd->qpd.doorbell_bitmap);
idr_destroy(&pdd->alloc_idr);
kfd_free_process_doorbells(pdd->dev, pdd->doorbell_index);
@ -1433,9 +1432,8 @@ static int init_doorbell_bitmap(struct qcm_process_device *qpd,
if (!KFD_IS_SOC15(dev))
return 0;
qpd->doorbell_bitmap =
kzalloc(DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
BITS_PER_BYTE), GFP_KERNEL);
qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
GFP_KERNEL);
if (!qpd->doorbell_bitmap)
return -ENOMEM;
@ -1447,8 +1445,8 @@ static int init_doorbell_bitmap(struct qcm_process_device *qpd,
for (i = 0; i < KFD_MAX_NUM_OF_QUEUES_PER_PROCESS / 2; i++) {
if (i >= range_start && i <= range_end) {
set_bit(i, qpd->doorbell_bitmap);
set_bit(i + KFD_QUEUE_DOORBELL_MIRROR_OFFSET,
__set_bit(i, qpd->doorbell_bitmap);
__set_bit(i + KFD_QUEUE_DOORBELL_MIRROR_OFFSET,
qpd->doorbell_bitmap);
}
}

View File

@ -135,9 +135,8 @@ void kfd_process_dequeue_from_all_devices(struct kfd_process *p)
int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p)
{
INIT_LIST_HEAD(&pqm->queues);
pqm->queue_slot_bitmap =
kzalloc(DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
BITS_PER_BYTE), GFP_KERNEL);
pqm->queue_slot_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
GFP_KERNEL);
if (!pqm->queue_slot_bitmap)
return -ENOMEM;
pqm->process = p;
@ -159,7 +158,7 @@ void pqm_uninit(struct process_queue_manager *pqm)
kfree(pqn);
}
kfree(pqm->queue_slot_bitmap);
bitmap_free(pqm->queue_slot_bitmap);
pqm->queue_slot_bitmap = NULL;
}
@ -220,7 +219,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
* Hence we also check the type as well
*/
if ((pdd->qpd.is_debug) || (type == KFD_QUEUE_TYPE_DIQ))
max_queues = dev->device_info->max_no_of_hqd/2;
max_queues = dev->device_info.max_no_of_hqd/2;
if (pdd->qpd.queue_count >= max_queues)
return -ENOSPC;

View File

@ -704,6 +704,61 @@ svm_range_apply_attrs(struct kfd_process *p, struct svm_range *prange,
}
}
static bool
svm_range_is_same_attrs(struct kfd_process *p, struct svm_range *prange,
uint32_t nattr, struct kfd_ioctl_svm_attribute *attrs)
{
uint32_t i;
int gpuidx;
for (i = 0; i < nattr; i++) {
switch (attrs[i].type) {
case KFD_IOCTL_SVM_ATTR_PREFERRED_LOC:
if (prange->preferred_loc != attrs[i].value)
return false;
break;
case KFD_IOCTL_SVM_ATTR_PREFETCH_LOC:
/* Prefetch should always trigger a migration even
* if the value of the attribute didn't change.
*/
return false;
case KFD_IOCTL_SVM_ATTR_ACCESS:
case KFD_IOCTL_SVM_ATTR_ACCESS_IN_PLACE:
case KFD_IOCTL_SVM_ATTR_NO_ACCESS:
gpuidx = kfd_process_gpuidx_from_gpuid(p,
attrs[i].value);
if (attrs[i].type == KFD_IOCTL_SVM_ATTR_NO_ACCESS) {
if (test_bit(gpuidx, prange->bitmap_access) ||
test_bit(gpuidx, prange->bitmap_aip))
return false;
} else if (attrs[i].type == KFD_IOCTL_SVM_ATTR_ACCESS) {
if (!test_bit(gpuidx, prange->bitmap_access))
return false;
} else {
if (!test_bit(gpuidx, prange->bitmap_aip))
return false;
}
break;
case KFD_IOCTL_SVM_ATTR_SET_FLAGS:
if ((prange->flags & attrs[i].value) != attrs[i].value)
return false;
break;
case KFD_IOCTL_SVM_ATTR_CLR_FLAGS:
if ((prange->flags & attrs[i].value) != 0)
return false;
break;
case KFD_IOCTL_SVM_ATTR_GRANULARITY:
if (prange->granularity != attrs[i].value)
return false;
break;
default:
WARN_ONCE(1, "svm_range_check_attrs wasn't called?");
}
}
return true;
}
/**
* svm_range_debug_dump - print all range information from svms
* @svms: svm range list header
@ -741,14 +796,6 @@ static void svm_range_debug_dump(struct svm_range_list *svms)
}
}
static bool
svm_range_is_same_attrs(struct svm_range *old, struct svm_range *new)
{
return (old->prefetch_loc == new->prefetch_loc &&
old->flags == new->flags &&
old->granularity == new->granularity);
}
static int
svm_range_split_array(void *ppnew, void *ppold, size_t size,
uint64_t old_start, uint64_t old_n,
@ -941,7 +988,7 @@ svm_range_split(struct svm_range *prange, uint64_t start, uint64_t last,
}
static int
svm_range_split_tail(struct svm_range *prange, struct svm_range *new,
svm_range_split_tail(struct svm_range *prange,
uint64_t new_last, struct list_head *insert_list)
{
struct svm_range *tail;
@ -953,7 +1000,7 @@ svm_range_split_tail(struct svm_range *prange, struct svm_range *new,
}
static int
svm_range_split_head(struct svm_range *prange, struct svm_range *new,
svm_range_split_head(struct svm_range *prange,
uint64_t new_start, struct list_head *insert_list)
{
struct svm_range *head;
@ -1169,7 +1216,6 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,
unsigned long npages, bool readonly, dma_addr_t *dma_addr,
struct amdgpu_device *bo_adev, struct dma_fence **fence)
{
struct amdgpu_bo_va bo_va;
bool table_freed = false;
uint64_t pte_flags;
unsigned long last_start;
@ -1182,9 +1228,6 @@ svm_range_map_to_gpu(struct amdgpu_device *adev, struct amdgpu_vm *vm,
pr_debug("svms 0x%p [0x%lx 0x%lx] readonly %d\n", prange->svms,
last_start, last_start + npages - 1, readonly);
if (prange->svm_bo && prange->ttm_res)
bo_va.is_xgmi = amdgpu_xgmi_same_hive(adev, bo_adev);
for (i = offset; i < offset + npages; i++) {
last_domain = dma_addr[i] & SVM_RANGE_VRAM_DOMAIN;
dma_addr[i] &= ~SVM_RANGE_VRAM_DOMAIN;
@ -1650,6 +1693,10 @@ out_reschedule:
/**
* svm_range_evict - evict svm range
* @prange: svm range structure
* @mm: current process mm_struct
* @start: starting process queue number
* @last: last process queue number
*
* Stop all queues of the process to ensure GPU doesn't access the memory, then
* return to let CPU evict the buffer and proceed CPU pagetable update.
@ -1754,46 +1801,49 @@ static struct svm_range *svm_range_clone(struct svm_range *old)
}
/**
* svm_range_handle_overlap - split overlap ranges
* @svms: svm range list header
* @new: range added with this attributes
* @start: range added start address, in pages
* @last: range last address, in pages
* @update_list: output, the ranges attributes are updated. For set_attr, this
* will do validation and map to GPUs. For unmap, this will be
* removed and unmap from GPUs
* @insert_list: output, the ranges will be inserted into svms, attributes are
* not changes. For set_attr, this will add into svms.
* @remove_list:output, the ranges will be removed from svms
* @left: the remaining range after overlap, For set_attr, this will be added
* as new range.
* svm_range_add - add svm range and handle overlap
* @p: the range add to this process svms
* @start: page size aligned
* @size: page size aligned
* @nattr: number of attributes
* @attrs: array of attributes
* @update_list: output, the ranges need validate and update GPU mapping
* @insert_list: output, the ranges need insert to svms
* @remove_list: output, the ranges are replaced and need remove from svms
*
* Total have 5 overlap cases.
* Check if the virtual address range has overlap with any existing ranges,
* split partly overlapping ranges and add new ranges in the gaps. All changes
* should be applied to the range_list and interval tree transactionally. If
* any range split or allocation fails, the entire update fails. Therefore any
* existing overlapping svm_ranges are cloned and the original svm_ranges left
* unchanged.
*
* This function handles overlap of an address interval with existing
* struct svm_ranges for applying new attributes. This may require
* splitting existing struct svm_ranges. All changes should be applied to
* the range_list and interval tree transactionally. If any split operation
* fails, the entire update fails. Therefore the existing overlapping
* svm_ranges are cloned and the original svm_ranges left unchanged. If the
* transaction succeeds, the modified clones are added and the originals
* freed. Otherwise the clones are removed and the old svm_ranges remain.
* If the transaction succeeds, the caller can update and insert clones and
* new ranges, then free the originals.
*
* Context: The caller must hold svms->lock
* Otherwise the caller can free the clones and new ranges, while the old
* svm_ranges remain unchanged.
*
* Context: Process context, caller must hold svms->lock
*
* Return:
* 0 - OK, otherwise error code
*/
static int
svm_range_handle_overlap(struct svm_range_list *svms, struct svm_range *new,
unsigned long start, unsigned long last,
struct list_head *update_list,
struct list_head *insert_list,
struct list_head *remove_list,
unsigned long *left)
svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size,
uint32_t nattr, struct kfd_ioctl_svm_attribute *attrs,
struct list_head *update_list, struct list_head *insert_list,
struct list_head *remove_list)
{
unsigned long last = start + size - 1UL;
struct svm_range_list *svms = &p->svms;
struct interval_tree_node *node;
struct svm_range *prange;
struct svm_range *tmp;
int r = 0;
pr_debug("svms 0x%p [0x%llx 0x%lx]\n", &p->svms, start, last);
INIT_LIST_HEAD(update_list);
INIT_LIST_HEAD(insert_list);
INIT_LIST_HEAD(remove_list);
@ -1801,18 +1851,24 @@ svm_range_handle_overlap(struct svm_range_list *svms, struct svm_range *new,
node = interval_tree_iter_first(&svms->objects, start, last);
while (node) {
struct interval_tree_node *next;
struct svm_range *old;
unsigned long next_start;
pr_debug("found overlap node [0x%lx 0x%lx]\n", node->start,
node->last);
old = container_of(node, struct svm_range, it_node);
prange = container_of(node, struct svm_range, it_node);
next = interval_tree_iter_next(node, start, last);
next_start = min(node->last, last) + 1;
if (node->start < start || node->last > last) {
/* node intersects the updated range, clone+split it */
if (svm_range_is_same_attrs(p, prange, nattr, attrs)) {
/* nothing to do */
} else if (node->start < start || node->last > last) {
/* node intersects the update range and its attributes
* will change. Clone and split it, apply updates only
* to the overlapping part
*/
struct svm_range *old = prange;
prange = svm_range_clone(old);
if (!prange) {
r = -ENOMEM;
@ -1821,17 +1877,18 @@ svm_range_handle_overlap(struct svm_range_list *svms, struct svm_range *new,
list_add(&old->remove_list, remove_list);
list_add(&prange->insert_list, insert_list);
list_add(&prange->update_list, update_list);
if (node->start < start) {
pr_debug("change old range start\n");
r = svm_range_split_head(prange, new, start,
r = svm_range_split_head(prange, start,
insert_list);
if (r)
goto out;
}
if (node->last > last) {
pr_debug("change old range last\n");
r = svm_range_split_tail(prange, new, last,
r = svm_range_split_tail(prange, last,
insert_list);
if (r)
goto out;
@ -1840,16 +1897,12 @@ svm_range_handle_overlap(struct svm_range_list *svms, struct svm_range *new,
/* The node is contained within start..last,
* just update it
*/
prange = old;
}
if (!svm_range_is_same_attrs(prange, new))
list_add(&prange->update_list, update_list);
}
/* insert a new node if needed */
if (node->start > start) {
prange = svm_range_new(prange->svms, start,
node->start - 1);
prange = svm_range_new(svms, start, node->start - 1);
if (!prange) {
r = -ENOMEM;
goto out;
@ -1863,8 +1916,16 @@ svm_range_handle_overlap(struct svm_range_list *svms, struct svm_range *new,
start = next_start;
}
if (left && start <= last)
*left = last - start + 1;
/* add a final range at the end if needed */
if (start <= last) {
prange = svm_range_new(svms, start, last);
if (!prange) {
r = -ENOMEM;
goto out;
}
list_add(&prange->insert_list, insert_list);
list_add(&prange->update_list, update_list);
}
out:
if (r)
@ -1970,7 +2031,7 @@ restart:
pr_debug("drain retry fault gpu %d svms %p\n", i, svms);
amdgpu_ih_wait_on_checkpoint_process(pdd->dev->adev,
amdgpu_ih_wait_on_checkpoint_process_ts(pdd->dev->adev,
&pdd->dev->adev->irq.ih1);
pr_debug("drain retry fault gpu %d svms 0x%p done\n", i, svms);
}
@ -2161,6 +2222,9 @@ svm_range_unmap_from_cpu(struct mm_struct *mm, struct svm_range *prange,
/**
* svm_range_cpu_invalidate_pagetables - interval notifier callback
* @mni: mmu_interval_notifier struct
* @range: mmu_notifier_range struct
* @cur_seq: value to pass to mmu_interval_set_seq()
*
* If event is MMU_NOTIFY_UNMAP, this is from CPU unmap range, otherwise, it
* is from migration, or CPU page invalidation callback.
@ -2883,59 +2947,6 @@ svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size)
NULL);
}
/**
* svm_range_add - add svm range and handle overlap
* @p: the range add to this process svms
* @start: page size aligned
* @size: page size aligned
* @nattr: number of attributes
* @attrs: array of attributes
* @update_list: output, the ranges need validate and update GPU mapping
* @insert_list: output, the ranges need insert to svms
* @remove_list: output, the ranges are replaced and need remove from svms
*
* Check if the virtual address range has overlap with the registered ranges,
* split the overlapped range, copy and adjust pages address and vram nodes in
* old and new ranges.
*
* Context: Process context, caller must hold svms->lock
*
* Return:
* 0 - OK, otherwise error code
*/
static int
svm_range_add(struct kfd_process *p, uint64_t start, uint64_t size,
uint32_t nattr, struct kfd_ioctl_svm_attribute *attrs,
struct list_head *update_list, struct list_head *insert_list,
struct list_head *remove_list)
{
uint64_t last = start + size - 1UL;
struct svm_range_list *svms;
struct svm_range new = {0};
struct svm_range *prange;
unsigned long left = 0;
int r = 0;
pr_debug("svms 0x%p [0x%llx 0x%llx]\n", &p->svms, start, last);
svm_range_apply_attrs(p, &new, nattr, attrs);
svms = &p->svms;
r = svm_range_handle_overlap(svms, &new, start, last, update_list,
insert_list, remove_list, &left);
if (r)
return r;
if (left) {
prange = svm_range_new(svms, last - left + 1, last);
list_add(&prange->insert_list, insert_list);
list_add(&prange->update_list, update_list);
}
return 0;
}
/**
* svm_range_best_prefetch_location - decide the best prefetch location
* @prange: svm range structure

View File

@ -503,7 +503,7 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
if (dev->gpu) {
log_max_watch_addr =
__ilog2_u32(dev->gpu->device_info->num_of_watch_points);
__ilog2_u32(dev->gpu->device_info.num_of_watch_points);
if (log_max_watch_addr) {
dev->node_props.capability |=
@ -1285,6 +1285,8 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
void *crat_image = NULL;
size_t image_size = 0;
int proximity_domain;
int i;
const char *asic_name = amdgpu_asic_name[gpu->adev->asic_type];
INIT_LIST_HEAD(&temp_topology_device_list);
@ -1370,13 +1372,17 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
amdgpu_amdkfd_get_cu_info(dev->gpu->adev, &cu_info);
strncpy(dev->node_props.name, gpu->device_info->asic_name,
KFD_TOPOLOGY_PUBLIC_NAME_SIZE);
for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1; i++) {
dev->node_props.name[i] = __tolower(asic_name[i]);
if (asic_name[i] == '\0')
break;
}
dev->node_props.name[i] = '\0';
dev->node_props.simd_arrays_per_engine =
cu_info.num_shader_arrays_per_engine;
dev->node_props.gfx_target_version = gpu->device_info->gfx_target_version;
dev->node_props.gfx_target_version = gpu->device_info.gfx_target_version;
dev->node_props.vendor_id = gpu->pdev->vendor;
dev->node_props.device_id = gpu->pdev->device;
dev->node_props.capability |=
@ -1396,7 +1402,7 @@ int kfd_topology_add_device(struct kfd_dev *gpu)
dev->node_props.num_sdma_xgmi_engines =
kfd_get_num_xgmi_sdma_engines(gpu);
dev->node_props.num_sdma_queues_per_engine =
gpu->device_info->num_sdma_queues_per_engine;
gpu->device_info.num_sdma_queues_per_engine;
dev->node_props.num_gws = (dev->gpu->gws &&
dev->gpu->dqm->sched_policy != KFD_SCHED_POLICY_NO_HWS) ?
dev->gpu->adev->gds.gws_size : 0;
@ -1572,7 +1578,7 @@ void kfd_double_confirm_iommu_support(struct kfd_dev *gpu)
gpu->use_iommu_v2 = false;
if (!gpu->device_info->needs_iommu_device)
if (!gpu->device_info.needs_iommu_device)
return;
down_read(&topology_lock);

View File

@ -624,7 +624,7 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
#endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */
/**
* dmub_aux_setconfig_reply_callback - Callback for AUX or SET_CONFIG command.
* dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command.
* @adev: amdgpu_device pointer
* @notify: dmub notification structure
*
@ -632,7 +632,8 @@ static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params)
* Copies dmub notification to DM which is to be read by AUX command.
* issuing thread and also signals the event to wake up the thread.
*/
void dmub_aux_setconfig_callback(struct amdgpu_device *adev, struct dmub_notification *notify)
static void dmub_aux_setconfig_callback(struct amdgpu_device *adev,
struct dmub_notification *notify)
{
if (adev->dm.dmub_notify)
memcpy(adev->dm.dmub_notify, notify, sizeof(struct dmub_notification));
@ -648,7 +649,8 @@ void dmub_aux_setconfig_callback(struct amdgpu_device *adev, struct dmub_notific
* Dmub Hpd interrupt processing callback. Gets displayindex through the
* ink index and calls helper to do the processing.
*/
void dmub_hpd_callback(struct amdgpu_device *adev, struct dmub_notification *notify)
static void dmub_hpd_callback(struct amdgpu_device *adev,
struct dmub_notification *notify)
{
struct amdgpu_dm_connector *aconnector;
struct amdgpu_dm_connector *hpd_aconnector = NULL;
@ -705,8 +707,10 @@ void dmub_hpd_callback(struct amdgpu_device *adev, struct dmub_notification *not
* to dmub interrupt handling thread
* Return: true if successfully registered, false if there is existing registration
*/
bool register_dmub_notify_callback(struct amdgpu_device *adev, enum dmub_notification_type type,
dmub_notify_interrupt_callback_t callback, bool dmub_int_thread_offload)
static bool register_dmub_notify_callback(struct amdgpu_device *adev,
enum dmub_notification_type type,
dmub_notify_interrupt_callback_t callback,
bool dmub_int_thread_offload)
{
if (callback != NULL && type < ARRAY_SIZE(adev->dm.dmub_thread_offload)) {
adev->dm.dmub_callback[type] = callback;
@ -1050,6 +1054,11 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
return 0;
}
/* Reset DMCUB if it was previously running - before we overwrite its memory. */
status = dmub_srv_hw_reset(dmub_srv);
if (status != DMUB_STATUS_OK)
DRM_WARN("Error resetting DMUB HW: %d\n", status);
hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data;
fw_inst_const = dmub_fw->data +
@ -1453,6 +1462,13 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_feature_mask & DC_EDP_NO_POWER_SEQUENCING)
init_data.flags.edp_no_power_sequencing = true;
#ifdef CONFIG_DRM_AMD_DC_DCN
if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP1_4A)
init_data.flags.allow_lttpr_non_transparent_mode.bits.DP1_4A = true;
if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP2_0)
init_data.flags.allow_lttpr_non_transparent_mode.bits.DP2_0 = true;
#endif
init_data.flags.power_down_display_on_boot = true;
if (check_seamless_boot_capability(adev)) {
@ -2950,13 +2966,12 @@ void amdgpu_dm_update_connector_after_detect(
aconnector->edid =
(struct edid *)sink->dc_edid.raw_edid;
drm_connector_update_edid_property(connector,
aconnector->edid);
if (aconnector->dc_link->aux_mode)
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
aconnector->edid);
}
drm_connector_update_edid_property(connector, aconnector->edid);
amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
update_connector_ext_caps(aconnector);
} else {
@ -6061,6 +6076,8 @@ static void update_dsc_caps(struct amdgpu_dm_connector *aconnector,
if (aconnector->dc_link && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT ||
sink->sink_signal == SIGNAL_TYPE_EDP)) {
if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE ||
sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)
dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
@ -6134,6 +6151,8 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
uint32_t link_bandwidth_kbps;
uint32_t max_dsc_target_bpp_limit_override = 0;
struct dc *dc = sink->ctx->dc;
uint32_t max_supported_bw_in_kbps, timing_bw_in_kbps;
uint32_t dsc_max_supported_bw_in_kbps;
link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
dc_link_get_link_cap(aconnector->dc_link));
@ -6152,7 +6171,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
apply_dsc_policy_for_edp(aconnector, sink, stream, dsc_caps, max_dsc_target_bpp_limit_override);
} else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) {
if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) {
if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
dsc_caps,
aconnector->dc_link->ctx->dc->debug.dsc_min_slice_height_override,
@ -6161,7 +6180,28 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
&stream->timing,
&stream->timing.dsc_cfg)) {
stream->timing.flags.DSC = 1;
DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from SST RX\n", __func__, drm_connector->name);
DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from SST RX\n",
__func__, drm_connector->name);
}
} else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing);
max_supported_bw_in_kbps = link_bandwidth_kbps;
dsc_max_supported_bw_in_kbps = link_bandwidth_kbps;
if (timing_bw_in_kbps > max_supported_bw_in_kbps &&
max_supported_bw_in_kbps > 0 &&
dsc_max_supported_bw_in_kbps > 0)
if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0],
dsc_caps,
aconnector->dc_link->ctx->dc->debug.dsc_min_slice_height_override,
max_dsc_target_bpp_limit_override,
dsc_max_supported_bw_in_kbps,
&stream->timing,
&stream->timing.dsc_cfg)) {
stream->timing.flags.DSC = 1;
DRM_DEBUG_DRIVER("%s: [%s] DSC is selected from DP-HDMI PCON\n",
__func__, drm_connector->name);
}
}
}
@ -8305,15 +8345,8 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
break;
case DRM_MODE_CONNECTOR_DisplayPort:
aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
if (link->is_dig_mapping_flexible &&
link->dc->res_pool->funcs->link_encs_assign) {
link->link_enc =
link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
if (!link->link_enc)
link->link_enc =
link_enc_cfg_get_next_avail_link_enc(link->ctx->dc);
}
link->link_enc = dp_get_link_enc(link);
ASSERT(link->link_enc);
if (link->link_enc)
aconnector->base.ycbcr_420_allowed =
link->link_enc->features.dp_ycbcr420_supported ? true : false;
@ -10716,6 +10749,24 @@ static int dm_update_plane_state(struct dc *dc,
return ret;
}
static void dm_get_oriented_plane_size(struct drm_plane_state *plane_state,
int *src_w, int *src_h)
{
switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) {
case DRM_MODE_ROTATE_90:
case DRM_MODE_ROTATE_270:
*src_w = plane_state->src_h >> 16;
*src_h = plane_state->src_w >> 16;
break;
case DRM_MODE_ROTATE_0:
case DRM_MODE_ROTATE_180:
default:
*src_w = plane_state->src_w >> 16;
*src_h = plane_state->src_h >> 16;
break;
}
}
static int dm_check_crtc_cursor(struct drm_atomic_state *state,
struct drm_crtc *crtc,
struct drm_crtc_state *new_crtc_state)
@ -10724,6 +10775,8 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state,
struct drm_plane_state *new_cursor_state, *new_underlying_state;
int i;
int cursor_scale_w, cursor_scale_h, underlying_scale_w, underlying_scale_h;
int cursor_src_w, cursor_src_h;
int underlying_src_w, underlying_src_h;
/* On DCE and DCN there is no dedicated hardware cursor plane. We get a
* cursor per pipe but it's going to inherit the scaling and
@ -10735,10 +10788,9 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state,
return 0;
}
cursor_scale_w = new_cursor_state->crtc_w * 1000 /
(new_cursor_state->src_w >> 16);
cursor_scale_h = new_cursor_state->crtc_h * 1000 /
(new_cursor_state->src_h >> 16);
dm_get_oriented_plane_size(new_cursor_state, &cursor_src_w, &cursor_src_h);
cursor_scale_w = new_cursor_state->crtc_w * 1000 / cursor_src_w;
cursor_scale_h = new_cursor_state->crtc_h * 1000 / cursor_src_h;
for_each_new_plane_in_state_reverse(state, underlying, new_underlying_state, i) {
/* Narrow down to non-cursor planes on the same CRTC as the cursor */
@ -10749,10 +10801,10 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state,
if (!new_underlying_state->fb)
continue;
underlying_scale_w = new_underlying_state->crtc_w * 1000 /
(new_underlying_state->src_w >> 16);
underlying_scale_h = new_underlying_state->crtc_h * 1000 /
(new_underlying_state->src_h >> 16);
dm_get_oriented_plane_size(new_underlying_state,
&underlying_src_w, &underlying_src_h);
underlying_scale_w = new_underlying_state->crtc_w * 1000 / underlying_src_w;
underlying_scale_h = new_underlying_state->crtc_h * 1000 / underlying_src_h;
if (cursor_scale_w != underlying_scale_w ||
cursor_scale_h != underlying_scale_h) {
@ -11271,7 +11323,7 @@ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header);
input->offset = offset;
input->length = length;
input->total_length = total_length;
input->cea_total_length = total_length;
memcpy(input->payload, data, length);
res = dc_dmub_srv_cmd_with_reply_data(dm->dc->ctx->dmub_srv, &cmd);
@ -11578,8 +11630,10 @@ uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address,
return value;
}
int amdgpu_dm_set_dmub_async_sync_status(bool is_cmd_aux, struct dc_context *ctx,
uint8_t status_type, uint32_t *operation_result)
static int amdgpu_dm_set_dmub_async_sync_status(bool is_cmd_aux,
struct dc_context *ctx,
uint8_t status_type,
uint32_t *operation_result)
{
struct amdgpu_device *adev = ctx->driver_context;
int return_status = -1;

View File

@ -50,9 +50,9 @@
#define AMDGPU_DMUB_NOTIFICATION_MAX 5
/**
/*
* DMUB Async to Sync Mechanism Status
**/
*/
#define DMUB_ASYNC_TO_SYNC_ACCESS_FAIL 1
#define DMUB_ASYNC_TO_SYNC_ACCESS_TIMEOUT 2
#define DMUB_ASYNC_TO_SYNC_ACCESS_SUCCESS 3

View File

@ -285,8 +285,12 @@ static int __set_input_tf(struct dc_transfer_func *func,
}
/**
* amdgpu_dm_verify_lut_sizes
* @crtc_state: the DRM CRTC state
*
* Verifies that the Degamma and Gamma LUTs attached to the |crtc_state| are of
* the expected size.
*
* Returns 0 on success.
*/
int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state)

View File

@ -824,6 +824,48 @@ static int dmub_fw_state_show(struct seq_file *m, void *data)
return seq_write(m, state_base, state_size);
}
/* psr_capability_show() - show eDP panel PSR capability
*
* The read function: sink_psr_capability_show
* Shows if sink has PSR capability or not.
* If yes - the PSR version is appended
*
* cat /sys/kernel/debug/dri/0/eDP-X/psr_capability
*
* Expected output:
* "Sink support: no\n" - if panel doesn't support PSR
* "Sink support: yes [0x01]\n" - if panel supports PSR1
* "Driver support: no\n" - if driver doesn't support PSR
* "Driver support: yes [0x01]\n" - if driver supports PSR1
*/
static int psr_capability_show(struct seq_file *m, void *data)
{
struct drm_connector *connector = m->private;
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
struct dc_link *link = aconnector->dc_link;
if (!link)
return -ENODEV;
if (link->type == dc_connection_none)
return -ENODEV;
if (!(link->connector_signal & SIGNAL_TYPE_EDP))
return -ENODEV;
seq_printf(m, "Sink support: %s", yesno(link->dpcd_caps.psr_caps.psr_version != 0));
if (link->dpcd_caps.psr_caps.psr_version)
seq_printf(m, " [0x%02x]", link->dpcd_caps.psr_caps.psr_version);
seq_puts(m, "\n");
seq_printf(m, "Driver support: %s", yesno(link->psr_settings.psr_feature_enabled));
if (link->psr_settings.psr_version)
seq_printf(m, " [0x%02x]", link->psr_settings.psr_version);
seq_puts(m, "\n");
return 0;
}
/*
* Returns the current and maximum output bpc for the connector.
* Example usage: cat /sys/kernel/debug/dri/0/DP-1/output_bpc
@ -2467,6 +2509,7 @@ DEFINE_SHOW_ATTRIBUTE(dp_lttpr_status);
DEFINE_SHOW_ATTRIBUTE(hdcp_sink_capability);
#endif
DEFINE_SHOW_ATTRIBUTE(internal_display);
DEFINE_SHOW_ATTRIBUTE(psr_capability);
static const struct file_operations dp_dsc_clock_en_debugfs_fops = {
.owner = THIS_MODULE,
@ -2712,6 +2755,138 @@ static const struct {
{"internal_display", &internal_display_fops}
};
/*
* Returns supported customized link rates by this eDP panel.
* Example usage: cat /sys/kernel/debug/dri/0/eDP-x/ilr_setting
*/
static int edp_ilr_show(struct seq_file *m, void *unused)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(m->private);
struct dc_link *link = aconnector->dc_link;
uint8_t supported_link_rates[16];
uint32_t link_rate_in_khz;
uint32_t entry = 0;
uint8_t dpcd_rev;
memset(supported_link_rates, 0, sizeof(supported_link_rates));
dm_helpers_dp_read_dpcd(link->ctx, link, DP_SUPPORTED_LINK_RATES,
supported_link_rates, sizeof(supported_link_rates));
dpcd_rev = link->dpcd_caps.dpcd_rev.raw;
if (dpcd_rev >= DP_DPCD_REV_13 &&
(supported_link_rates[entry+1] != 0 || supported_link_rates[entry] != 0)) {
for (entry = 0; entry < 16; entry += 2) {
link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 +
supported_link_rates[entry]) * 200;
seq_printf(m, "[%d] %d kHz\n", entry/2, link_rate_in_khz);
}
} else {
seq_printf(m, "ILR is not supported by this eDP panel.\n");
}
return 0;
}
/*
* Set supported customized link rate to eDP panel.
*
* echo <lane_count> <link_rate option> > ilr_setting
*
* for example, supported ILR : [0] 1620000 kHz [1] 2160000 kHz [2] 2430000 kHz ...
* echo 4 1 > /sys/kernel/debug/dri/0/eDP-x/ilr_setting
* to set 4 lanes and 2.16 GHz
*/
static ssize_t edp_ilr_write(struct file *f, const char __user *buf,
size_t size, loff_t *pos)
{
struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
struct dc_link *link = connector->dc_link;
struct amdgpu_device *adev = drm_to_adev(connector->base.dev);
struct dc *dc = (struct dc *)link->dc;
struct dc_link_settings prefer_link_settings;
char *wr_buf = NULL;
const uint32_t wr_buf_size = 40;
/* 0: lane_count; 1: link_rate */
int max_param_num = 2;
uint8_t param_nums = 0;
long param[2];
bool valid_input = true;
if (size == 0)
return -EINVAL;
wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL);
if (!wr_buf)
return -ENOMEM;
if (parse_write_buffer_into_params(wr_buf, wr_buf_size,
(long *)param, buf,
max_param_num,
&param_nums)) {
kfree(wr_buf);
return -EINVAL;
}
if (param_nums <= 0) {
kfree(wr_buf);
return -EINVAL;
}
switch (param[0]) {
case LANE_COUNT_ONE:
case LANE_COUNT_TWO:
case LANE_COUNT_FOUR:
break;
default:
valid_input = false;
break;
}
if (param[1] >= link->dpcd_caps.edp_supported_link_rates_count)
valid_input = false;
if (!valid_input) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("Invalid Input value. No HW will be programmed\n");
prefer_link_settings.use_link_rate_set = false;
dc_link_set_preferred_training_settings(dc, NULL, NULL, link, true);
return size;
}
/* save user force lane_count, link_rate to preferred settings
* spread spectrum will not be changed
*/
prefer_link_settings.link_spread = link->cur_link_settings.link_spread;
prefer_link_settings.lane_count = param[0];
prefer_link_settings.use_link_rate_set = true;
prefer_link_settings.link_rate_set = param[1];
prefer_link_settings.link_rate = link->dpcd_caps.edp_supported_link_rates[param[1]];
mutex_lock(&adev->dm.dc_lock);
dc_link_set_preferred_training_settings(dc, &prefer_link_settings,
NULL, link, false);
mutex_unlock(&adev->dm.dc_lock);
kfree(wr_buf);
return size;
}
static int edp_ilr_open(struct inode *inode, struct file *file)
{
return single_open(file, edp_ilr_show, inode->i_private);
}
static const struct file_operations edp_ilr_debugfs_fops = {
.owner = THIS_MODULE,
.open = edp_ilr_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = edp_ilr_write
};
void connector_debugfs_init(struct amdgpu_dm_connector *connector)
{
int i;
@ -2726,11 +2901,14 @@ void connector_debugfs_init(struct amdgpu_dm_connector *connector)
}
}
if (connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) {
debugfs_create_file_unsafe("psr_capability", 0444, dir, connector, &psr_capability_fops);
debugfs_create_file_unsafe("psr_state", 0444, dir, connector, &psr_fops);
debugfs_create_file("amdgpu_current_backlight_pwm", 0444, dir, connector,
&current_backlight_fops);
debugfs_create_file("amdgpu_target_backlight_pwm", 0444, dir, connector,
&target_backlight_fops);
debugfs_create_file("ilr_setting", 0644, dir, connector,
&edp_ilr_debugfs_fops);
}
for (i = 0; i < ARRAY_SIZE(connector_debugfs_entries); i++) {
@ -2909,10 +3087,13 @@ static int crc_win_update_set(void *data, u64 val)
struct amdgpu_device *adev = drm_to_adev(new_crtc->dev);
struct crc_rd_work *crc_rd_wrk = adev->dm.crc_rd_wrk;
if (!crc_rd_wrk)
return 0;
if (val) {
spin_lock_irq(&adev_to_drm(adev)->event_lock);
spin_lock_irq(&crc_rd_wrk->crc_rd_work_lock);
if (crc_rd_wrk && crc_rd_wrk->crtc) {
if (crc_rd_wrk->crtc) {
old_crtc = crc_rd_wrk->crtc;
old_acrtc = to_amdgpu_crtc(old_crtc);
}
@ -3190,6 +3371,32 @@ static int disable_hpd_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(disable_hpd_ops, disable_hpd_get,
disable_hpd_set, "%llu\n");
#if defined(CONFIG_DRM_AMD_DC_DCN)
/*
* Temporary w/a to force sst sequence in M42D DP2 mst receiver
* Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dp_set_mst_en_for_sst
*/
static int dp_force_sst_set(void *data, u64 val)
{
struct amdgpu_device *adev = data;
adev->dm.dc->debug.set_mst_en_for_sst = val;
return 0;
}
static int dp_force_sst_get(void *data, u64 *val)
{
struct amdgpu_device *adev = data;
*val = adev->dm.dc->debug.set_mst_en_for_sst;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(dp_set_mst_en_for_sst_ops, dp_force_sst_get,
dp_force_sst_set, "%llu\n");
#endif
/*
* Sets the DC visual confirm debug option from the given string.
* Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_visual_confirm
@ -3299,6 +3506,10 @@ void dtn_debugfs_init(struct amdgpu_device *adev)
adev, &mst_topo_fops);
debugfs_create_file("amdgpu_dm_dtn_log", 0644, root, adev,
&dtn_log_fops);
#if defined(CONFIG_DRM_AMD_DC_DCN)
debugfs_create_file("amdgpu_dm_dp_set_mst_en_for_sst", 0644, root, adev,
&dp_set_mst_en_for_sst_ops);
#endif
debugfs_create_file_unsafe("amdgpu_dm_visual_confirm", 0644, root, adev,
&visual_confirm_fops);

View File

@ -83,16 +83,17 @@ static int amdgpu_dm_patch_edid_caps(struct dc_edid_caps *edid_caps)
* void
* */
enum dc_edid_status dm_helpers_parse_edid_caps(
struct dc_context *ctx,
struct dc_link *link,
const struct dc_edid *edid,
struct dc_edid_caps *edid_caps)
{
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_connector *connector = &aconnector->base;
struct edid *edid_buf = (struct edid *) edid->raw_edid;
struct cea_sad *sads;
int sad_count = -1;
int sadb_count = -1;
int i = 0;
int j = 0;
uint8_t *sadb = NULL;
enum dc_edid_status result = EDID_OK;
@ -111,23 +112,11 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->manufacture_week = edid_buf->mfg_week;
edid_caps->manufacture_year = edid_buf->mfg_year;
/* One of the four detailed_timings stores the monitor name. It's
* stored in an array of length 13. */
for (i = 0; i < 4; i++) {
if (edid_buf->detailed_timings[i].data.other_data.type == 0xfc) {
while (j < 13 && edid_buf->detailed_timings[i].data.other_data.data.str.str[j]) {
if (edid_buf->detailed_timings[i].data.other_data.data.str.str[j] == '\n')
break;
drm_edid_get_monitor_name(edid_buf,
edid_caps->display_name,
AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
edid_caps->display_name[j] =
edid_buf->detailed_timings[i].data.other_data.data.str.str[j];
j++;
}
}
}
edid_caps->edid_hdmi = drm_detect_hdmi_monitor(
(struct edid *) edid->raw_edid);
edid_caps->edid_hdmi = connector->display_info.is_hdmi;
sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
if (sad_count <= 0)
@ -585,8 +574,17 @@ bool dm_helpers_dp_write_dsc_enable(
}
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT || stream->signal == SIGNAL_TYPE_EDP) {
#if defined(CONFIG_DRM_AMD_DC_DCN)
if (stream->sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) {
#endif
ret = dm_helpers_dp_write_dpcd(ctx, stream->link, DP_DSC_ENABLE, &enable_dsc, 1);
DC_LOG_DC("Send DSC %s to sst display\n", enable_dsc ? "enable" : "disable");
DC_LOG_DC("Send DSC %s to SST RX\n", enable_dsc ? "enable" : "disable");
#if defined(CONFIG_DRM_AMD_DC_DCN)
} else if (stream->sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
ret = dm_helpers_dp_write_dpcd(ctx, stream->link, DP_DSC_ENABLE, &enable_dsc, 1);
DC_LOG_DC("Send DSC %s to DP-HDMI PCON\n", enable_dsc ? "enable" : "disable");
}
#endif
}
return (ret > 0);
@ -650,14 +648,8 @@ enum dc_edid_status dm_helpers_read_local_edid(
/* We don't need the original edid anymore */
kfree(edid);
/* connector->display_info will be parsed from EDID and saved
* into drm_connector->display_info from edid by call stack
* below:
* drm_parse_ycbcr420_deep_color_info
* drm_parse_hdmi_forum_vsdb
* drm_parse_cea_ext
* drm_add_display_info
* drm_connector_update_edid_property
/* connector->display_info is parsed from EDID and saved
* into drm_connector->display_info
*
* drm_connector->display_info will be used by amdgpu_dm funcs,
* like fill_stream_properties_from_drm_display_mode
@ -665,7 +657,7 @@ enum dc_edid_status dm_helpers_read_local_edid(
amdgpu_dm_update_connector_after_detect(aconnector);
edid_status = dm_helpers_parse_edid_caps(
ctx,
link,
&sink->dc_edid,
&sink->edid_caps);

View File

@ -26,6 +26,73 @@
#include "amdgpu_dm_psr.h"
#include "dc.h"
#include "dm_helpers.h"
#include "amdgpu_dm.h"
static bool link_get_psr_caps(struct dc_link *link)
{
uint8_t psr_dpcd_data[EDP_PSR_RECEIVER_CAP_SIZE];
uint8_t edp_rev_dpcd_data;
if (!dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT,
psr_dpcd_data, sizeof(psr_dpcd_data)))
return false;
if (!dm_helpers_dp_read_dpcd(NULL, link, DP_EDP_DPCD_REV,
&edp_rev_dpcd_data, sizeof(edp_rev_dpcd_data)))
return false;
link->dpcd_caps.psr_caps.psr_version = psr_dpcd_data[0];
link->dpcd_caps.psr_caps.edp_revision = edp_rev_dpcd_data;
#ifdef CONFIG_DRM_AMD_DC_DCN
if (link->dpcd_caps.psr_caps.psr_version > 0x1) {
uint8_t alpm_dpcd_data;
uint8_t su_granularity_dpcd_data;
if (!dm_helpers_dp_read_dpcd(NULL, link, DP_RECEIVER_ALPM_CAP,
&alpm_dpcd_data, sizeof(alpm_dpcd_data)))
return false;
if (!dm_helpers_dp_read_dpcd(NULL, link, DP_PSR2_SU_Y_GRANULARITY,
&su_granularity_dpcd_data, sizeof(su_granularity_dpcd_data)))
return false;
link->dpcd_caps.psr_caps.y_coordinate_required = psr_dpcd_data[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED;
link->dpcd_caps.psr_caps.su_granularity_required = psr_dpcd_data[1] & DP_PSR2_SU_GRANULARITY_REQUIRED;
link->dpcd_caps.psr_caps.alpm_cap = alpm_dpcd_data & DP_ALPM_CAP;
link->dpcd_caps.psr_caps.standby_support = alpm_dpcd_data & (1 << 1);
link->dpcd_caps.psr_caps.su_y_granularity = su_granularity_dpcd_data;
}
#endif
return true;
}
#ifdef CONFIG_DRM_AMD_DC_DCN
static bool link_supports_psrsu(struct dc_link *link)
{
struct dc *dc = link->ctx->dc;
if (!dc->caps.dmcub_support)
return false;
if (dc->ctx->dce_version < DCN_VERSION_3_1)
return false;
if (!link->dpcd_caps.psr_caps.alpm_cap ||
!link->dpcd_caps.psr_caps.y_coordinate_required)
return false;
if (link->dpcd_caps.psr_caps.su_granularity_required &&
!link->dpcd_caps.psr_caps.su_y_granularity)
return false;
return true;
}
#endif
/*
* amdgpu_dm_set_psr_caps() - set link psr capabilities
@ -34,26 +101,34 @@
*/
void amdgpu_dm_set_psr_caps(struct dc_link *link)
{
uint8_t dpcd_data[EDP_PSR_RECEIVER_CAP_SIZE];
if (!(link->connector_signal & SIGNAL_TYPE_EDP))
return;
if (link->type == dc_connection_none)
return;
if (dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT,
dpcd_data, sizeof(dpcd_data))) {
link->dpcd_caps.psr_caps.psr_version = dpcd_data[0];
if (dpcd_data[0] == 0) {
if (!link_get_psr_caps(link)) {
DRM_ERROR("amdgpu: Failed to read PSR Caps!\n");
return;
}
if (link->dpcd_caps.psr_caps.psr_version == 0) {
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
link->psr_settings.psr_feature_enabled = false;
} else {
#ifdef CONFIG_DRM_AMD_DC_DCN
if (link_supports_psrsu(link))
link->psr_settings.psr_version = DC_PSR_VERSION_SU_1;
else
#endif
link->psr_settings.psr_version = DC_PSR_VERSION_1;
link->psr_settings.psr_feature_enabled = true;
}
DRM_INFO("PSR support:%d\n", link->psr_settings.psr_feature_enabled);
}
}
/*

View File

@ -739,7 +739,9 @@ static void hack_bounding_box(struct dcn_bw_internal_vars *v,
hack_force_pipe_split(v, context->streams[0]->timing.pix_clk_100hz);
}
unsigned int get_highest_allowed_voltage_level(uint32_t chip_family, uint32_t hw_internal_rev, uint32_t pci_revision_id)
static unsigned int get_highest_allowed_voltage_level(uint32_t chip_family,
uint32_t hw_internal_rev,
uint32_t pci_revision_id)
{
/* for low power RV2 variants, the highest voltage level we want is 0 */
if ((chip_family == FAMILY_RV) &&

View File

@ -34,7 +34,7 @@
#include "rv1_clk_mgr_vbios_smu.h"
#include "rv1_clk_mgr_clk.h"
void rv1_init_clocks(struct clk_mgr *clk_mgr)
static void rv1_init_clocks(struct clk_mgr *clk_mgr)
{
memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
}

View File

@ -28,6 +28,8 @@
#include "reg_helper.h"
#include <linux/delay.h>
#include "rv1_clk_mgr_vbios_smu.h"
#define MAX_INSTANCE 5
#define MAX_SEGMENT 5

View File

@ -409,7 +409,7 @@ void dcn2_init_clocks(struct clk_mgr *clk_mgr)
clk_mgr->clks.prev_p_state_change_support = true;
}
void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base)
static void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
struct pp_smu_funcs_nv *pp_smu = NULL;

View File

@ -74,42 +74,6 @@ static const struct clk_mgr_mask clk_mgr_mask = {
CLK_COMMON_MASK_SH_LIST_DCN201_BASE(_MASK)
};
void dcn201_update_clocks_vbios(struct clk_mgr *clk_mgr,
struct dc_state *context,
bool safe_to_lower)
{
struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
bool update_dppclk = false;
bool update_dispclk = false;
if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz)) {
clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz;
update_dppclk = true;
}
if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)) {
clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz;
update_dispclk = true;
}
if (update_dppclk || update_dispclk) {
struct bp_set_dce_clock_parameters dce_clk_params;
struct dc_bios *bp = clk_mgr->ctx->dc_bios;
if (update_dispclk) {
memset(&dce_clk_params, 0, sizeof(dce_clk_params));
dce_clk_params.target_clock_frequency = new_clocks->dispclk_khz;
dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
bp->funcs->set_dce_clock(bp, &dce_clk_params);
}
/* currently there is no DCECLOCK_TYPE_DPPCLK type defined in VBIOS interface.
* vbios program DPPCLK to the same DispCLK limitation
*/
}
}
static void dcn201_init_clocks(struct clk_mgr *clk_mgr)
{
memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
@ -126,10 +90,8 @@ static void dcn201_update_clocks(struct clk_mgr *clk_mgr_base,
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
struct dc *dc = clk_mgr_base->ctx->dc;
int display_count;
bool update_dppclk = false;
bool update_dispclk = false;
bool enter_display_off = false;
bool dpp_clock_lowered = false;
bool force_reset = false;
bool p_state_change_support;
@ -145,10 +107,7 @@ static void dcn201_update_clocks(struct clk_mgr *clk_mgr_base,
dcn2_read_clocks_from_hw_dentist(clk_mgr_base);
}
display_count = clk_mgr_helper_get_active_display_cnt(dc, context);
if (display_count == 0)
enter_display_off = true;
clk_mgr_helper_get_active_display_cnt(dc, context);
if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz))
clk_mgr_base->clks.phyclk_khz = new_clocks->phyclk_khz;

View File

@ -56,9 +56,7 @@
/* TODO: evaluate how to lower or disable all dcn clocks in screen off case */
int rn_get_active_display_cnt_wa(
struct dc *dc,
struct dc_state *context)
static int rn_get_active_display_cnt_wa(struct dc *dc, struct dc_state *context)
{
int i, display_count;
bool tmds_present = false;
@ -77,7 +75,8 @@ int rn_get_active_display_cnt_wa(
const struct dc_link *link = dc->links[i];
/* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
if (link->link_enc->funcs->is_dig_enabled(link->link_enc))
if (link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc))
display_count++;
}
@ -88,7 +87,7 @@ int rn_get_active_display_cnt_wa(
return display_count;
}
void rn_set_low_power_state(struct clk_mgr *clk_mgr_base)
static void rn_set_low_power_state(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
@ -122,7 +121,7 @@ static void rn_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
}
void rn_update_clocks(struct clk_mgr *clk_mgr_base,
static void rn_update_clocks(struct clk_mgr *clk_mgr_base,
struct dc_state *context,
bool safe_to_lower)
{
@ -437,25 +436,14 @@ static void rn_dump_clk_registers(struct clk_state_registers_and_bypass *regs_an
}
}
/* This function produce translated logical clk state values*/
void rn_get_clk_states(struct clk_mgr *clk_mgr_base, struct clk_states *s)
{
struct clk_state_registers_and_bypass sb = { 0 };
struct clk_log_info log_info = { 0 };
rn_dump_clk_registers(&sb, clk_mgr_base, &log_info);
s->dprefclk_khz = sb.dprefclk * 1000;
}
void rn_enable_pme_wa(struct clk_mgr *clk_mgr_base)
static void rn_enable_pme_wa(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
rn_vbios_smu_enable_pme_wa(clk_mgr);
}
void rn_init_clocks(struct clk_mgr *clk_mgr)
static void rn_init_clocks(struct clk_mgr *clk_mgr)
{
memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
// Assumption is that boot state always supports pstate

View File

@ -33,6 +33,8 @@
#include "mp/mp_12_0_0_offset.h"
#include "mp/mp_12_0_0_sh_mask.h"
#include "rn_clk_mgr_vbios_smu.h"
#define REG(reg_name) \
(MP0_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name)
@ -86,7 +88,9 @@ static uint32_t rn_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsig
}
int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param)
static int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
unsigned int msg_id,
unsigned int param)
{
uint32_t result;

View File

@ -252,6 +252,7 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base,
bool update_dispclk = false;
bool enter_display_off = false;
bool dpp_clock_lowered = false;
bool update_pstate_unsupported_clk = false;
struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
bool force_reset = false;
bool update_uclk = false;
@ -299,14 +300,29 @@ static void dcn3_update_clocks(struct clk_mgr *clk_mgr_base,
clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support;
total_plane_count = clk_mgr_helper_get_active_plane_cnt(dc, context);
p_state_change_support = new_clocks->p_state_change_support || (total_plane_count == 0);
if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support)) {
// invalidate the current P-State forced min in certain dc_mode_softmax situations
if (dc->clk_mgr->dc_mode_softmax_enabled && safe_to_lower && !p_state_change_support) {
if ((new_clocks->dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) !=
(clk_mgr_base->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000))
update_pstate_unsupported_clk = true;
}
if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support) ||
update_pstate_unsupported_clk) {
clk_mgr_base->clks.p_state_change_support = p_state_change_support;
/* to disable P-State switching, set UCLK min = max */
if (!clk_mgr_base->clks.p_state_change_support)
if (!clk_mgr_base->clks.p_state_change_support) {
if (dc->clk_mgr->dc_mode_softmax_enabled &&
new_clocks->dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
else
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
}
}
/* Always update saved value, even if new value not set due to P-State switching unsupported */
if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) {
@ -421,6 +437,24 @@ static void dcn3_set_hard_max_memclk(struct clk_mgr *clk_mgr_base)
clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
}
static void dcn3_set_max_memclk(struct clk_mgr *clk_mgr_base, unsigned int memclk_mhz)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
if (!clk_mgr->smu_present)
return;
dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, memclk_mhz);
}
static void dcn3_set_min_memclk(struct clk_mgr *clk_mgr_base, unsigned int memclk_mhz)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
if (!clk_mgr->smu_present)
return;
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, memclk_mhz);
}
/* Get current memclk states, update bounding box */
static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
{
@ -436,6 +470,8 @@ static void dcn3_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base)
&num_levels);
clk_mgr_base->bw_params->clk_table.num_entries = num_levels ? num_levels : 1;
clk_mgr_base->bw_params->dc_mode_softmax_memclk = dcn30_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK);
/* Refresh bounding box */
clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box(
clk_mgr->base.ctx->dc, clk_mgr_base->bw_params);
@ -505,6 +541,8 @@ static struct clk_mgr_funcs dcn3_funcs = {
.notify_wm_ranges = dcn3_notify_wm_ranges,
.set_hard_min_memclk = dcn3_set_hard_min_memclk,
.set_hard_max_memclk = dcn3_set_hard_max_memclk,
.set_max_memclk = dcn3_set_max_memclk,
.set_min_memclk = dcn3_set_min_memclk,
.get_memclk_states_from_smu = dcn3_get_memclk_states_from_smu,
.are_clock_states_equal = dcn3_are_clock_states_equal,
.enable_pme_wa = dcn3_enable_pme_wa,

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