mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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:
commit
b06103b532
@ -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
|
@ -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
|
87
Documentation/gpu/amdgpu/amdgpu-glossary.rst
Normal file
87
Documentation/gpu/amdgpu/amdgpu-glossary.rst
Normal 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
|
414
Documentation/gpu/amdgpu/display/config_example.svg
Normal file
414
Documentation/gpu/amdgpu/display/config_example.svg
Normal 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 |
77
Documentation/gpu/amdgpu/display/dc-debug.rst
Normal file
77
Documentation/gpu/amdgpu/display/dc-debug.rst
Normal 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.
|
237
Documentation/gpu/amdgpu/display/dc-glossary.rst
Normal file
237
Documentation/gpu/amdgpu/display/dc-glossary.rst
Normal 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
|
1125
Documentation/gpu/amdgpu/display/dc_pipeline_overview.svg
Normal file
1125
Documentation/gpu/amdgpu/display/dc_pipeline_overview.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 54 KiB |
171
Documentation/gpu/amdgpu/display/dcn-overview.rst
Normal file
171
Documentation/gpu/amdgpu/display/dcn-overview.rst
Normal 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
|
42
Documentation/gpu/amdgpu/display/display-manager.rst
Normal file
42
Documentation/gpu/amdgpu/display/display-manager.rst
Normal 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
|
485
Documentation/gpu/amdgpu/display/global_sync_vblank.svg
Normal file
485
Documentation/gpu/amdgpu/display/global_sync_vblank.svg
Normal 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 |
31
Documentation/gpu/amdgpu/display/index.rst
Normal file
31
Documentation/gpu/amdgpu/display/index.rst
Normal 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
|
182
Documentation/gpu/amdgpu/driver-core.rst
Normal file
182
Documentation/gpu/amdgpu/driver-core.rst
Normal 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
|
112
Documentation/gpu/amdgpu/driver-misc.rst
Normal file
112
Documentation/gpu/amdgpu/driver-misc.rst
Normal 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
|
17
Documentation/gpu/amdgpu/index.rst
Normal file
17
Documentation/gpu/amdgpu/index.rst
Normal 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
|
7
Documentation/gpu/amdgpu/module-parameters.rst
Normal file
7
Documentation/gpu/amdgpu/module-parameters.rst
Normal 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
|
62
Documentation/gpu/amdgpu/ras.rst
Normal file
62
Documentation/gpu/amdgpu/ras.rst
Normal 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.
|
65
Documentation/gpu/amdgpu/thermal.rst
Normal file
65
Documentation/gpu/amdgpu/thermal.rst
Normal 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
|
5
Documentation/gpu/amdgpu/xgmi.rst
Normal file
5
Documentation/gpu/amdgpu/xgmi.rst
Normal file
@ -0,0 +1,5 @@
|
||||
=====================
|
||||
AMDGPU XGMI Support
|
||||
=====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c
|
@ -4,8 +4,7 @@ GPU Driver Documentation
|
||||
|
||||
.. toctree::
|
||||
|
||||
amdgpu
|
||||
amdgpu-dc
|
||||
amdgpu/index
|
||||
i915
|
||||
mcde
|
||||
meson
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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):
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
¶m_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,
|
||||
¤t_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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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) &&
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user