drm for 5.19-rc1
dma-buf:
- add dma_resv_replace_fences
- add dma_resv_get_singleton
- make dma_excl_fence private
core:
- EDID parser refactorings
- switch drivers to drm_mode_copy/duplicate
- DRM managed mutex initialization
display-helper:
- put HDMI, SCDC, HDCP, DSC and DP into new module
gem:
- rework fence handling
ttm:
- rework bulk move handling
- add common debugfs for resource managers
- convert to kvcalloc
format helpers:
- support monochrome formats
- RGB888, RGB565 to XRGB8888 conversions
fbdev:
- cfb/sys_imageblit fixes
- pagelist corruption fix
- create offb platform device
- deferred io improvements
sysfb:
- Kconfig rework
- support for VESA mode selection
bridge:
- conversions to devm_drm_of_get_bridge
- conversions to panel_bridge
- analogix_dp - autosuspend support
- it66121 - audio support
- tc358767 - DSI to DPI support
- icn6211 - PLL/I2C fixes, DT property
- adv7611 - enable DRM_BRIDGE_OP_HPD
- anx7625 - fill ELD if no monitor
- dw_hdmi - add audio support
- lontium LT9211 support, i.MXMP LDB
- it6505: Kconfig fix, DPCD set power fix
- adv7511 - CEC support for ADV7535
panel:
- ltk035c5444t, B133UAN01, NV3052C panel support
- DataImage FG040346DSSWBG04 support
- st7735r - DT bindings fix
- ssd130x - fixes
i915:
- DG2 laptop PCI-IDs ("motherboard down")
- Initial RPL-P PCI IDs
- compute engine ABI
- DG2 Tile4 support
- DG2 CCS clear color compression support
- DG2 render/media compression formats support
- ATS-M platform info
- RPL-S PCI IDs added
- Bump ADL-P DMC version to v2.16
- Support static DRRS
- Support multiple eDP/LVDS native mode refresh rates
- DP HDR support for HSW+
- Lots of display refactoring + fixes
- GuC hwconfig support and query
- sysfs support for multi-tile
- fdinfo per-client gpu utilisation
- add geometry subslices query
- fix prime mmap with LMEM
- fix vm open count and remove vma refcounts
- contiguous allocation fixes
- steered register write support
- small PCI BAR enablement
- GuC error capture support
- sunset igpu legacy mmap support for newer devices
- GuC version 70.1.1 support
amdgpu:
- Initial SoC21 support
- SMU 13.x enablement
- SMU 13.0.4 support
- ttm_eu cleanups
- USB-C, GPUVM updates
- TMZ fixes for RV
- RAS support for VCN
- PM sysfs code cleanup
- DC FP rework
- extend CG/PG flags to 64-bit
- SI dpm lockdep fix
- runtime PM fixes
amdkfd:
- RAS/SVM fixes
- TLB flush fixes
- CRIU GWS support
- ignore bogus MEC signals more efficiently
msm:
- Fourcc modifier for tiled but not compressed layouts
- Support for userspace allocated IOVA (GPU virtual address)
- DPU: DSC (Display Stream Compression) support
- DP: eDP support
- DP: conversion to use drm_bridge and drm_bridge_connector
- Merge DPU1 and MDP5 MDSS driver
- DPU: writeback support
nouveau:
- make some structures static
- make some variables static
- switch to drm_gem_plane_helper_prepare_fb
radeon:
- misc fixes/cleanups
mxsfb:
- rework crtc mode setting
- LCDIF CRC support
etnaviv:
- fencing improvements
- fix address space collisions
- cleanup MMU reference handling
gma500:
- GEM/GTT improvements
- connector handling fixes
komeda:
- switch to plane reset helper
mediatek:
- MIPI DSI improvements
omapdrm:
- GEM improvements
qxl:
- aarch64 support
vc4:
- add a CL submission tracepoint
- HDMI YUV support
- HDMI/clock improvements
- drop is_hdmi caching
virtio:
- remove restriction of non-zero blob types
vmwgfx:
- support for cursormob and cursorbypass 4
- fence improvements
tidss:
- reset DISPC on startup
solomon:
- SPI support
- DT improvements
sun4i:
- allwinner D1 support
- drop is_hdmi caching
imx:
- use swap() instead of open-coding
- use devm_platform_ioremap_resource
- remove redunant initializations
ast:
- Displayport support
rockchip:
- Refactor IOMMU initialisation
- make some structures static
- replace drm_detect_hdmi_monitor with drm_display_info.is_hdmi
- support swapped YUV formats,
- clock improvements
- rk3568 support
- VOP2 support
mediatek:
- MT8186 support
tegra:
- debugabillity improvements
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmKNxkAACgkQDHTzWXnE
hr4hghAAqSXeMEw1w34miyM28hcOpXqkDfT1VVooqFxBT8MBqamzpZvCH94qsZwm
3DRXlhQ4pk8wzUcWJpGprdNakxNQPpFVs2UuxYxOyrxYpdkbOwqsEcM3d8VXD9Cy
E36z+dr85A8Te/J0Yg/FLoZMHulTlidqEZeOz6SMaNUohtrmH/oPWR+cPIy4/Zpp
yysfbBSKTwblJFDf4+nIpks/VvJYAUO3i6KClT/Rh79Yg6de582AU0YaNcEArTi6
JqdiYIoYLx609Ecy5NVme6wR/ai46afFLMYt3ZIP4OfHRINk+YL01BYMo2JE2M8l
xjOH0Iwb7evzWqLK/ESwqp3P7nyppmLlfbZOFHWUfNJsjq2H3ePaAGhzOlYx1c70
XENzY4IvpYYdR0pJuh1gw1cNZfM9JDAynGJ5jvsATLGBGQbpFsy3w/PMZT17q8an
DpBwqQmShUdCJ2m+6zznC3VsxJpbvWKNE1I93NxAWZXmFYxoHCzRihahUxKcNDrQ
ZLH7RSlk9SE/ZtNSLkU15YnKtoW+ThFIssUpVio6U/fZot1+efZkmkXplSuFvj6R
i7s14hMWQjSJzpJg1DXfhDMycEOujNiQppCG2EaDlVxvUtCqYBd3EHOI7KQON//+
iVtmEEnWh5rcCM+WsxLGf3Y7sVP3vfo1LOCxshb1XVfDmeMksoI=
=BYQA
-----END PGP SIGNATURE-----
Merge tag 'drm-next-2022-05-25' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"Intel have enabled DG2 on certain SKUs for laptops, AMD has started
some new GPU support, msm has user allocated VA controls
dma-buf:
- add dma_resv_replace_fences
- add dma_resv_get_singleton
- make dma_excl_fence private
core:
- EDID parser refactorings
- switch drivers to drm_mode_copy/duplicate
- DRM managed mutex initialization
display-helper:
- put HDMI, SCDC, HDCP, DSC and DP into new module
gem:
- rework fence handling
ttm:
- rework bulk move handling
- add common debugfs for resource managers
- convert to kvcalloc
format helpers:
- support monochrome formats
- RGB888, RGB565 to XRGB8888 conversions
fbdev:
- cfb/sys_imageblit fixes
- pagelist corruption fix
- create offb platform device
- deferred io improvements
sysfb:
- Kconfig rework
- support for VESA mode selection
bridge:
- conversions to devm_drm_of_get_bridge
- conversions to panel_bridge
- analogix_dp - autosuspend support
- it66121 - audio support
- tc358767 - DSI to DPI support
- icn6211 - PLL/I2C fixes, DT property
- adv7611 - enable DRM_BRIDGE_OP_HPD
- anx7625 - fill ELD if no monitor
- dw_hdmi - add audio support
- lontium LT9211 support, i.MXMP LDB
- it6505: Kconfig fix, DPCD set power fix
- adv7511 - CEC support for ADV7535
panel:
- ltk035c5444t, B133UAN01, NV3052C panel support
- DataImage FG040346DSSWBG04 support
- st7735r - DT bindings fix
- ssd130x - fixes
i915:
- DG2 laptop PCI-IDs ("motherboard down")
- Initial RPL-P PCI IDs
- compute engine ABI
- DG2 Tile4 support
- DG2 CCS clear color compression support
- DG2 render/media compression formats support
- ATS-M platform info
- RPL-S PCI IDs added
- Bump ADL-P DMC version to v2.16
- Support static DRRS
- Support multiple eDP/LVDS native mode refresh rates
- DP HDR support for HSW+
- Lots of display refactoring + fixes
- GuC hwconfig support and query
- sysfs support for multi-tile
- fdinfo per-client gpu utilisation
- add geometry subslices query
- fix prime mmap with LMEM
- fix vm open count and remove vma refcounts
- contiguous allocation fixes
- steered register write support
- small PCI BAR enablement
- GuC error capture support
- sunset igpu legacy mmap support for newer devices
- GuC version 70.1.1 support
amdgpu:
- Initial SoC21 support
- SMU 13.x enablement
- SMU 13.0.4 support
- ttm_eu cleanups
- USB-C, GPUVM updates
- TMZ fixes for RV
- RAS support for VCN
- PM sysfs code cleanup
- DC FP rework
- extend CG/PG flags to 64-bit
- SI dpm lockdep fix
- runtime PM fixes
amdkfd:
- RAS/SVM fixes
- TLB flush fixes
- CRIU GWS support
- ignore bogus MEC signals more efficiently
msm:
- Fourcc modifier for tiled but not compressed layouts
- Support for userspace allocated IOVA (GPU virtual address)
- DPU: DSC (Display Stream Compression) support
- DP: eDP support
- DP: conversion to use drm_bridge and drm_bridge_connector
- Merge DPU1 and MDP5 MDSS driver
- DPU: writeback support
nouveau:
- make some structures static
- make some variables static
- switch to drm_gem_plane_helper_prepare_fb
radeon:
- misc fixes/cleanups
mxsfb:
- rework crtc mode setting
- LCDIF CRC support
etnaviv:
- fencing improvements
- fix address space collisions
- cleanup MMU reference handling
gma500:
- GEM/GTT improvements
- connector handling fixes
komeda:
- switch to plane reset helper
mediatek:
- MIPI DSI improvements
omapdrm:
- GEM improvements
qxl:
- aarch64 support
vc4:
- add a CL submission tracepoint
- HDMI YUV support
- HDMI/clock improvements
- drop is_hdmi caching
virtio:
- remove restriction of non-zero blob types
vmwgfx:
- support for cursormob and cursorbypass 4
- fence improvements
tidss:
- reset DISPC on startup
solomon:
- SPI support
- DT improvements
sun4i:
- allwinner D1 support
- drop is_hdmi caching
imx:
- use swap() instead of open-coding
- use devm_platform_ioremap_resource
- remove redunant initializations
ast:
- Displayport support
rockchip:
- Refactor IOMMU initialisation
- make some structures static
- replace drm_detect_hdmi_monitor with drm_display_info.is_hdmi
- support swapped YUV formats,
- clock improvements
- rk3568 support
- VOP2 support
mediatek:
- MT8186 support
tegra:
- debugabillity improvements"
* tag 'drm-next-2022-05-25' of git://anongit.freedesktop.org/drm/drm: (1740 commits)
drm/i915/dsi: fix VBT send packet port selection for ICL+
drm/i915/uc: Fix undefined behavior due to shift overflowing the constant
drm/i915/reg: fix undefined behavior due to shift overflowing the constant
drm/i915/gt: Fix use of static in macro mismatch
drm/i915/audio: fix audio code enable/disable pipe logging
drm/i915: Fix CFI violation with show_dynamic_id()
drm/i915: Fix 'mixing different enum types' warnings in intel_display_power.c
drm/i915/gt: Fix build error without CONFIG_PM
drm/msm/dpu: handle pm_runtime_get_sync() errors in bind path
drm/msm/dpu: add DRM_MODE_ROTATE_180 back to supported rotations
drm/msm: don't free the IRQ if it was not requested
drm/msm/dpu: limit writeback modes according to max_linewidth
drm/amd: Don't reset dGPUs if the system is going to s2idle
drm/amdgpu: Unmap legacy queue when MES is enabled
drm: msm: fix possible memory leak in mdp5_crtc_cursor_set()
drm/msm: Fix fb plane offset calculation
drm/msm/a6xx: Fix refcount leak in a6xx_gpu_init
drm/msm/dsi: don't powerup at modeset time for parade-ps8640
drm/rockchip: Change register space names in vop2
dt-bindings: display: rockchip: make reg-names mandatory for VOP2
...
This commit is contained in:
commit
2518f226c6
1297 changed files with 495407 additions and 31700 deletions
|
|
@ -62,6 +62,7 @@ properties:
|
|||
- allwinner,sun8i-r40-display-engine
|
||||
- allwinner,sun8i-v3s-display-engine
|
||||
- allwinner,sun9i-a80-display-engine
|
||||
- allwinner,sun20i-d1-display-engine
|
||||
- allwinner,sun50i-a64-display-engine
|
||||
- allwinner,sun50i-h6-display-engine
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ properties:
|
|||
- const: allwinner,sun8i-v3s-tcon
|
||||
- const: allwinner,sun9i-a80-tcon-lcd
|
||||
- const: allwinner,sun9i-a80-tcon-tv
|
||||
- const: allwinner,sun20i-d1-tcon-lcd
|
||||
- const: allwinner,sun20i-d1-tcon-tv
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ properties:
|
|||
- allwinner,sun8i-r40-de2-mixer-0
|
||||
- allwinner,sun8i-r40-de2-mixer-1
|
||||
- allwinner,sun8i-v3s-de2-mixer
|
||||
- allwinner,sun20i-d1-de2-mixer-0
|
||||
- allwinner,sun20i-d1-de2-mixer-1
|
||||
- allwinner,sun50i-a64-de2-mixer-0
|
||||
- allwinner,sun50i-a64-de2-mixer-1
|
||||
- allwinner,sun50i-h6-de3-mixer-0
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- allwinner,sun8i-r40-tcon-top
|
||||
- allwinner,sun20i-d1-tcon-top
|
||||
- allwinner,sun50i-h6-tcon-top
|
||||
|
||||
reg:
|
||||
|
|
@ -48,31 +49,15 @@ properties:
|
|||
|
||||
clocks:
|
||||
minItems: 2
|
||||
items:
|
||||
- description: The TCON TOP interface clock
|
||||
- description: The TCON TOP TV0 clock
|
||||
- description: The TCON TOP TVE0 clock
|
||||
- description: The TCON TOP TV1 clock
|
||||
- description: The TCON TOP TVE1 clock
|
||||
- description: The TCON TOP MIPI DSI clock
|
||||
maxItems: 6
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: bus
|
||||
- const: tcon-tv0
|
||||
- const: tve0
|
||||
- const: tcon-tv1
|
||||
- const: tve1
|
||||
- const: dsi
|
||||
maxItems: 6
|
||||
|
||||
clock-output-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
description: >
|
||||
The first item is the name of the clock created for the TV0
|
||||
channel, the second item is the name of the TCON TV1 channel
|
||||
clock and the third one is the name of the DSI channel clock.
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
|
@ -129,32 +114,92 @@ required:
|
|||
|
||||
additionalProperties: false
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun50i-h6-tcon-top
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun8i-r40-tcon-top
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 2
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: The TCON TOP interface clock
|
||||
- description: The TCON TOP TV0 clock
|
||||
- description: The TCON TOP TVE0 clock
|
||||
- description: The TCON TOP TV1 clock
|
||||
- description: The TCON TOP TVE1 clock
|
||||
- description: The TCON TOP MIPI DSI clock
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: tcon-tv0
|
||||
- const: tve0
|
||||
- const: tcon-tv1
|
||||
- const: tve1
|
||||
- const: dsi
|
||||
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 6
|
||||
clock-output-names:
|
||||
items:
|
||||
- description: TCON TV0 output clock name
|
||||
- description: TCON TV1 output clock name
|
||||
- description: DSI output clock name
|
||||
|
||||
clock-output-names:
|
||||
minItems: 3
|
||||
ports:
|
||||
required:
|
||||
- port@2
|
||||
- port@3
|
||||
|
||||
ports:
|
||||
required:
|
||||
- port@2
|
||||
- port@3
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun20i-d1-tcon-top
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: The TCON TOP interface clock
|
||||
- description: The TCON TOP TV0 clock
|
||||
- description: The TCON TOP TVE0 clock
|
||||
- description: The TCON TOP MIPI DSI clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: tcon-tv0
|
||||
- const: tve0
|
||||
- const: dsi
|
||||
|
||||
clock-output-names:
|
||||
items:
|
||||
- description: TCON TV0 output clock name
|
||||
- description: DSI output clock name
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: allwinner,sun50i-h6-tcon-top
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: The TCON TOP interface clock
|
||||
- description: The TCON TOP TV0 clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bus
|
||||
- const: tcon-tv0
|
||||
|
||||
clock-output-names:
|
||||
items:
|
||||
- description: TCON TV0 output clock name
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
|||
|
|
@ -41,10 +41,26 @@ properties:
|
|||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Video port for MIPI DSI input
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
description: array of physical DSI data lane indexes.
|
||||
minItems: 1
|
||||
items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/fsl,ldb.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale i.MX8MP DPI to LVDS bridge chip
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
|
||||
description: |
|
||||
The i.MX8MP mediamix contains two registers which are responsible
|
||||
for configuring the on-SoC DPI-to-LVDS serializer. This describes
|
||||
those registers as bridge within the DT.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: fsl,imx8mp-ldb
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: ldb
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Video port for DPI input.
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Video port for LVDS Channel-A output (panel or bridge).
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Video port for LVDS Channel-B output (panel or bridge).
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/imx8mp-clock.h>
|
||||
|
||||
blk-ctrl {
|
||||
bridge {
|
||||
compatible = "fsl,imx8mp-ldb";
|
||||
clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
|
||||
clock-names = "ldb";
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
ldb_from_lcdif2: endpoint {
|
||||
remote-endpoint = <&lcdif2_to_ldb>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
ldb_lvds_ch0: endpoint {
|
||||
remote-endpoint = <&ldb_to_lvdsx4panel>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
ldb_lvds_ch1: endpoint {
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -38,6 +38,9 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 0
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/bridge/lontium,lt9211.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Lontium LT9211 DSI/LVDS/DPI to DSI/LVDS/DPI bridge.
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
|
||||
description: |
|
||||
The LT9211 are bridge devices which convert Single/Dual-Link DSI/LVDS
|
||||
or Single DPI to Single/Dual-Link DSI/LVDS or Single DPI.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- lontium,lt9211
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO connected to active high RESET pin.
|
||||
|
||||
vccio-supply:
|
||||
description: Regulator for 1.8V IO power.
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Primary MIPI DSI port-1 for MIPI input or
|
||||
LVDS port-1 for LVDS input or DPI input.
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Additional MIPI port-2 for MIPI input or LVDS port-2
|
||||
for LVDS input. Used in combination with primary
|
||||
port-1 to drive higher resolution displays
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Primary MIPI DSI port-1 for MIPI output or
|
||||
LVDS port-1 for LVDS output or DPI output.
|
||||
|
||||
port@3:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Additional MIPI port-2 for MIPI output or LVDS port-2
|
||||
for LVDS output. Used in combination with primary
|
||||
port-1 to drive higher resolution displays.
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vccio-supply
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hdmi-bridge@3b {
|
||||
compatible = "lontium,lt9211";
|
||||
reg = <0x3b>;
|
||||
|
||||
reset-gpios = <&tlmm 128 GPIO_ACTIVE_HIGH>;
|
||||
interrupts-extended = <&tlmm 84 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
vccio-supply = <<9211_1v8>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&dsi0_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
|
||||
endpoint {
|
||||
remote-endpoint = <&panel_in_lvds>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -53,16 +53,32 @@ properties:
|
|||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description: |
|
||||
DSI input port. The remote endpoint phandle should be a
|
||||
reference to a valid DSI output endpoint node
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
$ref: /schemas/media/video-interfaces.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
data-lanes:
|
||||
description: array of physical DSI data lane indexes.
|
||||
minItems: 1
|
||||
items:
|
||||
- const: 1
|
||||
- const: 2
|
||||
- const: 3
|
||||
- const: 4
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: |
|
||||
DPI input port. The remote endpoint phandle should be a
|
||||
reference to a valid DPI output endpoint node
|
||||
DPI input/output port. The remote endpoint phandle should be a
|
||||
reference to a valid DPI output or input endpoint node.
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
|
|
|
|||
|
|
@ -21,16 +21,19 @@ description: |
|
|||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: mediatek,mt8173-disp-aal
|
||||
- enum:
|
||||
- mediatek,mt8173-disp-aal
|
||||
- mediatek,mt8183-disp-aal
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt2712-disp-aal
|
||||
- mediatek,mt8183-disp-aal
|
||||
- const: mediatek,mt8173-disp-aal
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8186-disp-aal
|
||||
- mediatek,mt8192-disp-aal
|
||||
- mediatek,mt8195-disp-aal
|
||||
- enum:
|
||||
- mediatek,mt8173-disp-aal
|
||||
- const: mediatek,mt8183-disp-aal
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@ properties:
|
|||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8195-disp-ccorr
|
||||
- const: mediatek,mt8192-disp-ccorr
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8192-disp-ccorr
|
||||
- mediatek,mt8186-disp-ccorr
|
||||
- const: mediatek,mt8183-disp-ccorr
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -32,15 +32,14 @@ properties:
|
|||
- enum:
|
||||
- mediatek,mt7623-disp-color
|
||||
- mediatek,mt2712-disp-color
|
||||
- enum:
|
||||
- mediatek,mt2701-disp-color
|
||||
- const: mediatek,mt2701-disp-color
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8183-disp-color
|
||||
- mediatek,mt8186-disp-color
|
||||
- mediatek,mt8192-disp-color
|
||||
- mediatek,mt8195-disp-color
|
||||
- enum:
|
||||
- mediatek,mt8173-disp-color
|
||||
- const: mediatek,mt8173-disp-color
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ properties:
|
|||
- const: mediatek,mt8183-disp-dither
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8186-disp-dither
|
||||
- mediatek,mt8192-disp-dither
|
||||
- mediatek,mt8195-disp-dither
|
||||
- enum:
|
||||
- mediatek,mt8183-disp-dither
|
||||
- const: mediatek,mt8183-disp-dither
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ properties:
|
|||
- mediatek,mt7623-dpi
|
||||
- mediatek,mt8173-dpi
|
||||
- mediatek,mt8183-dpi
|
||||
- mediatek,mt8186-dpi
|
||||
- mediatek,mt8192-dpi
|
||||
|
||||
reg:
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ properties:
|
|||
- const: mediatek,mt8183-disp-gamma
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8186-disp-gamma
|
||||
- mediatek,mt8192-disp-gamma
|
||||
- mediatek,mt8195-disp-gamma
|
||||
- enum:
|
||||
- mediatek,mt8183-disp-gamma
|
||||
- const: mediatek,mt8183-disp-gamma
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -23,21 +23,16 @@ description: |
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: mediatek,mt2701-disp-mutex
|
||||
- items:
|
||||
- const: mediatek,mt2712-disp-mutex
|
||||
- items:
|
||||
- const: mediatek,mt8167-disp-mutex
|
||||
- items:
|
||||
- const: mediatek,mt8173-disp-mutex
|
||||
- items:
|
||||
- const: mediatek,mt8183-disp-mutex
|
||||
- items:
|
||||
- const: mediatek,mt8192-disp-mutex
|
||||
- items:
|
||||
- const: mediatek,mt8195-disp-mutex
|
||||
enum:
|
||||
- mediatek,mt2701-disp-mutex
|
||||
- mediatek,mt2712-disp-mutex
|
||||
- mediatek,mt8167-disp-mutex
|
||||
- mediatek,mt8173-disp-mutex
|
||||
- mediatek,mt8183-disp-mutex
|
||||
- mediatek,mt8186-disp-mutex
|
||||
- mediatek,mt8192-disp-mutex
|
||||
- mediatek,mt8195-disp-mutex
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ properties:
|
|||
- const: mediatek,mt8183-disp-ovl-2l
|
||||
- items:
|
||||
- const: mediatek,mt8192-disp-ovl-2l
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8186-disp-ovl-2l
|
||||
- const: mediatek,mt8192-disp-ovl-2l
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -33,13 +33,15 @@ properties:
|
|||
- enum:
|
||||
- mediatek,mt7623-disp-ovl
|
||||
- mediatek,mt2712-disp-ovl
|
||||
- enum:
|
||||
- mediatek,mt2701-disp-ovl
|
||||
- const: mediatek,mt2701-disp-ovl
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8195-disp-ovl
|
||||
- const: mediatek,mt8183-disp-ovl
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8183-disp-ovl
|
||||
- mediatek,mt8186-disp-ovl
|
||||
- const: mediatek,mt8192-disp-ovl
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ properties:
|
|||
oneOf:
|
||||
- items:
|
||||
- const: mediatek,mt8192-disp-postmask
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8186-disp-postmask
|
||||
- const: mediatek,mt8192-disp-postmask
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -35,13 +35,12 @@ properties:
|
|||
- enum:
|
||||
- mediatek,mt7623-disp-rdma
|
||||
- mediatek,mt2712-disp-rdma
|
||||
- enum:
|
||||
- mediatek,mt2701-disp-rdma
|
||||
- const: mediatek,mt2701-disp-rdma
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8186-disp-rdma
|
||||
- mediatek,mt8192-disp-rdma
|
||||
- enum:
|
||||
- mediatek,mt8183-disp-rdma
|
||||
- const: mediatek,mt8183-disp-rdma
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ properties:
|
|||
interconnect-names:
|
||||
const: mdp0-mem
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: MDSS_CORE reset
|
||||
|
||||
patternProperties:
|
||||
"^display-controller@[0-9a-f]+$":
|
||||
type: object
|
||||
|
|
|
|||
|
|
@ -65,6 +65,10 @@ properties:
|
|||
interconnect-names:
|
||||
const: mdp0-mem
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: MDSS_CORE reset
|
||||
|
||||
patternProperties:
|
||||
"^display-controller@[0-9a-f]+$":
|
||||
type: object
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ properties:
|
|||
interconnect-names:
|
||||
const: mdp0-mem
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: MDSS_CORE reset
|
||||
|
||||
patternProperties:
|
||||
"^display-controller@[0-9a-f]+$":
|
||||
type: object
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ properties:
|
|||
|
||||
ranges: true
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: MDSS_CORE reset
|
||||
|
||||
patternProperties:
|
||||
"^display-controller@[0-9a-f]+$":
|
||||
type: object
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/leadtek,ltk035c5444t.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Leadtek ltk035c5444t 3.5" (640x480 pixels) 24-bit IPS LCD panel
|
||||
|
||||
maintainers:
|
||||
- Paul Cercueil <paul@crapouillou.net>
|
||||
- Christophe Branchereau <cbranchereau@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: leadtek,ltk035c5444t
|
||||
|
||||
backlight: true
|
||||
port: true
|
||||
power-supply: true
|
||||
reg: true
|
||||
reset-gpios: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- power-supply
|
||||
- reset-gpios
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "leadtek,ltk035c5444t";
|
||||
reg = <0>;
|
||||
|
||||
spi-3wire;
|
||||
spi-max-frequency = <3125000>;
|
||||
|
||||
reset-gpios = <&gpe 2 GPIO_ACTIVE_LOW>;
|
||||
|
||||
backlight = <&backlight>;
|
||||
power-supply = <&vcc>;
|
||||
|
||||
port {
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&panel_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -105,6 +105,8 @@ properties:
|
|||
- chunghwa,claa101wb01
|
||||
# Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
|
||||
- chunghwa,claa101wb03
|
||||
# DataImage, Inc. 4.3" WQVGA (480x272) TFT LCD panel with 24-bit parallel interface.
|
||||
- dataimage,fg040346dsswbg04
|
||||
# DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface.
|
||||
- dataimage,scf0700c48ggu18
|
||||
# DLC Display Co. DLC1010GIG 10.1" WXGA TFT LCD Panel
|
||||
|
|
@ -294,6 +296,8 @@ properties:
|
|||
- starry,kr070pe2t
|
||||
# Starry 12.2" (1920x1200 pixels) TFT LCD panel
|
||||
- starry,kr122ea0sra
|
||||
# Startek KD070WVFPA043-C069A 7" TFT LCD panel
|
||||
- startek,kd070wvfpa
|
||||
# Team Source Display Technology TST043015CMHX 4.3" WQVGA TFT LCD panel
|
||||
- team-source-display,tst043015cmhx
|
||||
# Tianma Micro-electronics TM070JDHG30 7.0" WXGA TFT LCD panel
|
||||
|
|
|
|||
|
|
@ -23,10 +23,22 @@ properties:
|
|||
- rockchip,rk3288-dw-hdmi
|
||||
- rockchip,rk3328-dw-hdmi
|
||||
- rockchip,rk3399-dw-hdmi
|
||||
- rockchip,rk3568-dw-hdmi
|
||||
|
||||
reg-io-width:
|
||||
const: 4
|
||||
|
||||
avdd-0v9-supply:
|
||||
description:
|
||||
A 0.9V supply that powers up the SoC internal circuitry. The actual pin name
|
||||
varies between the different SoCs and is usually HDMI_TX_AVDD_0V9 or sometimes
|
||||
HDMI_AVDD_1V0.
|
||||
|
||||
avdd-1v8-supply:
|
||||
description:
|
||||
A 1.8V supply that powers up the SoC internal circuitry. The pin name on the
|
||||
SoC usually is HDMI_TX_AVDD_1V8.
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
items:
|
||||
|
|
@ -36,7 +48,8 @@ properties:
|
|||
# order when present.
|
||||
- description: The HDMI CEC controller main clock
|
||||
- description: Power for GRF IO
|
||||
- description: External clock for some HDMI PHY
|
||||
- description: External clock for some HDMI PHY (old clock name, deprecated)
|
||||
- description: External clock for some HDMI PHY (new name)
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
|
|
@ -47,10 +60,14 @@ properties:
|
|||
- cec
|
||||
- grf
|
||||
- vpll
|
||||
- ref
|
||||
- enum:
|
||||
- grf
|
||||
- vpll
|
||||
- const: vpll
|
||||
- ref
|
||||
- enum:
|
||||
- vpll
|
||||
- ref
|
||||
|
||||
ddc-i2c-bus:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
|
@ -72,6 +89,7 @@ properties:
|
|||
The unwedge pinctrl entry shall drive the DDC SDA line low. This is
|
||||
intended to work around a hardware errata that can cause the DDC I2C
|
||||
bus to be wedged.
|
||||
minItems: 1
|
||||
items:
|
||||
- const: default
|
||||
- const: unwedge
|
||||
|
|
@ -79,27 +97,21 @@ properties:
|
|||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
patternProperties:
|
||||
"^port(@0)?$":
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Input of the DWC HDMI TX
|
||||
|
||||
properties:
|
||||
endpoint:
|
||||
description: Connection to the VOP
|
||||
endpoint@0:
|
||||
$ref: /schemas/graph.yaml#/properties/endpoint
|
||||
description: Connection to the VOPB
|
||||
|
||||
endpoint@1:
|
||||
$ref: /schemas/graph.yaml#/properties/endpoint
|
||||
description: Connection to the VOPL
|
||||
|
||||
required:
|
||||
- endpoint@0
|
||||
- endpoint@1
|
||||
|
||||
required:
|
||||
- port
|
||||
properties:
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: Output of the DWC HDMI TX
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/rockchip/rockchip-vop2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip SoC display controller (VOP2)
|
||||
|
||||
description:
|
||||
VOP2 (Video Output Processor v2) is the display controller for the Rockchip
|
||||
series of SoCs which transfers the image data from a video memory
|
||||
buffer to an external LCD interface.
|
||||
|
||||
maintainers:
|
||||
- Sandy Huang <hjc@rock-chips.com>
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3566-vop
|
||||
- rockchip,rk3568-vop
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description:
|
||||
Must contain one entry corresponding to the base address and length
|
||||
of the register space.
|
||||
- description:
|
||||
Can optionally contain a second entry corresponding to
|
||||
the CRTC gamma LUT address.
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: vop
|
||||
- const: gamma-lut
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description:
|
||||
The VOP interrupt is shared by several interrupt sources, such as
|
||||
frame start (VSYNC), line flag and other status interrupts.
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Clock for ddr buffer transfer.
|
||||
- description: Clock for the ahb bus to R/W the phy regs.
|
||||
- description: Pixel clock for video port 0.
|
||||
- description: Pixel clock for video port 1.
|
||||
- description: Pixel clock for video port 2.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: aclk
|
||||
- const: hclk
|
||||
- const: dclk_vp0
|
||||
- const: dclk_vp1
|
||||
- const: dclk_vp2
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to GRF regs used for misc control
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Output endpoint of VP0
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Output endpoint of VP1
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Output endpoint of VP2
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3568-cru.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/rk3568-power.h>
|
||||
bus {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
vop: vop@fe040000 {
|
||||
compatible = "rockchip,rk3568-vop";
|
||||
reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>;
|
||||
reg-names = "vop", "gamma-lut";
|
||||
interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru ACLK_VOP>,
|
||||
<&cru HCLK_VOP>,
|
||||
<&cru DCLK_VOP0>,
|
||||
<&cru DCLK_VOP1>,
|
||||
<&cru DCLK_VOP2>;
|
||||
clock-names = "aclk",
|
||||
"hclk",
|
||||
"dclk_vp0",
|
||||
"dclk_vp1",
|
||||
"dclk_vp2";
|
||||
power-domains = <&power RK3568_PD_VO>;
|
||||
iommus = <&vop_mmu>;
|
||||
vop_out: ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
vp0: port@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
vp1: port@1 {
|
||||
reg = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
vp2: port@2 {
|
||||
reg = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -32,15 +32,13 @@ properties:
|
|||
- okaya,rh128128t
|
||||
- const: sitronix,st7715r
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 32000000
|
||||
|
||||
dc-gpios:
|
||||
maxItems: 1
|
||||
description: Display data/command selection (D/CX)
|
||||
|
||||
backlight: true
|
||||
reg: true
|
||||
spi-max-frequency: true
|
||||
reset-gpios: true
|
||||
rotation: true
|
||||
|
||||
|
|
@ -48,7 +46,6 @@ required:
|
|||
- compatible
|
||||
- reg
|
||||
- dc-gpios
|
||||
- reset-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
|
@ -72,6 +69,7 @@ examples:
|
|||
dc-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>;
|
||||
rotation = <270>;
|
||||
backlight = <&backlight>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,22 @@ maintainers:
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- solomon,ssd1305fb-i2c
|
||||
- solomon,ssd1306fb-i2c
|
||||
- solomon,ssd1307fb-i2c
|
||||
- solomon,ssd1309fb-i2c
|
||||
oneOf:
|
||||
# Deprecated compatible strings
|
||||
- items:
|
||||
- enum:
|
||||
- solomon,ssd1305fb-i2c
|
||||
- solomon,ssd1306fb-i2c
|
||||
- solomon,ssd1307fb-i2c
|
||||
- solomon,ssd1309fb-i2c
|
||||
deprecated: true
|
||||
- items:
|
||||
- enum:
|
||||
- sinowealth,sh1106
|
||||
- solomon,ssd1305
|
||||
- solomon,ssd1306
|
||||
- solomon,ssd1307
|
||||
- solomon,ssd1309
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
@ -27,9 +38,20 @@ properties:
|
|||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
# Only required for SPI
|
||||
dc-gpios:
|
||||
description:
|
||||
GPIO connected to the controller's D/C# (Data/Command) pin,
|
||||
that is needed for 4-wire SPI to tell the controller if the
|
||||
data sent is for a command register or the display data RAM
|
||||
maxItems: 1
|
||||
|
||||
vbat-supply:
|
||||
description: The supply for VBAT
|
||||
|
||||
# Only required for SPI
|
||||
spi-max-frequency: true
|
||||
|
||||
solomon,height:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 16
|
||||
|
|
@ -135,7 +157,21 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1305fb-i2c
|
||||
const: sinowealth,sh1106
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
default: 1
|
||||
solomon,dclk-frq:
|
||||
default: 5
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- solomon,ssd1305-i2c
|
||||
- solomon,ssd1305
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
|
|
@ -147,7 +183,9 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1306fb-i2c
|
||||
enum:
|
||||
- solomon,ssd1306-i2c
|
||||
- solomon,ssd1306
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
|
|
@ -159,7 +197,9 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1307fb-i2c
|
||||
enum:
|
||||
- solomon,ssd1307-i2c
|
||||
- solomon,ssd1307
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
|
|
@ -173,7 +213,9 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: solomon,ssd1309fb-i2c
|
||||
enum:
|
||||
- solomon,ssd1309-i2c
|
||||
- solomon,ssd1309
|
||||
then:
|
||||
properties:
|
||||
solomon,dclk-div:
|
||||
|
|
@ -189,15 +231,15 @@ examples:
|
|||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ssd1307: oled@3c {
|
||||
compatible = "solomon,ssd1307fb-i2c";
|
||||
ssd1307_i2c: oled@3c {
|
||||
compatible = "solomon,ssd1307";
|
||||
reg = <0x3c>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
};
|
||||
|
||||
ssd1306: oled@3d {
|
||||
compatible = "solomon,ssd1306fb-i2c";
|
||||
ssd1306_i2c: oled@3d {
|
||||
compatible = "solomon,ssd1306";
|
||||
reg = <0x3c>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
|
|
@ -207,3 +249,30 @@ examples:
|
|||
solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ssd1307_spi: oled@0 {
|
||||
compatible = "solomon,ssd1307";
|
||||
reg = <0x0>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
dc-gpios = <&gpio2 8>;
|
||||
spi-max-frequency = <10000000>;
|
||||
};
|
||||
|
||||
ssd1306_spi: oled@1 {
|
||||
compatible = "solomon,ssd1306";
|
||||
reg = <0x1>;
|
||||
pwms = <&pwm 4 3000>;
|
||||
reset-gpios = <&gpio2 7>;
|
||||
dc-gpios = <&gpio2 8>;
|
||||
spi-max-frequency = <10000000>;
|
||||
solomon,com-lrremap;
|
||||
solomon,com-invdir;
|
||||
solomon,com-offset = <32>;
|
||||
solomon,lookup-table = /bits/ 8 <0x3f 0x3f 0x3f 0x3f>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1136,6 +1136,8 @@ patternProperties:
|
|||
description: Sinlinx Electronics Technology Co., LTD
|
||||
"^sinovoip,.*":
|
||||
description: SinoVoip Co., Ltd
|
||||
"^sinowealth,.*":
|
||||
description: SINO WEALTH Electronic Ltd.
|
||||
"^sipeed,.*":
|
||||
description: Shenzhen Sipeed Technology Co., Ltd.
|
||||
"^sirf,.*":
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ structure to represent a mediated device's driver::
|
|||
struct mdev_driver {
|
||||
int (*probe) (struct mdev_device *dev);
|
||||
void (*remove) (struct mdev_device *dev);
|
||||
struct attribute_group **supported_type_groups;
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
|
|
@ -119,33 +120,15 @@ to register and unregister itself with the core driver:
|
|||
|
||||
extern void mdev_unregister_driver(struct mdev_driver *drv);
|
||||
|
||||
The mediated bus driver is responsible for adding mediated devices to the VFIO
|
||||
group when devices are bound to the driver and removing mediated devices from
|
||||
the VFIO when devices are unbound from the driver.
|
||||
|
||||
|
||||
Physical Device Driver Interface
|
||||
--------------------------------
|
||||
|
||||
The physical device driver interface provides the mdev_parent_ops[3] structure
|
||||
to define the APIs to manage work in the mediated core driver that is related
|
||||
to the physical device.
|
||||
|
||||
The structures in the mdev_parent_ops structure are as follows:
|
||||
|
||||
* dev_attr_groups: attributes of the parent device
|
||||
* mdev_attr_groups: attributes of the mediated device
|
||||
* supported_config: attributes to define supported configurations
|
||||
* device_driver: device driver to bind for mediated device instances
|
||||
|
||||
The mdev_parent_ops also still has various functions pointers. Theses exist
|
||||
for historical reasons only and shall not be used for new drivers.
|
||||
The mediated bus driver's probe function should create a vfio_device on top of
|
||||
the mdev_device and connect it to an appropriate implementation of
|
||||
vfio_device_ops.
|
||||
|
||||
When a driver wants to add the GUID creation sysfs to an existing device it has
|
||||
probe'd to then it should call::
|
||||
|
||||
extern int mdev_register_device(struct device *dev,
|
||||
const struct mdev_parent_ops *ops);
|
||||
struct mdev_driver *mdev_driver);
|
||||
|
||||
This will provide the 'mdev_supported_types/XX/create' files which can then be
|
||||
used to trigger the creation of a mdev_device. The created mdev_device will be
|
||||
|
|
|
|||
|
|
@ -8,12 +8,19 @@ we have a dedicated glossary for Display Core at
|
|||
|
||||
.. glossary::
|
||||
|
||||
active_cu_number
|
||||
The number of CUs that are active on the system. The number of active
|
||||
CUs may be less than SE * SH * CU depending on the board configuration.
|
||||
|
||||
CP
|
||||
Command Processor
|
||||
|
||||
CPLIB
|
||||
Content Protection Library
|
||||
|
||||
CU
|
||||
Compute Unit
|
||||
|
||||
DFS
|
||||
Digital Frequency Synthesizer
|
||||
|
||||
|
|
@ -74,6 +81,12 @@ we have a dedicated glossary for Display Core at
|
|||
SDMA
|
||||
System DMA
|
||||
|
||||
SE
|
||||
Shader Engine
|
||||
|
||||
SH
|
||||
SHader array
|
||||
|
||||
SMU
|
||||
System Management Unit
|
||||
|
||||
|
|
|
|||
|
|
@ -226,40 +226,43 @@ Panel Self Refresh Helper Reference
|
|||
HDCP Helper Functions Reference
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_hdcp.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_hdcp_helper.c
|
||||
:export:
|
||||
|
||||
Display Port Helper Functions Reference
|
||||
=======================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_helper.c
|
||||
:doc: dp helpers
|
||||
|
||||
.. kernel-doc:: include/drm/dp/drm_dp_helper.h
|
||||
.. kernel-doc:: include/drm/display/drm_dp.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c
|
||||
.. kernel-doc:: include/drm/display/drm_dp_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_helper.c
|
||||
:export:
|
||||
|
||||
Display Port CEC Helper Functions Reference
|
||||
===========================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_cec.c
|
||||
:doc: dp cec helpers
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_cec.c
|
||||
:export:
|
||||
|
||||
Display Port Dual Mode Adaptor Helper Functions Reference
|
||||
=========================================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
|
||||
:doc: dp dual mode helpers
|
||||
|
||||
.. kernel-doc:: include/drm/dp/drm_dp_dual_mode_helper.h
|
||||
.. kernel-doc:: include/drm/display/drm_dp_dual_mode_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_dual_mode_helper.c
|
||||
:export:
|
||||
|
||||
Display Port MST Helpers
|
||||
|
|
@ -268,19 +271,19 @@ Display Port MST Helpers
|
|||
Overview
|
||||
--------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_mst_topology.c
|
||||
:doc: dp mst helper
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_mst_topology.c
|
||||
:doc: Branch device and port refcounting
|
||||
|
||||
Functions Reference
|
||||
-------------------
|
||||
|
||||
.. kernel-doc:: include/drm/dp/drm_dp_mst_helper.h
|
||||
.. kernel-doc:: include/drm/display/drm_dp_mst_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_mst_topology.c
|
||||
:export:
|
||||
|
||||
Topology Lifetime Internals
|
||||
|
|
@ -289,7 +292,7 @@ Topology Lifetime Internals
|
|||
These functions aren't exported to drivers, but are documented here to help make
|
||||
the MST topology helpers easier to understand
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dp_mst_topology.c
|
||||
:functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb
|
||||
drm_dp_mst_topology_put_mstb
|
||||
drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port
|
||||
|
|
@ -323,13 +326,13 @@ MIPI DSI Helper Functions Reference
|
|||
Display Stream Compression Helper Functions Reference
|
||||
=====================================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_dsc.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dsc_helper.c
|
||||
:doc: dsc helpers
|
||||
|
||||
.. kernel-doc:: include/drm/drm_dsc.h
|
||||
.. kernel-doc:: include/drm/display/drm_dsc.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_dsc.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_dsc_helper.c
|
||||
:export:
|
||||
|
||||
Output Probing Helper Functions Reference
|
||||
|
|
@ -353,13 +356,13 @@ EDID Helper Functions Reference
|
|||
SCDC Helper Functions Reference
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_scdc_helper.c
|
||||
:doc: scdc helpers
|
||||
|
||||
.. kernel-doc:: include/drm/drm_scdc_helper.h
|
||||
.. kernel-doc:: include/drm/display/drm_scdc_helper.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_scdc_helper.c
|
||||
.. kernel-doc:: drivers/gpu/drm/display/drm_scdc_helper.c
|
||||
:export:
|
||||
|
||||
HDMI Infoframes Helper Reference
|
||||
|
|
|
|||
|
|
@ -466,6 +466,15 @@ DRM MM Range Allocator Function References
|
|||
.. kernel-doc:: drivers/gpu/drm/drm_mm.c
|
||||
:export:
|
||||
|
||||
DRM Buddy Allocator
|
||||
===================
|
||||
|
||||
DRM Buddy Function References
|
||||
-----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/drm_buddy.c
|
||||
:export:
|
||||
|
||||
DRM Cache Handling and Fast WC memcpy()
|
||||
=======================================
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,9 @@ clients together with the legacy drmAuth authentication procedure.
|
|||
If a driver advertises render node support, DRM core will create a
|
||||
separate render node called renderD<num>. There will be one render node
|
||||
per device. No ioctls except PRIME-related ioctls will be allowed on
|
||||
this node. Especially GEM_OPEN will be explicitly prohibited. Render
|
||||
this node. Especially GEM_OPEN will be explicitly prohibited. For a
|
||||
complete list of driver-independent ioctls that can be used on render
|
||||
nodes, see the ioctls marked DRM_RENDER_ALLOW in drm_ioctl.c Render
|
||||
nodes are designed to avoid the buffer-leaks, which occur if clients
|
||||
guess the flink names or mmap offsets on the legacy interface.
|
||||
Additionally to this basic interface, drivers must mark their
|
||||
|
|
|
|||
112
Documentation/gpu/drm-usage-stats.rst
Normal file
112
Documentation/gpu/drm-usage-stats.rst
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
.. _drm-client-usage-stats:
|
||||
|
||||
======================
|
||||
DRM client usage stats
|
||||
======================
|
||||
|
||||
DRM drivers can choose to export partly standardised text output via the
|
||||
`fops->show_fdinfo()` as part of the driver specific file operations registered
|
||||
in the `struct drm_driver` object registered with the DRM core.
|
||||
|
||||
One purpose of this output is to enable writing as generic as practicaly
|
||||
feasible `top(1)` like userspace monitoring tools.
|
||||
|
||||
Given the differences between various DRM drivers the specification of the
|
||||
output is split between common and driver specific parts. Having said that,
|
||||
wherever possible effort should still be made to standardise as much as
|
||||
possible.
|
||||
|
||||
File format specification
|
||||
=========================
|
||||
|
||||
- File shall contain one key value pair per one line of text.
|
||||
- Colon character (`:`) must be used to delimit keys and values.
|
||||
- All keys shall be prefixed with `drm-`.
|
||||
- Whitespace between the delimiter and first non-whitespace character shall be
|
||||
ignored when parsing.
|
||||
- Neither keys or values are allowed to contain whitespace characters.
|
||||
- Numerical key value pairs can end with optional unit string.
|
||||
- Data type of the value is fixed as defined in the specification.
|
||||
|
||||
Key types
|
||||
---------
|
||||
|
||||
1. Mandatory, fully standardised.
|
||||
2. Optional, fully standardised.
|
||||
3. Driver specific.
|
||||
|
||||
Data types
|
||||
----------
|
||||
|
||||
- <uint> - Unsigned integer without defining the maximum value.
|
||||
- <str> - String excluding any above defined reserved characters or whitespace.
|
||||
|
||||
Mandatory fully standardised keys
|
||||
---------------------------------
|
||||
|
||||
- drm-driver: <str>
|
||||
|
||||
String shall contain the name this driver registered as via the respective
|
||||
`struct drm_driver` data structure.
|
||||
|
||||
Optional fully standardised keys
|
||||
--------------------------------
|
||||
|
||||
- drm-pdev: <aaaa:bb.cc.d>
|
||||
|
||||
For PCI devices this should contain the PCI slot address of the device in
|
||||
question.
|
||||
|
||||
- drm-client-id: <uint>
|
||||
|
||||
Unique value relating to the open DRM file descriptor used to distinguish
|
||||
duplicated and shared file descriptors. Conceptually the value should map 1:1
|
||||
to the in kernel representation of `struct drm_file` instances.
|
||||
|
||||
Uniqueness of the value shall be either globally unique, or unique within the
|
||||
scope of each device, in which case `drm-pdev` shall be present as well.
|
||||
|
||||
Userspace should make sure to not double account any usage statistics by using
|
||||
the above described criteria in order to associate data to individual clients.
|
||||
|
||||
- drm-engine-<str>: <uint> ns
|
||||
|
||||
GPUs usually contain multiple execution engines. Each shall be given a stable
|
||||
and unique name (str), with possible values documented in the driver specific
|
||||
documentation.
|
||||
|
||||
Value shall be in specified time units which the respective GPU engine spent
|
||||
busy executing workloads belonging to this client.
|
||||
|
||||
Values are not required to be constantly monotonic if it makes the driver
|
||||
implementation easier, but are required to catch up with the previously reported
|
||||
larger value within a reasonable period. Upon observing a value lower than what
|
||||
was previously read, userspace is expected to stay with that larger previous
|
||||
value until a monotonic update is seen.
|
||||
|
||||
- drm-engine-capacity-<str>: <uint>
|
||||
|
||||
Engine identifier string must be the same as the one specified in the
|
||||
drm-engine-<str> tag and shall contain a greater than zero number in case the
|
||||
exported engine corresponds to a group of identical hardware engines.
|
||||
|
||||
In the absence of this tag parser shall assume capacity of one. Zero capacity
|
||||
is not allowed.
|
||||
|
||||
- drm-memory-<str>: <uint> [KiB|MiB]
|
||||
|
||||
Each possible memory type which can be used to store buffer objects by the
|
||||
GPU in question shall be given a stable and unique name to be returned as the
|
||||
string here.
|
||||
|
||||
Value shall reflect the amount of storage currently consumed by the buffer
|
||||
object belong to this client, in the respective memory region.
|
||||
|
||||
Default unit shall be bytes with optional unit specifiers of 'KiB' or 'MiB'
|
||||
indicating kibi- or mebi-bytes.
|
||||
|
||||
===============================
|
||||
Driver specific implementations
|
||||
===============================
|
||||
|
||||
:ref:`i915-usage-stats`
|
||||
|
|
@ -187,19 +187,7 @@ Display Refresh Rate Switching (DRRS)
|
|||
:doc: Display Refresh Rate Switching (DRRS)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:functions: intel_drrs_enable
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:functions: intel_drrs_disable
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:functions: intel_drrs_invalidate
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:functions: intel_drrs_flush
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:functions: intel_drrs_init
|
||||
:internal:
|
||||
|
||||
DPIO
|
||||
----
|
||||
|
|
@ -709,3 +697,31 @@ The style guide for ``i915_reg.h``.
|
|||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/i915_reg.h
|
||||
:doc: The i915 register macro definition style guide
|
||||
|
||||
.. _i915-usage-stats:
|
||||
|
||||
i915 DRM client usage stats implementation
|
||||
==========================================
|
||||
|
||||
The drm/i915 driver implements the DRM client usage stats specification as
|
||||
documented in :ref:`drm-client-usage-stats`.
|
||||
|
||||
Example of the output showing the implemented key value pairs and entirety of
|
||||
the currently possible format options:
|
||||
|
||||
::
|
||||
|
||||
pos: 0
|
||||
flags: 0100002
|
||||
mnt_id: 21
|
||||
drm-driver: i915
|
||||
drm-pdev: 0000:00:02.0
|
||||
drm-client-id: 7
|
||||
drm-engine-render: 9288864723 ns
|
||||
drm-engine-copy: 2035071108 ns
|
||||
drm-engine-video: 0 ns
|
||||
drm-engine-capacity-video: 2
|
||||
drm-engine-video-enhance: 0 ns
|
||||
|
||||
Possible `drm-engine-` key names are: `render`, `copy`, `video` and
|
||||
`video-enhance`.
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ Linux GPU Driver Developer's Guide
|
|||
drm-kms
|
||||
drm-kms-helpers
|
||||
drm-uapi
|
||||
drm-usage-stats
|
||||
driver-uapi
|
||||
drm-client
|
||||
drivers
|
||||
|
|
|
|||
|
|
@ -112,3 +112,63 @@ Please conduct yourself in a respectful and civilised manner when
|
|||
interacting with community members on mailing lists, IRC, or bug
|
||||
trackers. The community represents the project as a whole, and abusive
|
||||
or bullying behaviour is not tolerated by the project.
|
||||
|
||||
Simple DRM drivers to use as examples
|
||||
=====================================
|
||||
|
||||
The DRM subsystem contains a lot of helper functions to ease writing drivers for
|
||||
simple graphic devices. For example, the `drivers/gpu/drm/tiny/` directory has a
|
||||
set of drivers that are simple enough to be implemented in a single source file.
|
||||
|
||||
These drivers make use of the `struct drm_simple_display_pipe_funcs`, that hides
|
||||
any complexity of the DRM subsystem and just requires drivers to implement a few
|
||||
functions needed to operate the device. This could be used for devices that just
|
||||
need a display pipeline with one full-screen scanout buffer feeding one output.
|
||||
|
||||
The tiny DRM drivers are good examples to understand how DRM drivers should look
|
||||
like. Since are just a few hundreds lines of code, they are quite easy to read.
|
||||
|
||||
External References
|
||||
===================
|
||||
|
||||
Delving into a Linux kernel subsystem for the first time can be an overwhelming
|
||||
experience, one needs to get familiar with all the concepts and learn about the
|
||||
subsystem's internals, among other details.
|
||||
|
||||
To shallow the learning curve, this section contains a list of presentations
|
||||
and documents that can be used to learn about DRM/KMS and graphics in general.
|
||||
|
||||
There are different reasons why someone might want to get into DRM: porting an
|
||||
existing fbdev driver, write a DRM driver for a new hardware, fixing bugs that
|
||||
could face when working on the graphics user-space stack, etc. For this reason,
|
||||
the learning material covers many aspects of the Linux graphics stack. From an
|
||||
overview of the kernel and user-space stacks to very specific topics.
|
||||
|
||||
The list is sorted in reverse chronological order, to keep the most up-to-date
|
||||
material at the top. But all of them contain useful information, and it can be
|
||||
valuable to go through older material to understand the rationale and context
|
||||
in which the changes to the DRM subsystem were made.
|
||||
|
||||
Conference talks
|
||||
----------------
|
||||
|
||||
* `An Overview of the Linux and Userspace Graphics Stack <https://www.youtube.com/watch?v=wjAJmqwg47k>`_ - Paul Kocialkowski (2020)
|
||||
* `Getting pixels on screen on Linux: introduction to Kernel Mode Setting <https://www.youtube.com/watch?v=haes4_Xnc5Q>`_ - Simon Ser (2020)
|
||||
* `Everything Great about Upstream Graphics <https://www.youtube.com/watch?v=kVzHOgt6WGE>`_ - Daniel Vetter (2019)
|
||||
* `An introduction to the Linux DRM subsystem <https://www.youtube.com/watch?v=LbDOCJcDRoo>`_ - Maxime Ripard (2017)
|
||||
* `Embrace the Atomic (Display) Age <https://www.youtube.com/watch?v=LjiB_JeDn2M>`_ - Daniel Vetter (2016)
|
||||
* `Anatomy of an Atomic KMS Driver <https://www.youtube.com/watch?v=lihqR9sENpc>`_ - Laurent Pinchart (2015)
|
||||
* `Atomic Modesetting for Drivers <https://www.youtube.com/watch?v=kl9suFgbTc8>`_ - Daniel Vetter (2015)
|
||||
* `Anatomy of an Embedded KMS Driver <https://www.youtube.com/watch?v=Ja8fM7rTae4>`_ - Laurent Pinchart (2013)
|
||||
|
||||
Slides and articles
|
||||
-------------------
|
||||
|
||||
* `Understanding the Linux Graphics Stack <https://bootlin.com/doc/training/graphics/graphics-slides.pdf>`_ - Bootlin (2022)
|
||||
* `DRM KMS overview <https://wiki.st.com/stm32mpu/wiki/DRM_KMS_overview>`_ - STMicroelectronics (2021)
|
||||
* `Linux graphic stack <https://studiopixl.com/2017-05-13/linux-graphic-stack-an-overview>`_ - Nathan Gauër (2017)
|
||||
* `Atomic mode setting design overview, part 1 <https://lwn.net/Articles/653071/>`_ - Daniel Vetter (2015)
|
||||
* `Atomic mode setting design overview, part 2 <https://lwn.net/Articles/653466/>`_ - Daniel Vetter (2015)
|
||||
* `The DRM/KMS subsystem from a newbie’s point of view <https://bootlin.com/pub/conferences/2014/elce/brezillon-drm-kms/brezillon-drm-kms.pdf>`_ - Boris Brezillon (2014)
|
||||
* `A brief introduction to the Linux graphics stack <https://blogs.igalia.com/itoral/2014/07/29/a-brief-introduction-to-the-linux-graphics-stack/>`_ - Iago Toral (2014)
|
||||
* `The Linux Graphics Stack <https://blog.mecheye.net/2012/06/the-linux-graphics-stack/>`_ - Jasper St. Pierre (2012)
|
||||
|
|
|
|||
|
|
@ -603,6 +603,20 @@ Level: Advanced
|
|||
Better Testing
|
||||
==============
|
||||
|
||||
Add unit tests using the Kernel Unit Testing (KUnit) framework
|
||||
--------------------------------------------------------------
|
||||
|
||||
The `KUnit <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>`_
|
||||
provides a common framework for unit tests within the Linux kernel. Having a
|
||||
test suite would allow to identify regressions earlier.
|
||||
|
||||
A good candidate for the first unit tests are the format-conversion helpers in
|
||||
``drm_format_helper.c``.
|
||||
|
||||
Contact: Javier Martinez Canillas <javierm@redhat.com>
|
||||
|
||||
Level: Intermediate
|
||||
|
||||
Enable trinity for DRM
|
||||
----------------------
|
||||
|
||||
|
|
|
|||
18
MAINTAINERS
18
MAINTAINERS
|
|
@ -6280,8 +6280,9 @@ F: drivers/gpu/drm/tiny/panel-mipi-dbi.c
|
|||
|
||||
DRM DRIVER FOR MSM ADRENO GPU
|
||||
M: Rob Clark <robdclark@gmail.com>
|
||||
M: Sean Paul <sean@poorly.run>
|
||||
R: Abhinav Kumar <quic_abhinavk@quicinc.com>
|
||||
M: Abhinav Kumar <quic_abhinavk@quicinc.com>
|
||||
M: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
R: Sean Paul <sean@poorly.run>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
L: freedreno@lists.freedesktop.org
|
||||
|
|
@ -6334,6 +6335,11 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino.yaml
|
||||
F: drivers/gpu/drm/panel/panel-olimex-lcd-olinuxino.c
|
||||
|
||||
DRM DRIVER FOR PARADE PS8640 BRIDGE CHIP
|
||||
R: Douglas Anderson <dianders@chromium.org>
|
||||
F: Documentation/devicetree/bindings/display/bridge/ps8640.yaml
|
||||
F: drivers/gpu/drm/bridge/parade-ps8640.c
|
||||
|
||||
DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS
|
||||
M: Noralf Trønnes <noralf@tronnes.org>
|
||||
S: Maintained
|
||||
|
|
@ -6447,6 +6453,11 @@ DRM DRIVER FOR TDFX VIDEO CARDS
|
|||
S: Orphan / Obsolete
|
||||
F: drivers/gpu/drm/tdfx/
|
||||
|
||||
DRM DRIVER FOR TI SN65DSI86 BRIDGE CHIP
|
||||
R: Douglas Anderson <dianders@chromium.org>
|
||||
F: Documentation/devicetree/bindings/display/bridge/ti,sn65dsi86.yaml
|
||||
F: drivers/gpu/drm/bridge/ti-sn65dsi86.c
|
||||
|
||||
DRM DRIVER FOR TPO TPG110 PANELS
|
||||
M: Linus Walleij <linus.walleij@linaro.org>
|
||||
S: Maintained
|
||||
|
|
@ -6566,6 +6577,7 @@ R: Jonas Karlman <jonas@kwiboo.se>
|
|||
R: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
S: Maintained
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/display/bridge/
|
||||
F: drivers/gpu/drm/bridge/
|
||||
|
||||
DRM DRIVERS FOR EXYNOS
|
||||
|
|
@ -10023,6 +10035,7 @@ S: Supported
|
|||
F: Documentation/driver-api/mei/*
|
||||
F: drivers/misc/mei/
|
||||
F: drivers/watchdog/mei_wdt.c
|
||||
F: include/linux/mei_aux.h
|
||||
F: include/linux/mei_cl_bus.h
|
||||
F: include/uapi/linux/mei.h
|
||||
F: samples/mei/*
|
||||
|
|
@ -16546,6 +16559,7 @@ S: Supported
|
|||
T: git https://gitlab.freedesktop.org/agd5f/linux.git
|
||||
B: https://gitlab.freedesktop.org/drm/amd/-/issues
|
||||
C: irc://irc.oftc.net/radeon
|
||||
F: Documentation/gpu/amdgpu/
|
||||
F: drivers/gpu/drm/amd/
|
||||
F: drivers/gpu/drm/radeon/
|
||||
F: include/uapi/drm/amdgpu_drm.h
|
||||
|
|
|
|||
|
|
@ -960,6 +960,12 @@ config GART_IOMMU
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config BOOT_VESA_SUPPORT
|
||||
bool
|
||||
help
|
||||
If true, at least one selected framebuffer driver can take advantage
|
||||
of VESA video modes set at an early boot stage via the vga= parameter.
|
||||
|
||||
config MAXSMP
|
||||
bool "Enable Maximum number of SMP Processors and NUMA Nodes"
|
||||
depends on X86_64 && SMP && DEBUG_KERNEL
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static int vesa_probe(void)
|
|||
(vminfo.memory_layout == 4 ||
|
||||
vminfo.memory_layout == 6) &&
|
||||
vminfo.memory_planes == 1) {
|
||||
#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
|
||||
#ifdef CONFIG_BOOT_VESA_SUPPORT
|
||||
/* Graphics mode, color, linear frame buffer
|
||||
supported. Only register the mode if
|
||||
if framebuffer is configured, however,
|
||||
|
|
@ -121,7 +121,7 @@ static int vesa_set_mode(struct mode_info *mode)
|
|||
if ((vminfo.mode_attr & 0x15) == 0x05) {
|
||||
/* It's a supported text mode */
|
||||
is_graphic = 0;
|
||||
#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
|
||||
#ifdef CONFIG_BOOT_VESA_SUPPORT
|
||||
} else if ((vminfo.mode_attr & 0x99) == 0x99) {
|
||||
/* It's a graphics mode with linear frame buffer */
|
||||
is_graphic = 1;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/bcma/bcma_regs.h>
|
||||
#include <linux/platform_data/x86/apple.h>
|
||||
#include <drm/i915_drm.h>
|
||||
#include <drm/i915_pciids.h>
|
||||
#include <asm/pci-direct.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/io_apic.h>
|
||||
|
|
@ -557,6 +558,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
|
|||
INTEL_ADLP_IDS(&gen11_early_ops),
|
||||
INTEL_ADLN_IDS(&gen11_early_ops),
|
||||
INTEL_RPLS_IDS(&gen11_early_ops),
|
||||
INTEL_RPLP_IDS(&gen11_early_ops),
|
||||
};
|
||||
|
||||
struct resource intel_graphics_stolen_res __ro_after_init = DEFINE_RES_MEM(0, 0);
|
||||
|
|
|
|||
|
|
@ -216,7 +216,8 @@ static bool dma_buf_poll_add_cb(struct dma_resv *resv, bool write,
|
|||
struct dma_fence *fence;
|
||||
int r;
|
||||
|
||||
dma_resv_for_each_fence(&cursor, resv, write, fence) {
|
||||
dma_resv_for_each_fence(&cursor, resv, dma_resv_usage_rw(write),
|
||||
fence) {
|
||||
dma_fence_get(fence);
|
||||
r = dma_fence_add_callback(fence, &dcb->cb, dma_buf_poll_cb);
|
||||
if (!r)
|
||||
|
|
@ -451,7 +452,7 @@ err_alloc_file:
|
|||
* as a file descriptor by calling dma_buf_fd().
|
||||
*
|
||||
* 2. Userspace passes this file-descriptors to all drivers it wants this buffer
|
||||
* to share with: First the filedescriptor is converted to a &dma_buf using
|
||||
* to share with: First the file descriptor is converted to a &dma_buf using
|
||||
* dma_buf_get(). Then the buffer is attached to the device using
|
||||
* dma_buf_attach().
|
||||
*
|
||||
|
|
@ -668,12 +669,24 @@ static struct sg_table * __map_dma_buf(struct dma_buf_attachment *attach,
|
|||
enum dma_data_direction direction)
|
||||
{
|
||||
struct sg_table *sg_table;
|
||||
signed long ret;
|
||||
|
||||
sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
|
||||
if (IS_ERR_OR_NULL(sg_table))
|
||||
return sg_table;
|
||||
|
||||
if (!IS_ERR_OR_NULL(sg_table))
|
||||
mangle_sg_table(sg_table);
|
||||
if (!dma_buf_attachment_is_dynamic(attach)) {
|
||||
ret = dma_resv_wait_timeout(attach->dmabuf->resv,
|
||||
DMA_RESV_USAGE_KERNEL, true,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0) {
|
||||
attach->dmabuf->ops->unmap_dma_buf(attach, sg_table,
|
||||
direction);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
|
||||
mangle_sg_table(sg_table);
|
||||
return sg_table;
|
||||
}
|
||||
|
||||
|
|
@ -1132,7 +1145,8 @@ static int __dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
|
|||
long ret;
|
||||
|
||||
/* Wait on any implicit rendering fences */
|
||||
ret = dma_resv_wait_timeout(resv, write, true, MAX_SCHEDULE_TIMEOUT);
|
||||
ret = dma_resv_wait_timeout(resv, dma_resv_usage_rw(write),
|
||||
true, MAX_SCHEDULE_TIMEOUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/dma-resv.h>
|
||||
#include <linux/dma-fence-array.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched/mm.h>
|
||||
|
|
@ -43,12 +44,12 @@
|
|||
/**
|
||||
* DOC: Reservation Object Overview
|
||||
*
|
||||
* The reservation object provides a mechanism to manage shared and
|
||||
* exclusive fences associated with a buffer. A reservation object
|
||||
* can have attached one exclusive fence (normally associated with
|
||||
* write operations) or N shared fences (read operations). The RCU
|
||||
* mechanism is used to protect read access to fences from locked
|
||||
* write-side updates.
|
||||
* The reservation object provides a mechanism to manage a container of
|
||||
* dma_fence object associated with a resource. A reservation object
|
||||
* can have any number of fences attaches to it. Each fence carries an usage
|
||||
* parameter determining how the operation represented by the fence is using the
|
||||
* resource. The RCU mechanism is used to protect read access to fences from
|
||||
* locked write-side updates.
|
||||
*
|
||||
* See struct dma_resv for more details.
|
||||
*/
|
||||
|
|
@ -56,33 +57,59 @@
|
|||
DEFINE_WD_CLASS(reservation_ww_class);
|
||||
EXPORT_SYMBOL(reservation_ww_class);
|
||||
|
||||
/**
|
||||
* dma_resv_list_alloc - allocate fence list
|
||||
* @shared_max: number of fences we need space for
|
||||
*
|
||||
/* Mask for the lower fence pointer bits */
|
||||
#define DMA_RESV_LIST_MASK 0x3
|
||||
|
||||
struct dma_resv_list {
|
||||
struct rcu_head rcu;
|
||||
u32 num_fences, max_fences;
|
||||
struct dma_fence __rcu *table[];
|
||||
};
|
||||
|
||||
/* Extract the fence and usage flags from an RCU protected entry in the list. */
|
||||
static void dma_resv_list_entry(struct dma_resv_list *list, unsigned int index,
|
||||
struct dma_resv *resv, struct dma_fence **fence,
|
||||
enum dma_resv_usage *usage)
|
||||
{
|
||||
long tmp;
|
||||
|
||||
tmp = (long)rcu_dereference_check(list->table[index],
|
||||
resv ? dma_resv_held(resv) : true);
|
||||
*fence = (struct dma_fence *)(tmp & ~DMA_RESV_LIST_MASK);
|
||||
if (usage)
|
||||
*usage = tmp & DMA_RESV_LIST_MASK;
|
||||
}
|
||||
|
||||
/* Set the fence and usage flags at the specific index in the list. */
|
||||
static void dma_resv_list_set(struct dma_resv_list *list,
|
||||
unsigned int index,
|
||||
struct dma_fence *fence,
|
||||
enum dma_resv_usage usage)
|
||||
{
|
||||
long tmp = ((long)fence) | usage;
|
||||
|
||||
RCU_INIT_POINTER(list->table[index], (struct dma_fence *)tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new dma_resv_list and make sure to correctly initialize
|
||||
* shared_max.
|
||||
* max_fences.
|
||||
*/
|
||||
static struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max)
|
||||
static struct dma_resv_list *dma_resv_list_alloc(unsigned int max_fences)
|
||||
{
|
||||
struct dma_resv_list *list;
|
||||
|
||||
list = kmalloc(struct_size(list, shared, shared_max), GFP_KERNEL);
|
||||
list = kmalloc(struct_size(list, table, max_fences), GFP_KERNEL);
|
||||
if (!list)
|
||||
return NULL;
|
||||
|
||||
list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)) /
|
||||
sizeof(*list->shared);
|
||||
list->max_fences = (ksize(list) - offsetof(typeof(*list), table)) /
|
||||
sizeof(*list->table);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_list_free - free fence list
|
||||
* @list: list to free
|
||||
*
|
||||
* Free a dma_resv_list and make sure to drop all references.
|
||||
*/
|
||||
/* Free a dma_resv_list and make sure to drop all references. */
|
||||
static void dma_resv_list_free(struct dma_resv_list *list)
|
||||
{
|
||||
unsigned int i;
|
||||
|
|
@ -90,9 +117,12 @@ static void dma_resv_list_free(struct dma_resv_list *list)
|
|||
if (!list)
|
||||
return;
|
||||
|
||||
for (i = 0; i < list->shared_count; ++i)
|
||||
dma_fence_put(rcu_dereference_protected(list->shared[i], true));
|
||||
for (i = 0; i < list->num_fences; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_list_entry(list, i, NULL, &fence, NULL);
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
kfree_rcu(list, rcu);
|
||||
}
|
||||
|
||||
|
|
@ -103,10 +133,8 @@ static void dma_resv_list_free(struct dma_resv_list *list)
|
|||
void dma_resv_init(struct dma_resv *obj)
|
||||
{
|
||||
ww_mutex_init(&obj->lock, &reservation_ww_class);
|
||||
seqcount_ww_mutex_init(&obj->seq, &obj->lock);
|
||||
|
||||
RCU_INIT_POINTER(obj->fence, NULL);
|
||||
RCU_INIT_POINTER(obj->fence_excl, NULL);
|
||||
RCU_INIT_POINTER(obj->fences, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_init);
|
||||
|
||||
|
|
@ -116,51 +144,48 @@ EXPORT_SYMBOL(dma_resv_init);
|
|||
*/
|
||||
void dma_resv_fini(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *excl;
|
||||
|
||||
/*
|
||||
* This object should be dead and all references must have
|
||||
* been released to it, so no need to be protected with rcu.
|
||||
*/
|
||||
excl = rcu_dereference_protected(obj->fence_excl, 1);
|
||||
if (excl)
|
||||
dma_fence_put(excl);
|
||||
|
||||
fobj = rcu_dereference_protected(obj->fence, 1);
|
||||
dma_resv_list_free(fobj);
|
||||
dma_resv_list_free(rcu_dereference_protected(obj->fences, true));
|
||||
ww_mutex_destroy(&obj->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_fini);
|
||||
|
||||
/* Dereference the fences while ensuring RCU rules */
|
||||
static inline struct dma_resv_list *dma_resv_fences_list(struct dma_resv *obj)
|
||||
{
|
||||
return rcu_dereference_check(obj->fences, dma_resv_held(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_reserve_shared - Reserve space to add shared fences to
|
||||
* a dma_resv.
|
||||
* dma_resv_reserve_fences - Reserve space to add fences to a dma_resv object.
|
||||
* @obj: reservation object
|
||||
* @num_fences: number of fences we want to add
|
||||
*
|
||||
* Should be called before dma_resv_add_shared_fence(). Must
|
||||
* be called with @obj locked through dma_resv_lock().
|
||||
* Should be called before dma_resv_add_fence(). Must be called with @obj
|
||||
* locked through dma_resv_lock().
|
||||
*
|
||||
* Note that the preallocated slots need to be re-reserved if @obj is unlocked
|
||||
* at any time before calling dma_resv_add_shared_fence(). This is validated
|
||||
* when CONFIG_DEBUG_MUTEXES is enabled.
|
||||
* at any time before calling dma_resv_add_fence(). This is validated when
|
||||
* CONFIG_DEBUG_MUTEXES is enabled.
|
||||
*
|
||||
* RETURNS
|
||||
* Zero for success, or -errno
|
||||
*/
|
||||
int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
||||
int dma_resv_reserve_fences(struct dma_resv *obj, unsigned int num_fences)
|
||||
{
|
||||
struct dma_resv_list *old, *new;
|
||||
unsigned int i, j, k, max;
|
||||
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
old = dma_resv_shared_list(obj);
|
||||
if (old && old->shared_max) {
|
||||
if ((old->shared_count + num_fences) <= old->shared_max)
|
||||
old = dma_resv_fences_list(obj);
|
||||
if (old && old->max_fences) {
|
||||
if ((old->num_fences + num_fences) <= old->max_fences)
|
||||
return 0;
|
||||
max = max(old->shared_count + num_fences, old->shared_max * 2);
|
||||
max = max(old->num_fences + num_fences, old->max_fences * 2);
|
||||
} else {
|
||||
max = max(4ul, roundup_pow_of_two(num_fences));
|
||||
}
|
||||
|
|
@ -175,27 +200,27 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
|||
* references from the old struct are carried over to
|
||||
* the new.
|
||||
*/
|
||||
for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
|
||||
for (i = 0, j = 0, k = max; i < (old ? old->num_fences : 0); ++i) {
|
||||
enum dma_resv_usage usage;
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference_protected(old->shared[i],
|
||||
dma_resv_held(obj));
|
||||
dma_resv_list_entry(old, i, obj, &fence, &usage);
|
||||
if (dma_fence_is_signaled(fence))
|
||||
RCU_INIT_POINTER(new->shared[--k], fence);
|
||||
RCU_INIT_POINTER(new->table[--k], fence);
|
||||
else
|
||||
RCU_INIT_POINTER(new->shared[j++], fence);
|
||||
dma_resv_list_set(new, j++, fence, usage);
|
||||
}
|
||||
new->shared_count = j;
|
||||
new->num_fences = j;
|
||||
|
||||
/*
|
||||
* We are not changing the effective set of fences here so can
|
||||
* merely update the pointer to the new array; both existing
|
||||
* readers and new readers will see exactly the same set of
|
||||
* active (unsignaled) shared fences. Individual fences and the
|
||||
* active (unsignaled) fences. Individual fences and the
|
||||
* old array are protected by RCU and so will not vanish under
|
||||
* the gaze of the rcu_read_lock() readers.
|
||||
*/
|
||||
rcu_assign_pointer(obj->fence, new);
|
||||
rcu_assign_pointer(obj->fences, new);
|
||||
|
||||
if (!old)
|
||||
return 0;
|
||||
|
|
@ -204,7 +229,7 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
|||
for (i = k; i < max; ++i) {
|
||||
struct dma_fence *fence;
|
||||
|
||||
fence = rcu_dereference_protected(new->shared[i],
|
||||
fence = rcu_dereference_protected(new->table[i],
|
||||
dma_resv_held(obj));
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
|
|
@ -212,41 +237,43 @@ int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_reserve_shared);
|
||||
EXPORT_SYMBOL(dma_resv_reserve_fences);
|
||||
|
||||
#ifdef CONFIG_DEBUG_MUTEXES
|
||||
/**
|
||||
* dma_resv_reset_shared_max - reset shared fences for debugging
|
||||
* dma_resv_reset_max_fences - reset fences for debugging
|
||||
* @obj: the dma_resv object to reset
|
||||
*
|
||||
* Reset the number of pre-reserved shared slots to test that drivers do
|
||||
* correct slot allocation using dma_resv_reserve_shared(). See also
|
||||
* &dma_resv_list.shared_max.
|
||||
* Reset the number of pre-reserved fence slots to test that drivers do
|
||||
* correct slot allocation using dma_resv_reserve_fences(). See also
|
||||
* &dma_resv_list.max_fences.
|
||||
*/
|
||||
void dma_resv_reset_shared_max(struct dma_resv *obj)
|
||||
void dma_resv_reset_max_fences(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_resv_list *fences = dma_resv_shared_list(obj);
|
||||
struct dma_resv_list *fences = dma_resv_fences_list(obj);
|
||||
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
/* Test shared fence slot reservation */
|
||||
/* Test fence slot reservation */
|
||||
if (fences)
|
||||
fences->shared_max = fences->shared_count;
|
||||
fences->max_fences = fences->num_fences;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_reset_shared_max);
|
||||
EXPORT_SYMBOL(dma_resv_reset_max_fences);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dma_resv_add_shared_fence - Add a fence to a shared slot
|
||||
* dma_resv_add_fence - Add a fence to the dma_resv obj
|
||||
* @obj: the reservation object
|
||||
* @fence: the shared fence to add
|
||||
* @fence: the fence to add
|
||||
* @usage: how the fence is used, see enum dma_resv_usage
|
||||
*
|
||||
* Add a fence to a shared slot, @obj must be locked with dma_resv_lock(), and
|
||||
* dma_resv_reserve_shared() has been called.
|
||||
* Add a fence to a slot, @obj must be locked with dma_resv_lock(), and
|
||||
* dma_resv_reserve_fences() has been called.
|
||||
*
|
||||
* See also &dma_resv.fence for a discussion of the semantics.
|
||||
*/
|
||||
void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
void dma_resv_add_fence(struct dma_resv *obj, struct dma_fence *fence,
|
||||
enum dma_resv_usage usage)
|
||||
{
|
||||
struct dma_resv_list *fobj;
|
||||
struct dma_fence *old;
|
||||
|
|
@ -261,118 +288,105 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
|
|||
*/
|
||||
WARN_ON(dma_fence_is_container(fence));
|
||||
|
||||
fobj = dma_resv_shared_list(obj);
|
||||
count = fobj->shared_count;
|
||||
|
||||
write_seqcount_begin(&obj->seq);
|
||||
fobj = dma_resv_fences_list(obj);
|
||||
count = fobj->num_fences;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
enum dma_resv_usage old_usage;
|
||||
|
||||
old = rcu_dereference_protected(fobj->shared[i],
|
||||
dma_resv_held(obj));
|
||||
if (old->context == fence->context ||
|
||||
dma_fence_is_signaled(old))
|
||||
goto replace;
|
||||
dma_resv_list_entry(fobj, i, obj, &old, &old_usage);
|
||||
if ((old->context == fence->context && old_usage >= usage) ||
|
||||
dma_fence_is_signaled(old)) {
|
||||
dma_resv_list_set(fobj, i, fence, usage);
|
||||
dma_fence_put(old);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BUG_ON(fobj->shared_count >= fobj->shared_max);
|
||||
old = NULL;
|
||||
BUG_ON(fobj->num_fences >= fobj->max_fences);
|
||||
count++;
|
||||
|
||||
replace:
|
||||
RCU_INIT_POINTER(fobj->shared[i], fence);
|
||||
/* pointer update must be visible before we extend the shared_count */
|
||||
smp_store_mb(fobj->shared_count, count);
|
||||
|
||||
write_seqcount_end(&obj->seq);
|
||||
dma_fence_put(old);
|
||||
dma_resv_list_set(fobj, i, fence, usage);
|
||||
/* pointer update must be visible before we extend the num_fences */
|
||||
smp_store_mb(fobj->num_fences, count);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_add_shared_fence);
|
||||
EXPORT_SYMBOL(dma_resv_add_fence);
|
||||
|
||||
/**
|
||||
* dma_resv_add_excl_fence - Add an exclusive fence.
|
||||
* dma_resv_replace_fences - replace fences in the dma_resv obj
|
||||
* @obj: the reservation object
|
||||
* @fence: the exclusive fence to add
|
||||
* @context: the context of the fences to replace
|
||||
* @replacement: the new fence to use instead
|
||||
* @usage: how the new fence is used, see enum dma_resv_usage
|
||||
*
|
||||
* Add a fence to the exclusive slot. @obj must be locked with dma_resv_lock().
|
||||
* Note that this function replaces all fences attached to @obj, see also
|
||||
* &dma_resv.fence_excl for a discussion of the semantics.
|
||||
* Replace fences with a specified context with a new fence. Only valid if the
|
||||
* operation represented by the original fence has no longer access to the
|
||||
* resources represented by the dma_resv object when the new fence completes.
|
||||
*
|
||||
* And example for using this is replacing a preemption fence with a page table
|
||||
* update fence which makes the resource inaccessible.
|
||||
*/
|
||||
void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
|
||||
void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,
|
||||
struct dma_fence *replacement,
|
||||
enum dma_resv_usage usage)
|
||||
{
|
||||
struct dma_fence *old_fence = dma_resv_excl_fence(obj);
|
||||
struct dma_resv_list *old;
|
||||
u32 i = 0;
|
||||
struct dma_resv_list *list;
|
||||
unsigned int i;
|
||||
|
||||
dma_resv_assert_held(obj);
|
||||
|
||||
old = dma_resv_shared_list(obj);
|
||||
if (old)
|
||||
i = old->shared_count;
|
||||
list = dma_resv_fences_list(obj);
|
||||
for (i = 0; list && i < list->num_fences; ++i) {
|
||||
struct dma_fence *old;
|
||||
|
||||
dma_fence_get(fence);
|
||||
dma_resv_list_entry(list, i, obj, &old, NULL);
|
||||
if (old->context != context)
|
||||
continue;
|
||||
|
||||
write_seqcount_begin(&obj->seq);
|
||||
/* write_seqcount_begin provides the necessary memory barrier */
|
||||
RCU_INIT_POINTER(obj->fence_excl, fence);
|
||||
if (old)
|
||||
old->shared_count = 0;
|
||||
write_seqcount_end(&obj->seq);
|
||||
|
||||
/* inplace update, no shared fences */
|
||||
while (i--)
|
||||
dma_fence_put(rcu_dereference_protected(old->shared[i],
|
||||
dma_resv_held(obj)));
|
||||
|
||||
dma_fence_put(old_fence);
|
||||
dma_resv_list_set(list, i, replacement, usage);
|
||||
dma_fence_put(old);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_add_excl_fence);
|
||||
EXPORT_SYMBOL(dma_resv_replace_fences);
|
||||
|
||||
/* Restart the iterator by initializing all the necessary fields, but not the
|
||||
* relation to the dma_resv object. */
|
||||
/* Restart the unlocked iteration by initializing the cursor object. */
|
||||
static void dma_resv_iter_restart_unlocked(struct dma_resv_iter *cursor)
|
||||
{
|
||||
cursor->seq = read_seqcount_begin(&cursor->obj->seq);
|
||||
cursor->index = -1;
|
||||
cursor->shared_count = 0;
|
||||
if (cursor->all_fences) {
|
||||
cursor->fences = dma_resv_shared_list(cursor->obj);
|
||||
if (cursor->fences)
|
||||
cursor->shared_count = cursor->fences->shared_count;
|
||||
} else {
|
||||
cursor->fences = NULL;
|
||||
}
|
||||
cursor->index = 0;
|
||||
cursor->num_fences = 0;
|
||||
cursor->fences = dma_resv_fences_list(cursor->obj);
|
||||
if (cursor->fences)
|
||||
cursor->num_fences = cursor->fences->num_fences;
|
||||
cursor->is_restarted = true;
|
||||
}
|
||||
|
||||
/* Walk to the next not signaled fence and grab a reference to it */
|
||||
static void dma_resv_iter_walk_unlocked(struct dma_resv_iter *cursor)
|
||||
{
|
||||
struct dma_resv *obj = cursor->obj;
|
||||
if (!cursor->fences)
|
||||
return;
|
||||
|
||||
do {
|
||||
/* Drop the reference from the previous round */
|
||||
dma_fence_put(cursor->fence);
|
||||
|
||||
if (cursor->index == -1) {
|
||||
cursor->fence = dma_resv_excl_fence(obj);
|
||||
cursor->index++;
|
||||
if (!cursor->fence)
|
||||
continue;
|
||||
|
||||
} else if (!cursor->fences ||
|
||||
cursor->index >= cursor->shared_count) {
|
||||
if (cursor->index >= cursor->num_fences) {
|
||||
cursor->fence = NULL;
|
||||
break;
|
||||
|
||||
} else {
|
||||
struct dma_resv_list *fences = cursor->fences;
|
||||
unsigned int idx = cursor->index++;
|
||||
|
||||
cursor->fence = rcu_dereference(fences->shared[idx]);
|
||||
}
|
||||
|
||||
dma_resv_list_entry(cursor->fences, cursor->index++,
|
||||
cursor->obj, &cursor->fence,
|
||||
&cursor->fence_usage);
|
||||
cursor->fence = dma_fence_get_rcu(cursor->fence);
|
||||
if (!cursor->fence || !dma_fence_is_signaled(cursor->fence))
|
||||
if (!cursor->fence) {
|
||||
dma_resv_iter_restart_unlocked(cursor);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!dma_fence_is_signaled(cursor->fence) &&
|
||||
cursor->usage >= cursor->fence_usage)
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
|
|
@ -395,7 +409,7 @@ struct dma_fence *dma_resv_iter_first_unlocked(struct dma_resv_iter *cursor)
|
|||
do {
|
||||
dma_resv_iter_restart_unlocked(cursor);
|
||||
dma_resv_iter_walk_unlocked(cursor);
|
||||
} while (read_seqcount_retry(&cursor->obj->seq, cursor->seq));
|
||||
} while (dma_resv_fences_list(cursor->obj) != cursor->fences);
|
||||
rcu_read_unlock();
|
||||
|
||||
return cursor->fence;
|
||||
|
|
@ -418,13 +432,13 @@ struct dma_fence *dma_resv_iter_next_unlocked(struct dma_resv_iter *cursor)
|
|||
|
||||
rcu_read_lock();
|
||||
cursor->is_restarted = false;
|
||||
restart = read_seqcount_retry(&cursor->obj->seq, cursor->seq);
|
||||
restart = dma_resv_fences_list(cursor->obj) != cursor->fences;
|
||||
do {
|
||||
if (restart)
|
||||
dma_resv_iter_restart_unlocked(cursor);
|
||||
dma_resv_iter_walk_unlocked(cursor);
|
||||
restart = true;
|
||||
} while (read_seqcount_retry(&cursor->obj->seq, cursor->seq));
|
||||
} while (dma_resv_fences_list(cursor->obj) != cursor->fences);
|
||||
rcu_read_unlock();
|
||||
|
||||
return cursor->fence;
|
||||
|
|
@ -447,15 +461,9 @@ struct dma_fence *dma_resv_iter_first(struct dma_resv_iter *cursor)
|
|||
dma_resv_assert_held(cursor->obj);
|
||||
|
||||
cursor->index = 0;
|
||||
if (cursor->all_fences)
|
||||
cursor->fences = dma_resv_shared_list(cursor->obj);
|
||||
else
|
||||
cursor->fences = NULL;
|
||||
|
||||
fence = dma_resv_excl_fence(cursor->obj);
|
||||
if (!fence)
|
||||
fence = dma_resv_iter_next(cursor);
|
||||
cursor->fences = dma_resv_fences_list(cursor->obj);
|
||||
|
||||
fence = dma_resv_iter_next(cursor);
|
||||
cursor->is_restarted = true;
|
||||
return fence;
|
||||
}
|
||||
|
|
@ -470,17 +478,22 @@ EXPORT_SYMBOL_GPL(dma_resv_iter_first);
|
|||
*/
|
||||
struct dma_fence *dma_resv_iter_next(struct dma_resv_iter *cursor)
|
||||
{
|
||||
unsigned int idx;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_assert_held(cursor->obj);
|
||||
|
||||
cursor->is_restarted = false;
|
||||
if (!cursor->fences || cursor->index >= cursor->fences->shared_count)
|
||||
return NULL;
|
||||
|
||||
idx = cursor->index++;
|
||||
return rcu_dereference_protected(cursor->fences->shared[idx],
|
||||
dma_resv_held(cursor->obj));
|
||||
do {
|
||||
if (!cursor->fences ||
|
||||
cursor->index >= cursor->fences->num_fences)
|
||||
return NULL;
|
||||
|
||||
dma_resv_list_entry(cursor->fences, cursor->index++,
|
||||
cursor->obj, &fence, &cursor->fence_usage);
|
||||
} while (cursor->fence_usage > cursor->usage);
|
||||
|
||||
return fence;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_resv_iter_next);
|
||||
|
||||
|
|
@ -495,60 +508,43 @@ int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
|
|||
{
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_resv_list *list;
|
||||
struct dma_fence *f, *excl;
|
||||
struct dma_fence *f;
|
||||
|
||||
dma_resv_assert_held(dst);
|
||||
|
||||
list = NULL;
|
||||
excl = NULL;
|
||||
|
||||
dma_resv_iter_begin(&cursor, src, true);
|
||||
dma_resv_iter_begin(&cursor, src, DMA_RESV_USAGE_BOOKKEEP);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, f) {
|
||||
|
||||
if (dma_resv_iter_is_restarted(&cursor)) {
|
||||
dma_resv_list_free(list);
|
||||
dma_fence_put(excl);
|
||||
|
||||
if (cursor.shared_count) {
|
||||
list = dma_resv_list_alloc(cursor.shared_count);
|
||||
if (!list) {
|
||||
dma_resv_iter_end(&cursor);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
list->shared_count = 0;
|
||||
|
||||
} else {
|
||||
list = NULL;
|
||||
list = dma_resv_list_alloc(cursor.num_fences);
|
||||
if (!list) {
|
||||
dma_resv_iter_end(&cursor);
|
||||
return -ENOMEM;
|
||||
}
|
||||
excl = NULL;
|
||||
list->num_fences = 0;
|
||||
}
|
||||
|
||||
dma_fence_get(f);
|
||||
if (dma_resv_iter_is_exclusive(&cursor))
|
||||
excl = f;
|
||||
else
|
||||
RCU_INIT_POINTER(list->shared[list->shared_count++], f);
|
||||
dma_resv_list_set(list, list->num_fences++, f,
|
||||
dma_resv_iter_usage(&cursor));
|
||||
}
|
||||
dma_resv_iter_end(&cursor);
|
||||
|
||||
write_seqcount_begin(&dst->seq);
|
||||
excl = rcu_replace_pointer(dst->fence_excl, excl, dma_resv_held(dst));
|
||||
list = rcu_replace_pointer(dst->fence, list, dma_resv_held(dst));
|
||||
write_seqcount_end(&dst->seq);
|
||||
|
||||
list = rcu_replace_pointer(dst->fences, list, dma_resv_held(dst));
|
||||
dma_resv_list_free(list);
|
||||
dma_fence_put(excl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_resv_copy_fences);
|
||||
|
||||
/**
|
||||
* dma_resv_get_fences - Get an object's shared and exclusive
|
||||
* dma_resv_get_fences - Get an object's fences
|
||||
* fences without update side lock held
|
||||
* @obj: the reservation object
|
||||
* @write: true if we should return all fences
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
* @num_fences: the number of fences returned
|
||||
* @fences: the array of fence ptrs returned (array is krealloc'd to the
|
||||
* required size, and must be freed by caller)
|
||||
|
|
@ -556,7 +552,7 @@ EXPORT_SYMBOL(dma_resv_copy_fences);
|
|||
* Retrieve all fences from the reservation object.
|
||||
* Returns either zero or -ENOMEM.
|
||||
*/
|
||||
int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
||||
int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage,
|
||||
unsigned int *num_fences, struct dma_fence ***fences)
|
||||
{
|
||||
struct dma_resv_iter cursor;
|
||||
|
|
@ -565,7 +561,7 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
|||
*num_fences = 0;
|
||||
*fences = NULL;
|
||||
|
||||
dma_resv_iter_begin(&cursor, obj, write);
|
||||
dma_resv_iter_begin(&cursor, obj, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
|
||||
if (dma_resv_iter_is_restarted(&cursor)) {
|
||||
|
|
@ -574,7 +570,7 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
|||
while (*num_fences)
|
||||
dma_fence_put((*fences)[--(*num_fences)]);
|
||||
|
||||
count = cursor.shared_count + 1;
|
||||
count = cursor.num_fences + 1;
|
||||
|
||||
/* Eventually re-allocate the array */
|
||||
*fences = krealloc_array(*fences, count,
|
||||
|
|
@ -595,10 +591,62 @@ int dma_resv_get_fences(struct dma_resv *obj, bool write,
|
|||
EXPORT_SYMBOL_GPL(dma_resv_get_fences);
|
||||
|
||||
/**
|
||||
* dma_resv_wait_timeout - Wait on reservation's objects
|
||||
* shared and/or exclusive fences.
|
||||
* dma_resv_get_singleton - Get a single fence for all the fences
|
||||
* @obj: the reservation object
|
||||
* @wait_all: if true, wait on all fences, else wait on just exclusive fence
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
* @fence: the resulting fence
|
||||
*
|
||||
* Get a single fence representing all the fences inside the resv object.
|
||||
* Returns either 0 for success or -ENOMEM.
|
||||
*
|
||||
* Warning: This can't be used like this when adding the fence back to the resv
|
||||
* object since that can lead to stack corruption when finalizing the
|
||||
* dma_fence_array.
|
||||
*
|
||||
* Returns 0 on success and negative error values on failure.
|
||||
*/
|
||||
int dma_resv_get_singleton(struct dma_resv *obj, enum dma_resv_usage usage,
|
||||
struct dma_fence **fence)
|
||||
{
|
||||
struct dma_fence_array *array;
|
||||
struct dma_fence **fences;
|
||||
unsigned count;
|
||||
int r;
|
||||
|
||||
r = dma_resv_get_fences(obj, usage, &count, &fences);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (count == 0) {
|
||||
*fence = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
*fence = fences[0];
|
||||
kfree(fences);
|
||||
return 0;
|
||||
}
|
||||
|
||||
array = dma_fence_array_create(count, fences,
|
||||
dma_fence_context_alloc(1),
|
||||
1, false);
|
||||
if (!array) {
|
||||
while (count--)
|
||||
dma_fence_put(fences[count]);
|
||||
kfree(fences);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*fence = &array->base;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_resv_get_singleton);
|
||||
|
||||
/**
|
||||
* dma_resv_wait_timeout - Wait on reservation's objects fences
|
||||
* @obj: the reservation object
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
* @intr: if true, do interruptible wait
|
||||
* @timeout: timeout value in jiffies or zero to return immediately
|
||||
*
|
||||
|
|
@ -608,14 +656,14 @@ EXPORT_SYMBOL_GPL(dma_resv_get_fences);
|
|||
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
|
||||
* greater than zer on success.
|
||||
*/
|
||||
long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr,
|
||||
unsigned long timeout)
|
||||
long dma_resv_wait_timeout(struct dma_resv *obj, enum dma_resv_usage usage,
|
||||
bool intr, unsigned long timeout)
|
||||
{
|
||||
long ret = timeout ? timeout : 1;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_iter_begin(&cursor, obj, wait_all);
|
||||
dma_resv_iter_begin(&cursor, obj, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
|
||||
ret = dma_fence_wait_timeout(fence, intr, ret);
|
||||
|
|
@ -635,8 +683,7 @@ EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
|
|||
* dma_resv_test_signaled - Test if a reservation object's fences have been
|
||||
* signaled.
|
||||
* @obj: the reservation object
|
||||
* @test_all: if true, test all fences, otherwise only test the exclusive
|
||||
* fence
|
||||
* @usage: controls which fences to include, see enum dma_resv_usage.
|
||||
*
|
||||
* Callers are not required to hold specific locks, but maybe hold
|
||||
* dma_resv_lock() already.
|
||||
|
|
@ -645,12 +692,12 @@ EXPORT_SYMBOL_GPL(dma_resv_wait_timeout);
|
|||
*
|
||||
* True if all fences signaled, else false.
|
||||
*/
|
||||
bool dma_resv_test_signaled(struct dma_resv *obj, bool test_all)
|
||||
bool dma_resv_test_signaled(struct dma_resv *obj, enum dma_resv_usage usage)
|
||||
{
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_iter_begin(&cursor, obj, test_all);
|
||||
dma_resv_iter_begin(&cursor, obj, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
dma_resv_iter_end(&cursor);
|
||||
return false;
|
||||
|
|
@ -670,13 +717,13 @@ EXPORT_SYMBOL_GPL(dma_resv_test_signaled);
|
|||
*/
|
||||
void dma_resv_describe(struct dma_resv *obj, struct seq_file *seq)
|
||||
{
|
||||
static const char *usage[] = { "kernel", "write", "read", "bookkeep" };
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
dma_resv_for_each_fence(&cursor, obj, true, fence) {
|
||||
dma_resv_for_each_fence(&cursor, obj, DMA_RESV_USAGE_READ, fence) {
|
||||
seq_printf(seq, "\t%s fence:",
|
||||
dma_resv_iter_is_exclusive(&cursor) ?
|
||||
"Exclusive" : "Shared");
|
||||
usage[dma_resv_iter_usage(&cursor)]);
|
||||
dma_fence_describe(fence, seq);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,9 @@ static int sanitycheck(void *arg)
|
|||
return r;
|
||||
}
|
||||
|
||||
static int test_signaling(void *arg, bool shared)
|
||||
static int test_signaling(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_resv resv;
|
||||
struct dma_fence *f;
|
||||
int r;
|
||||
|
|
@ -75,25 +76,20 @@ static int test_signaling(void *arg, bool shared)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
if (dma_resv_test_signaled(&resv, shared)) {
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
if (dma_resv_test_signaled(&resv, usage)) {
|
||||
pr_err("Resv unexpectedly signaled\n");
|
||||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
}
|
||||
dma_fence_signal(f);
|
||||
if (!dma_resv_test_signaled(&resv, shared)) {
|
||||
if (!dma_resv_test_signaled(&resv, usage)) {
|
||||
pr_err("Resv not reporting signaled\n");
|
||||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
|
|
@ -106,18 +102,9 @@ err_free:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_signaling(void *arg)
|
||||
{
|
||||
return test_signaling(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_signaling(void *arg)
|
||||
{
|
||||
return test_signaling(arg, true);
|
||||
}
|
||||
|
||||
static int test_for_each(void *arg, bool shared)
|
||||
static int test_for_each(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *f, *fence;
|
||||
struct dma_resv resv;
|
||||
|
|
@ -134,20 +121,16 @@ static int test_for_each(void *arg, bool shared)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
|
||||
r = -ENOENT;
|
||||
dma_resv_for_each_fence(&cursor, &resv, shared, fence) {
|
||||
dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
|
||||
if (!r) {
|
||||
pr_err("More than one fence found\n");
|
||||
r = -EINVAL;
|
||||
|
|
@ -158,7 +141,7 @@ static int test_for_each(void *arg, bool shared)
|
|||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
}
|
||||
if (dma_resv_iter_is_exclusive(&cursor) != !shared) {
|
||||
if (dma_resv_iter_usage(&cursor) != usage) {
|
||||
pr_err("Unexpected fence usage\n");
|
||||
r = -EINVAL;
|
||||
goto err_unlock;
|
||||
|
|
@ -178,18 +161,9 @@ err_free:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_for_each(void *arg)
|
||||
{
|
||||
return test_for_each(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_for_each(void *arg)
|
||||
{
|
||||
return test_for_each(arg, true);
|
||||
}
|
||||
|
||||
static int test_for_each_unlocked(void *arg, bool shared)
|
||||
static int test_for_each_unlocked(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *f, *fence;
|
||||
struct dma_resv resv;
|
||||
|
|
@ -206,22 +180,18 @@ static int test_for_each_unlocked(void *arg, bool shared)
|
|||
goto err_free;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
dma_resv_unlock(&resv);
|
||||
|
||||
r = -ENOENT;
|
||||
dma_resv_iter_begin(&cursor, &resv, shared);
|
||||
dma_resv_iter_begin(&cursor, &resv, usage);
|
||||
dma_resv_for_each_fence_unlocked(&cursor, fence) {
|
||||
if (!r) {
|
||||
pr_err("More than one fence found\n");
|
||||
|
|
@ -237,7 +207,7 @@ static int test_for_each_unlocked(void *arg, bool shared)
|
|||
r = -EINVAL;
|
||||
goto err_iter_end;
|
||||
}
|
||||
if (dma_resv_iter_is_exclusive(&cursor) != !shared) {
|
||||
if (dma_resv_iter_usage(&cursor) != usage) {
|
||||
pr_err("Unexpected fence usage\n");
|
||||
r = -EINVAL;
|
||||
goto err_iter_end;
|
||||
|
|
@ -247,7 +217,7 @@ static int test_for_each_unlocked(void *arg, bool shared)
|
|||
if (r == -ENOENT) {
|
||||
r = -EINVAL;
|
||||
/* That should trigger an restart */
|
||||
cursor.seq--;
|
||||
cursor.fences = (void*)~0;
|
||||
} else if (r == -EINVAL) {
|
||||
r = 0;
|
||||
}
|
||||
|
|
@ -263,18 +233,9 @@ err_free:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_for_each_unlocked(void *arg)
|
||||
{
|
||||
return test_for_each_unlocked(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_for_each_unlocked(void *arg)
|
||||
{
|
||||
return test_for_each_unlocked(arg, true);
|
||||
}
|
||||
|
||||
static int test_get_fences(void *arg, bool shared)
|
||||
static int test_get_fences(void *arg)
|
||||
{
|
||||
enum dma_resv_usage usage = (unsigned long)arg;
|
||||
struct dma_fence *f, **fences = NULL;
|
||||
struct dma_resv resv;
|
||||
int r, i;
|
||||
|
|
@ -290,21 +251,17 @@ static int test_get_fences(void *arg, bool shared)
|
|||
goto err_resv;
|
||||
}
|
||||
|
||||
if (shared) {
|
||||
r = dma_resv_reserve_shared(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_resv;
|
||||
}
|
||||
|
||||
dma_resv_add_shared_fence(&resv, f);
|
||||
} else {
|
||||
dma_resv_add_excl_fence(&resv, f);
|
||||
r = dma_resv_reserve_fences(&resv, 1);
|
||||
if (r) {
|
||||
pr_err("Resv shared slot allocation failed\n");
|
||||
dma_resv_unlock(&resv);
|
||||
goto err_resv;
|
||||
}
|
||||
|
||||
dma_resv_add_fence(&resv, f, usage);
|
||||
dma_resv_unlock(&resv);
|
||||
|
||||
r = dma_resv_get_fences(&resv, shared, &i, &fences);
|
||||
r = dma_resv_get_fences(&resv, usage, &i, &fences);
|
||||
if (r) {
|
||||
pr_err("get_fences failed\n");
|
||||
goto err_free;
|
||||
|
|
@ -326,30 +283,24 @@ err_resv:
|
|||
return r;
|
||||
}
|
||||
|
||||
static int test_excl_get_fences(void *arg)
|
||||
{
|
||||
return test_get_fences(arg, false);
|
||||
}
|
||||
|
||||
static int test_shared_get_fences(void *arg)
|
||||
{
|
||||
return test_get_fences(arg, true);
|
||||
}
|
||||
|
||||
int dma_resv(void)
|
||||
{
|
||||
static const struct subtest tests[] = {
|
||||
SUBTEST(sanitycheck),
|
||||
SUBTEST(test_excl_signaling),
|
||||
SUBTEST(test_shared_signaling),
|
||||
SUBTEST(test_excl_for_each),
|
||||
SUBTEST(test_shared_for_each),
|
||||
SUBTEST(test_excl_for_each_unlocked),
|
||||
SUBTEST(test_shared_for_each_unlocked),
|
||||
SUBTEST(test_excl_get_fences),
|
||||
SUBTEST(test_shared_get_fences),
|
||||
SUBTEST(test_signaling),
|
||||
SUBTEST(test_for_each),
|
||||
SUBTEST(test_for_each_unlocked),
|
||||
SUBTEST(test_get_fences),
|
||||
};
|
||||
enum dma_resv_usage usage;
|
||||
int r;
|
||||
|
||||
spin_lock_init(&fence_lock);
|
||||
return subtests(tests, NULL);
|
||||
for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
|
||||
++usage) {
|
||||
r = subtests(tests, (void *)(unsigned long)usage);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,9 +157,15 @@ static int sync_file_set_fence(struct sync_file *sync_file,
|
|||
* we already own a new reference to the fence. For num_fence > 1
|
||||
* we own the reference of the dma_fence_array creation.
|
||||
*/
|
||||
if (num_fences == 1) {
|
||||
|
||||
if (num_fences == 0) {
|
||||
sync_file->fence = dma_fence_get_stub();
|
||||
kfree(fences);
|
||||
|
||||
} else if (num_fences == 1) {
|
||||
sync_file->fence = fences[0];
|
||||
kfree(fences);
|
||||
|
||||
} else {
|
||||
array = dma_fence_array_create(num_fences, fences,
|
||||
dma_fence_context_alloc(1),
|
||||
|
|
@ -261,19 +267,6 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
|
|||
}
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
fences[index++] = dma_fence_get_stub();
|
||||
|
||||
if (num_fences > index) {
|
||||
struct dma_fence **tmp;
|
||||
|
||||
/* Keep going even when reducing the size failed */
|
||||
tmp = krealloc_array(fences, index, sizeof(*fences),
|
||||
GFP_KERNEL);
|
||||
if (tmp)
|
||||
fences = tmp;
|
||||
}
|
||||
|
||||
if (sync_file_set_fence(sync_file, fences, index) < 0)
|
||||
goto err_put_fences;
|
||||
|
||||
|
|
|
|||
|
|
@ -219,12 +219,12 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
|
|||
|
||||
config SYSFB
|
||||
bool
|
||||
default y
|
||||
depends on X86 || EFI
|
||||
select BOOT_VESA_SUPPORT
|
||||
|
||||
config SYSFB_SIMPLEFB
|
||||
bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
|
||||
depends on SYSFB
|
||||
depends on X86 || EFI
|
||||
select SYSFB
|
||||
help
|
||||
Firmwares often provide initial graphics framebuffers so the BIOS,
|
||||
bootloader or kernel can show basic video-output during boot for
|
||||
|
|
|
|||
|
|
@ -36,19 +36,6 @@ config DRM_MIPI_DSI
|
|||
bool
|
||||
depends on DRM
|
||||
|
||||
config DRM_DP_AUX_BUS
|
||||
tristate
|
||||
depends on DRM
|
||||
depends on OF
|
||||
|
||||
config DRM_DP_AUX_CHARDEV
|
||||
bool "DRM DP AUX Interface"
|
||||
depends on DRM
|
||||
help
|
||||
Choose this option to enable a /dev/drm_dp_auxN node that allows to
|
||||
read and write values to arbitrary DPCD registers on the DP aux
|
||||
channel.
|
||||
|
||||
config DRM_DEBUG_MM
|
||||
bool "Insert extra checks and debug info into the DRM range managers"
|
||||
default n
|
||||
|
|
@ -68,7 +55,8 @@ config DRM_DEBUG_SELFTEST
|
|||
depends on DRM
|
||||
depends on DEBUG_KERNEL
|
||||
select PRIME_NUMBERS
|
||||
select DRM_DP_HELPER
|
||||
select DRM_DISPLAY_DP_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_LIB_RANDOM
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_BUDDY
|
||||
|
|
@ -82,12 +70,6 @@ config DRM_DEBUG_SELFTEST
|
|||
|
||||
If in doubt, say "N".
|
||||
|
||||
config DRM_DP_HELPER
|
||||
tristate
|
||||
depends on DRM
|
||||
help
|
||||
DRM helpers for DisplayPort.
|
||||
|
||||
config DRM_KMS_HELPER
|
||||
tristate
|
||||
depends on DRM
|
||||
|
|
@ -187,16 +169,7 @@ config DRM_LOAD_EDID_FIRMWARE
|
|||
default case is N. Details and instructions how to build your own
|
||||
EDID data are given in Documentation/admin-guide/edid.rst.
|
||||
|
||||
config DRM_DP_CEC
|
||||
bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support"
|
||||
depends on DRM
|
||||
select CEC_CORE
|
||||
help
|
||||
Choose this option if you want to enable HDMI CEC support for
|
||||
DisplayPort/USB-C to HDMI adapters.
|
||||
|
||||
Note: not all adapters support this feature, and even for those
|
||||
that do support this they often do not hook up the CEC pin.
|
||||
source "drivers/gpu/drm/display/Kconfig"
|
||||
|
||||
config DRM_TTM
|
||||
tristate
|
||||
|
|
@ -250,7 +223,8 @@ config DRM_RADEON
|
|||
depends on DRM && PCI && MMU
|
||||
depends on AGP || !AGP
|
||||
select FW_LOADER
|
||||
select DRM_DP_HELPER
|
||||
select DRM_DISPLAY_DP_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_TTM
|
||||
select DRM_TTM_HELPER
|
||||
|
|
@ -271,7 +245,9 @@ config DRM_AMDGPU
|
|||
tristate "AMD GPU"
|
||||
depends on DRM && PCI && MMU
|
||||
select FW_LOADER
|
||||
select DRM_DP_HELPER
|
||||
select DRM_DISPLAY_DP_HELPER
|
||||
select DRM_DISPLAY_HDMI_HELPER
|
||||
select DRM_DISPLAY_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_SCHED
|
||||
select DRM_TTM
|
||||
|
|
@ -280,6 +256,7 @@ config DRM_AMDGPU
|
|||
select HWMON
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select INTERVAL_TREE
|
||||
select DRM_BUDDY
|
||||
help
|
||||
Choose this option if you have a recent AMD Radeon graphics card.
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ drm-y := drm_aperture.o drm_auth.o drm_cache.o \
|
|||
drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \
|
||||
drm_client_modeset.o drm_atomic_uapi.o \
|
||||
drm_managed.o drm_vblank_work.o
|
||||
|
||||
drm-$(CONFIG_DRM_LEGACY) += drm_agpsupport.o drm_bufs.o drm_context.o drm_dma.o \
|
||||
drm_hashtab.o drm_irq.o drm_legacy_misc.o drm_lock.o \
|
||||
drm_memory.o drm_scatter.o drm_vm.o
|
||||
|
|
@ -30,8 +29,16 @@ drm-$(CONFIG_PCI) += drm_pci.o
|
|||
drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o
|
||||
drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
|
||||
drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
|
||||
obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o
|
||||
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
|
||||
|
||||
#
|
||||
# Memory-management helpers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o
|
||||
|
||||
drm_cma_helper-y := drm_gem_cma_helper.o
|
||||
drm_cma_helper-$(CONFIG_DRM_KMS_HELPER) += drm_fb_cma_helper.o
|
||||
|
|
@ -40,36 +47,40 @@ obj-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_cma_helper.o
|
|||
drm_shmem_helper-y := drm_gem_shmem_helper.o
|
||||
obj-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_shmem_helper.o
|
||||
|
||||
obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o
|
||||
|
||||
drm_vram_helper-y := drm_gem_vram_helper.o
|
||||
obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
|
||||
|
||||
drm_ttm_helper-y := drm_gem_ttm_helper.o
|
||||
obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
|
||||
|
||||
#
|
||||
# Modesetting helpers
|
||||
#
|
||||
|
||||
drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \
|
||||
drm_dsc.o drm_encoder_slave.o drm_flip_work.o drm_hdcp.o \
|
||||
drm_encoder_slave.o drm_flip_work.o \
|
||||
drm_probe_helper.o \
|
||||
drm_plane_helper.o drm_atomic_helper.o \
|
||||
drm_kms_helper_common.o \
|
||||
drm_simple_kms_helper.o drm_modeset_helper.o \
|
||||
drm_scdc_helper.o drm_gem_atomic_helper.o \
|
||||
drm_gem_atomic_helper.o \
|
||||
drm_gem_framebuffer_helper.o \
|
||||
drm_atomic_state_helper.o drm_damage_helper.o \
|
||||
drm_format_helper.o drm_self_refresh_helper.o drm_rect.o
|
||||
drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
|
||||
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
|
||||
|
||||
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
|
||||
|
||||
#
|
||||
# Drivers and the rest
|
||||
#
|
||||
|
||||
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
|
||||
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
|
||||
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
|
||||
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
|
||||
obj-y += arm/
|
||||
obj-y += dp/
|
||||
obj-y += display/
|
||||
obj-$(CONFIG_DRM_TTM) += ttm/
|
||||
obj-$(CONFIG_DRM_SCHED) += scheduler/
|
||||
obj-$(CONFIG_DRM_TDFX) += tdfx/
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
|
|||
amdgpu_cs.o amdgpu_bios.o amdgpu_benchmark.o \
|
||||
atombios_dp.o amdgpu_afmt.o amdgpu_trace_points.o \
|
||||
atombios_encoders.o amdgpu_sa.o atombios_i2c.o \
|
||||
amdgpu_dma_buf.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \
|
||||
amdgpu_dma_buf.o amdgpu_vm.o amdgpu_vm_pt.o amdgpu_ib.o amdgpu_pll.o \
|
||||
amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \
|
||||
amdgpu_gtt_mgr.o amdgpu_preempt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o \
|
||||
amdgpu_atomfirmware.o amdgpu_vf_error.o amdgpu_sched.o \
|
||||
|
|
@ -58,7 +58,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
|
|||
amdgpu_vm_sdma.o amdgpu_discovery.o amdgpu_ras_eeprom.o amdgpu_nbio.o \
|
||||
amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \
|
||||
amdgpu_fw_attestation.o amdgpu_securedisplay.o \
|
||||
amdgpu_eeprom.o amdgpu_mca.o
|
||||
amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o
|
||||
|
||||
amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o
|
||||
|
||||
|
|
@ -74,7 +74,8 @@ amdgpu-$(CONFIG_DRM_AMDGPU_SI)+= si.o gmc_v6_0.o gfx_v6_0.o si_ih.o si_dma.o dce
|
|||
amdgpu-y += \
|
||||
vi.o mxgpu_vi.o nbio_v6_1.o soc15.o emu_soc.o mxgpu_ai.o nbio_v7_0.o vega10_reg_init.o \
|
||||
vega20_reg_init.o nbio_v7_4.o nbio_v2_3.o nv.o arct_reg_init.o mxgpu_nv.o \
|
||||
nbio_v7_2.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o
|
||||
nbio_v7_2.o hdp_v4_0.o hdp_v5_0.o aldebaran_reg_init.o aldebaran.o soc21.o \
|
||||
nbio_v4_3.o hdp_v6_0.o nbio_v7_7.o hdp_v5_2.o lsdma_v6_0.o
|
||||
|
||||
# add DF block
|
||||
amdgpu-y += \
|
||||
|
|
@ -87,7 +88,7 @@ amdgpu-y += \
|
|||
gmc_v8_0.o \
|
||||
gfxhub_v1_0.o mmhub_v1_0.o gmc_v9_0.o gfxhub_v1_1.o mmhub_v9_4.o \
|
||||
gfxhub_v2_0.o mmhub_v2_0.o gmc_v10_0.o gfxhub_v2_1.o mmhub_v2_3.o \
|
||||
mmhub_v1_7.o
|
||||
mmhub_v1_7.o gfxhub_v3_0.o mmhub_v3_0.o mmhub_v3_0_2.o gmc_v11_0.o
|
||||
|
||||
# add UMC block
|
||||
amdgpu-y += \
|
||||
|
|
@ -102,7 +103,8 @@ amdgpu-y += \
|
|||
cz_ih.o \
|
||||
vega10_ih.o \
|
||||
vega20_ih.o \
|
||||
navi10_ih.o
|
||||
navi10_ih.o \
|
||||
ih_v6_0.o
|
||||
|
||||
# add PSP block
|
||||
amdgpu-y += \
|
||||
|
|
@ -128,7 +130,9 @@ amdgpu-y += \
|
|||
gfx_v9_0.o \
|
||||
gfx_v9_4.o \
|
||||
gfx_v9_4_2.o \
|
||||
gfx_v10_0.o
|
||||
gfx_v10_0.o \
|
||||
imu_v11_0.o \
|
||||
gfx_v11_0.o
|
||||
|
||||
# add async DMA block
|
||||
amdgpu-y += \
|
||||
|
|
@ -138,11 +142,14 @@ amdgpu-y += \
|
|||
sdma_v4_0.o \
|
||||
sdma_v4_4.o \
|
||||
sdma_v5_0.o \
|
||||
sdma_v5_2.o
|
||||
sdma_v5_2.o \
|
||||
sdma_v6_0.o
|
||||
|
||||
# add MES block
|
||||
amdgpu-y += \
|
||||
mes_v10_1.o
|
||||
amdgpu_mes.o \
|
||||
mes_v10_1.o \
|
||||
mes_v11_0.o
|
||||
|
||||
# add UVD block
|
||||
amdgpu-y += \
|
||||
|
|
@ -160,28 +167,33 @@ amdgpu-y += \
|
|||
# add VCN and JPEG block
|
||||
amdgpu-y += \
|
||||
amdgpu_vcn.o \
|
||||
vcn_sw_ring.o \
|
||||
vcn_v1_0.o \
|
||||
vcn_v2_0.o \
|
||||
vcn_v2_5.o \
|
||||
vcn_v3_0.o \
|
||||
vcn_v4_0.o \
|
||||
amdgpu_jpeg.o \
|
||||
jpeg_v1_0.o \
|
||||
jpeg_v2_0.o \
|
||||
jpeg_v2_5.o \
|
||||
jpeg_v3_0.o
|
||||
jpeg_v3_0.o \
|
||||
jpeg_v4_0.o
|
||||
|
||||
# add ATHUB block
|
||||
amdgpu-y += \
|
||||
athub_v1_0.o \
|
||||
athub_v2_0.o \
|
||||
athub_v2_1.o
|
||||
athub_v2_1.o \
|
||||
athub_v3_0.o
|
||||
|
||||
# add SMUIO block
|
||||
amdgpu-y += \
|
||||
smuio_v9_0.o \
|
||||
smuio_v11_0.o \
|
||||
smuio_v11_0_6.o \
|
||||
smuio_v13_0.o
|
||||
smuio_v13_0.o \
|
||||
smuio_v13_0_6.o
|
||||
|
||||
# add reset block
|
||||
amdgpu-y += \
|
||||
|
|
@ -207,7 +219,8 @@ amdgpu-y += \
|
|||
amdgpu_amdkfd_arcturus.o \
|
||||
amdgpu_amdkfd_aldebaran.o \
|
||||
amdgpu_amdkfd_gfx_v10.o \
|
||||
amdgpu_amdkfd_gfx_v10_3.o
|
||||
amdgpu_amdkfd_gfx_v10_3.o \
|
||||
amdgpu_amdkfd_gfx_v11.o
|
||||
|
||||
ifneq ($(CONFIG_DRM_AMDGPU_CIK),)
|
||||
amdgpu-y += amdgpu_amdkfd_gfx_v7.o
|
||||
|
|
|
|||
|
|
@ -86,11 +86,13 @@
|
|||
#include "amdgpu_gmc.h"
|
||||
#include "amdgpu_gfx.h"
|
||||
#include "amdgpu_sdma.h"
|
||||
#include "amdgpu_lsdma.h"
|
||||
#include "amdgpu_nbio.h"
|
||||
#include "amdgpu_hdp.h"
|
||||
#include "amdgpu_dm.h"
|
||||
#include "amdgpu_virt.h"
|
||||
#include "amdgpu_csa.h"
|
||||
#include "amdgpu_mes_ctx.h"
|
||||
#include "amdgpu_gart.h"
|
||||
#include "amdgpu_debugfs.h"
|
||||
#include "amdgpu_job.h"
|
||||
|
|
@ -179,7 +181,7 @@ extern int amdgpu_sched_jobs;
|
|||
extern int amdgpu_sched_hw_submission;
|
||||
extern uint amdgpu_pcie_gen_cap;
|
||||
extern uint amdgpu_pcie_lane_cap;
|
||||
extern uint amdgpu_cg_mask;
|
||||
extern u64 amdgpu_cg_mask;
|
||||
extern uint amdgpu_pg_mask;
|
||||
extern uint amdgpu_sdma_phase_quantum;
|
||||
extern char *amdgpu_disable_cu;
|
||||
|
|
@ -207,6 +209,7 @@ extern int amdgpu_async_gfx_ring;
|
|||
extern int amdgpu_mcbp;
|
||||
extern int amdgpu_discovery;
|
||||
extern int amdgpu_mes;
|
||||
extern int amdgpu_mes_kiq;
|
||||
extern int amdgpu_noretry;
|
||||
extern int amdgpu_force_asic_type;
|
||||
extern int amdgpu_smartshift_bias;
|
||||
|
|
@ -322,7 +325,7 @@ int amdgpu_device_ip_set_powergating_state(void *dev,
|
|||
enum amd_ip_block_type block_type,
|
||||
enum amd_powergating_state state);
|
||||
void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
|
||||
u32 *flags);
|
||||
u64 *flags);
|
||||
int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
|
||||
enum amd_ip_block_type block_type);
|
||||
bool amdgpu_device_ip_is_idle(struct amdgpu_device *adev,
|
||||
|
|
@ -641,6 +644,7 @@ enum amd_hw_ip_block_type {
|
|||
SDMA5_HWIP,
|
||||
SDMA6_HWIP,
|
||||
SDMA7_HWIP,
|
||||
LSDMA_HWIP,
|
||||
MMHUB_HWIP,
|
||||
ATHUB_HWIP,
|
||||
NBIO_HWIP,
|
||||
|
|
@ -666,10 +670,13 @@ enum amd_hw_ip_block_type {
|
|||
MAX_HWIP
|
||||
};
|
||||
|
||||
#define HWIP_MAX_INSTANCE 10
|
||||
#define HWIP_MAX_INSTANCE 11
|
||||
|
||||
#define HW_ID_MAX 300
|
||||
#define IP_VERSION(mj, mn, rv) (((mj) << 16) | ((mn) << 8) | (rv))
|
||||
#define IP_VERSION_MAJ(ver) ((ver) >> 16)
|
||||
#define IP_VERSION_MIN(ver) (((ver) >> 8) & 0xFF)
|
||||
#define IP_VERSION_REV(ver) ((ver) & 0xFF)
|
||||
|
||||
struct amd_powerplay {
|
||||
void *pp_handle;
|
||||
|
|
@ -717,6 +724,26 @@ struct ip_discovery_top;
|
|||
(rid == 0x01) || \
|
||||
(rid == 0x10))))
|
||||
|
||||
struct amdgpu_mqd_prop {
|
||||
uint64_t mqd_gpu_addr;
|
||||
uint64_t hqd_base_gpu_addr;
|
||||
uint64_t rptr_gpu_addr;
|
||||
uint64_t wptr_gpu_addr;
|
||||
uint32_t queue_size;
|
||||
bool use_doorbell;
|
||||
uint32_t doorbell_index;
|
||||
uint64_t eop_gpu_addr;
|
||||
uint32_t hqd_pipe_priority;
|
||||
uint32_t hqd_queue_priority;
|
||||
bool hqd_active;
|
||||
};
|
||||
|
||||
struct amdgpu_mqd {
|
||||
unsigned mqd_size;
|
||||
int (*init_mqd)(struct amdgpu_device *adev, void *mqd,
|
||||
struct amdgpu_mqd_prop *p);
|
||||
};
|
||||
|
||||
#define AMDGPU_RESET_MAGIC_NUM 64
|
||||
#define AMDGPU_MAX_DF_PERFMONS 4
|
||||
#define AMDGPU_PRODUCT_NAME_LEN 64
|
||||
|
|
@ -860,7 +887,7 @@ struct amdgpu_device {
|
|||
/* powerplay */
|
||||
struct amd_powerplay powerplay;
|
||||
struct amdgpu_pm pm;
|
||||
u32 cg_flags;
|
||||
u64 cg_flags;
|
||||
u32 pg_flags;
|
||||
|
||||
/* nbio */
|
||||
|
|
@ -884,6 +911,9 @@ struct amdgpu_device {
|
|||
/* sdma */
|
||||
struct amdgpu_sdma sdma;
|
||||
|
||||
/* lsdma */
|
||||
struct amdgpu_lsdma lsdma;
|
||||
|
||||
/* uvd */
|
||||
struct amdgpu_uvd uvd;
|
||||
|
||||
|
|
@ -916,7 +946,9 @@ struct amdgpu_device {
|
|||
|
||||
/* mes */
|
||||
bool enable_mes;
|
||||
bool enable_mes_kiq;
|
||||
struct amdgpu_mes mes;
|
||||
struct amdgpu_mqd mqds[AMDGPU_HW_IP_NUM];
|
||||
|
||||
/* df */
|
||||
struct amdgpu_df df;
|
||||
|
|
@ -978,10 +1010,10 @@ struct amdgpu_device {
|
|||
bool runpm;
|
||||
bool in_runpm;
|
||||
bool has_pr3;
|
||||
bool is_fw_fb;
|
||||
|
||||
bool pm_sysfs_en;
|
||||
bool ucode_sysfs_en;
|
||||
bool psp_sysfs_en;
|
||||
|
||||
/* Chip product information */
|
||||
char product_number[16];
|
||||
|
|
@ -1013,6 +1045,9 @@ struct amdgpu_device {
|
|||
/* reset dump register */
|
||||
uint32_t *reset_dump_reg_list;
|
||||
int num_regs;
|
||||
|
||||
bool scpm_enabled;
|
||||
uint32_t scpm_status;
|
||||
};
|
||||
|
||||
static inline struct amdgpu_device *drm_to_adev(struct drm_device *ddev)
|
||||
|
|
@ -1185,7 +1220,8 @@ int emu_soc_asic_init(struct amdgpu_device *adev);
|
|||
#define amdgpu_asic_flush_hdp(adev, r) \
|
||||
((adev)->asic_funcs->flush_hdp ? (adev)->asic_funcs->flush_hdp((adev), (r)) : (adev)->hdp.funcs->flush_hdp((adev), (r)))
|
||||
#define amdgpu_asic_invalidate_hdp(adev, r) \
|
||||
((adev)->asic_funcs->invalidate_hdp ? (adev)->asic_funcs->invalidate_hdp((adev), (r)) : (adev)->hdp.funcs->invalidate_hdp((adev), (r)))
|
||||
((adev)->asic_funcs->invalidate_hdp ? (adev)->asic_funcs->invalidate_hdp((adev), (r)) : \
|
||||
((adev)->hdp.funcs->invalidate_hdp ? (adev)->hdp.funcs->invalidate_hdp((adev), (r)) : 0))
|
||||
#define amdgpu_asic_need_full_reset(adev) (adev)->asic_funcs->need_full_reset((adev))
|
||||
#define amdgpu_asic_init_doorbell_index(adev) (adev)->asic_funcs->init_doorbell_index((adev))
|
||||
#define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1)))
|
||||
|
|
|
|||
|
|
@ -100,7 +100,18 @@ static void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev,
|
|||
* The first num_doorbells are used by amdgpu.
|
||||
* amdkfd takes whatever's left in the aperture.
|
||||
*/
|
||||
if (adev->doorbell.size > adev->doorbell.num_doorbells * sizeof(u32)) {
|
||||
if (adev->enable_mes) {
|
||||
/*
|
||||
* With MES enabled, we only need to initialize
|
||||
* the base address. The size and offset are
|
||||
* not initialized as AMDGPU manages the whole
|
||||
* doorbell space.
|
||||
*/
|
||||
*aperture_base = adev->doorbell.base;
|
||||
*aperture_size = 0;
|
||||
*start_offset = 0;
|
||||
} else if (adev->doorbell.size > adev->doorbell.num_doorbells *
|
||||
sizeof(u32)) {
|
||||
*aperture_base = adev->doorbell.base;
|
||||
*aperture_size = adev->doorbell.size;
|
||||
*start_offset = adev->doorbell.num_doorbells * sizeof(u32);
|
||||
|
|
@ -128,7 +139,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev)
|
|||
AMDGPU_GMC_HOLE_START),
|
||||
.drm_render_minor = adev_to_drm(adev)->render->index,
|
||||
.sdma_doorbell_idx = adev->doorbell_index.sdma_engine,
|
||||
|
||||
.enable_mes = adev->enable_mes,
|
||||
};
|
||||
|
||||
/* this is going to have a few of the MSBs set that we need to
|
||||
|
|
@ -724,3 +735,11 @@ void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev, bo
|
|||
else if (reset)
|
||||
amdgpu_amdkfd_gpu_reset(adev);
|
||||
}
|
||||
|
||||
bool amdgpu_amdkfd_ras_query_utcl2_poison_status(struct amdgpu_device *adev)
|
||||
{
|
||||
if (adev->gfx.ras && adev->gfx.ras->query_utcl2_poison_status)
|
||||
return adev->gfx.ras->query_utcl2_poison_status(adev);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -273,9 +273,8 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
|
|||
int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
|
||||
struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv,
|
||||
uint64_t *size);
|
||||
int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
|
||||
struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv,
|
||||
bool *table_freed);
|
||||
int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(struct amdgpu_device *adev,
|
||||
struct kgd_mem *mem, void *drm_priv);
|
||||
int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu(
|
||||
struct amdgpu_device *adev, struct kgd_mem *mem, void *drm_priv);
|
||||
int amdgpu_amdkfd_gpuvm_sync_memory(
|
||||
|
|
@ -301,6 +300,7 @@ void amdgpu_amdkfd_ras_poison_consumption_handler(struct amdgpu_device *adev,
|
|||
bool amdgpu_amdkfd_bo_mapped_to_dev(struct amdgpu_device *adev, struct kgd_mem *mem);
|
||||
void amdgpu_amdkfd_block_mmu_notifications(void *p);
|
||||
int amdgpu_amdkfd_criu_resume(void *p);
|
||||
bool amdgpu_amdkfd_ras_query_utcl2_poison_status(struct amdgpu_device *adev);
|
||||
|
||||
#if IS_ENABLED(CONFIG_HSA_AMD)
|
||||
void amdgpu_amdkfd_gpuvm_init_mem_limits(void);
|
||||
|
|
|
|||
625
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
Normal file
625
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v11.c
Normal file
|
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* Copyright 2021 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <linux/mmu_context.h>
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_amdkfd.h"
|
||||
#include "gc/gc_11_0_0_offset.h"
|
||||
#include "gc/gc_11_0_0_sh_mask.h"
|
||||
#include "oss/osssys_6_0_0_offset.h"
|
||||
#include "oss/osssys_6_0_0_sh_mask.h"
|
||||
#include "soc15_common.h"
|
||||
#include "soc15d.h"
|
||||
#include "v11_structs.h"
|
||||
#include "soc21.h"
|
||||
|
||||
enum hqd_dequeue_request_type {
|
||||
NO_ACTION = 0,
|
||||
DRAIN_PIPE,
|
||||
RESET_WAVES,
|
||||
SAVE_WAVES
|
||||
};
|
||||
|
||||
static void lock_srbm(struct amdgpu_device *adev, uint32_t mec, uint32_t pipe,
|
||||
uint32_t queue, uint32_t vmid)
|
||||
{
|
||||
mutex_lock(&adev->srbm_mutex);
|
||||
soc21_grbm_select(adev, mec, pipe, queue, vmid);
|
||||
}
|
||||
|
||||
static void unlock_srbm(struct amdgpu_device *adev)
|
||||
{
|
||||
soc21_grbm_select(adev, 0, 0, 0, 0);
|
||||
mutex_unlock(&adev->srbm_mutex);
|
||||
}
|
||||
|
||||
static void acquire_queue(struct amdgpu_device *adev, uint32_t pipe_id,
|
||||
uint32_t queue_id)
|
||||
{
|
||||
uint32_t mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
uint32_t pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
lock_srbm(adev, mec, pipe, queue_id, 0);
|
||||
}
|
||||
|
||||
static uint64_t get_queue_mask(struct amdgpu_device *adev,
|
||||
uint32_t pipe_id, uint32_t queue_id)
|
||||
{
|
||||
unsigned int bit = pipe_id * adev->gfx.mec.num_queue_per_pipe +
|
||||
queue_id;
|
||||
|
||||
return 1ull << bit;
|
||||
}
|
||||
|
||||
static void release_queue(struct amdgpu_device *adev)
|
||||
{
|
||||
unlock_srbm(adev);
|
||||
}
|
||||
|
||||
static void program_sh_mem_settings_v11(struct amdgpu_device *adev, uint32_t vmid,
|
||||
uint32_t sh_mem_config,
|
||||
uint32_t sh_mem_ape1_base,
|
||||
uint32_t sh_mem_ape1_limit,
|
||||
uint32_t sh_mem_bases)
|
||||
{
|
||||
lock_srbm(adev, 0, 0, 0, vmid);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regSH_MEM_CONFIG), sh_mem_config);
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regSH_MEM_BASES), sh_mem_bases);
|
||||
|
||||
unlock_srbm(adev);
|
||||
}
|
||||
|
||||
static int set_pasid_vmid_mapping_v11(struct amdgpu_device *adev, unsigned int pasid,
|
||||
unsigned int vmid)
|
||||
{
|
||||
uint32_t value = pasid << IH_VMID_0_LUT__PASID__SHIFT;
|
||||
|
||||
/* Mapping vmid to pasid also for IH block */
|
||||
pr_debug("mapping vmid %d -> pasid %d in IH block for GFX client\n",
|
||||
vmid, pasid);
|
||||
WREG32(SOC15_REG_OFFSET(OSSSYS, 0, regIH_VMID_0_LUT) + vmid, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_interrupts_v11(struct amdgpu_device *adev, uint32_t pipe_id)
|
||||
{
|
||||
uint32_t mec;
|
||||
uint32_t pipe;
|
||||
|
||||
mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
lock_srbm(adev, mec, pipe, 0, 0);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCPC_INT_CNTL),
|
||||
CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK |
|
||||
CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK);
|
||||
|
||||
unlock_srbm(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t get_sdma_rlc_reg_offset(struct amdgpu_device *adev,
|
||||
unsigned int engine_id,
|
||||
unsigned int queue_id)
|
||||
{
|
||||
uint32_t sdma_engine_reg_base = 0;
|
||||
uint32_t sdma_rlc_reg_offset;
|
||||
|
||||
switch (engine_id) {
|
||||
case 0:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA0, 0,
|
||||
regSDMA0_QUEUE0_RB_CNTL) - regSDMA0_QUEUE0_RB_CNTL;
|
||||
break;
|
||||
case 1:
|
||||
sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA1, 0,
|
||||
regSDMA1_QUEUE0_RB_CNTL) - regSDMA0_QUEUE0_RB_CNTL;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
sdma_rlc_reg_offset = sdma_engine_reg_base
|
||||
+ queue_id * (regSDMA0_QUEUE1_RB_CNTL - regSDMA0_QUEUE0_RB_CNTL);
|
||||
|
||||
pr_debug("RLC register offset for SDMA%d RLC%d: 0x%x\n", engine_id,
|
||||
queue_id, sdma_rlc_reg_offset);
|
||||
|
||||
return sdma_rlc_reg_offset;
|
||||
}
|
||||
|
||||
static inline struct v11_compute_mqd *get_mqd(void *mqd)
|
||||
{
|
||||
return (struct v11_compute_mqd *)mqd;
|
||||
}
|
||||
|
||||
static inline struct v11_sdma_mqd *get_sdma_mqd(void *mqd)
|
||||
{
|
||||
return (struct v11_sdma_mqd *)mqd;
|
||||
}
|
||||
|
||||
static int hqd_load_v11(struct amdgpu_device *adev, void *mqd, uint32_t pipe_id,
|
||||
uint32_t queue_id, uint32_t __user *wptr,
|
||||
uint32_t wptr_shift, uint32_t wptr_mask,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
struct v11_compute_mqd *m;
|
||||
uint32_t *mqd_hqd;
|
||||
uint32_t reg, hqd_base, data;
|
||||
|
||||
m = get_mqd(mqd);
|
||||
|
||||
pr_debug("Load hqd of pipe %d queue %d\n", pipe_id, queue_id);
|
||||
acquire_queue(adev, pipe_id, queue_id);
|
||||
|
||||
/* HIQ is set during driver init period with vmid set to 0*/
|
||||
if (m->cp_hqd_vmid == 0) {
|
||||
uint32_t value, mec, pipe;
|
||||
|
||||
mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n",
|
||||
mec, pipe, queue_id);
|
||||
value = RREG32(SOC15_REG_OFFSET(GC, 0, regRLC_CP_SCHEDULERS));
|
||||
value = REG_SET_FIELD(value, RLC_CP_SCHEDULERS, scheduler1,
|
||||
((mec << 5) | (pipe << 3) | queue_id | 0x80));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regRLC_CP_SCHEDULERS), value);
|
||||
}
|
||||
|
||||
/* HQD registers extend from CP_MQD_BASE_ADDR to CP_HQD_EOP_WPTR_MEM. */
|
||||
mqd_hqd = &m->cp_mqd_base_addr_lo;
|
||||
hqd_base = SOC15_REG_OFFSET(GC, 0, regCP_MQD_BASE_ADDR);
|
||||
|
||||
for (reg = hqd_base;
|
||||
reg <= SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_WPTR_HI); reg++)
|
||||
WREG32(reg, mqd_hqd[reg - hqd_base]);
|
||||
|
||||
|
||||
/* Activate doorbell logic before triggering WPTR poll. */
|
||||
data = REG_SET_FIELD(m->cp_hqd_pq_doorbell_control,
|
||||
CP_HQD_PQ_DOORBELL_CONTROL, DOORBELL_EN, 1);
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_DOORBELL_CONTROL), data);
|
||||
|
||||
if (wptr) {
|
||||
/* Don't read wptr with get_user because the user
|
||||
* context may not be accessible (if this function
|
||||
* runs in a work queue). Instead trigger a one-shot
|
||||
* polling read from memory in the CP. This assumes
|
||||
* that wptr is GPU-accessible in the queue's VMID via
|
||||
* ATC or SVM. WPTR==RPTR before starting the poll so
|
||||
* the CP starts fetching new commands from the right
|
||||
* place.
|
||||
*
|
||||
* Guessing a 64-bit WPTR from a 32-bit RPTR is a bit
|
||||
* tricky. Assume that the queue didn't overflow. The
|
||||
* number of valid bits in the 32-bit RPTR depends on
|
||||
* the queue size. The remaining bits are taken from
|
||||
* the saved 64-bit WPTR. If the WPTR wrapped, add the
|
||||
* queue size.
|
||||
*/
|
||||
uint32_t queue_size =
|
||||
2 << REG_GET_FIELD(m->cp_hqd_pq_control,
|
||||
CP_HQD_PQ_CONTROL, QUEUE_SIZE);
|
||||
uint64_t guessed_wptr = m->cp_hqd_pq_rptr & (queue_size - 1);
|
||||
|
||||
if ((m->cp_hqd_pq_wptr_lo & (queue_size - 1)) < guessed_wptr)
|
||||
guessed_wptr += queue_size;
|
||||
guessed_wptr += m->cp_hqd_pq_wptr_lo & ~(queue_size - 1);
|
||||
guessed_wptr += (uint64_t)m->cp_hqd_pq_wptr_hi << 32;
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_WPTR_LO),
|
||||
lower_32_bits(guessed_wptr));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_WPTR_HI),
|
||||
upper_32_bits(guessed_wptr));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_WPTR_POLL_ADDR),
|
||||
lower_32_bits((uint64_t)wptr));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_WPTR_POLL_ADDR_HI),
|
||||
upper_32_bits((uint64_t)wptr));
|
||||
pr_debug("%s setting CP_PQ_WPTR_POLL_CNTL1 to %x\n", __func__,
|
||||
(uint32_t)get_queue_mask(adev, pipe_id, queue_id));
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_PQ_WPTR_POLL_CNTL1),
|
||||
(uint32_t)get_queue_mask(adev, pipe_id, queue_id));
|
||||
}
|
||||
|
||||
/* Start the EOP fetcher */
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_EOP_RPTR),
|
||||
REG_SET_FIELD(m->cp_hqd_eop_rptr,
|
||||
CP_HQD_EOP_RPTR, INIT_FETCHER, 1));
|
||||
|
||||
data = REG_SET_FIELD(m->cp_hqd_active, CP_HQD_ACTIVE, ACTIVE, 1);
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_ACTIVE), data);
|
||||
|
||||
release_queue(adev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hiq_mqd_load_v11(struct amdgpu_device *adev, void *mqd,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t doorbell_off)
|
||||
{
|
||||
struct amdgpu_ring *kiq_ring = &adev->gfx.kiq.ring;
|
||||
struct v11_compute_mqd *m;
|
||||
uint32_t mec, pipe;
|
||||
int r;
|
||||
|
||||
m = get_mqd(mqd);
|
||||
|
||||
acquire_queue(adev, pipe_id, queue_id);
|
||||
|
||||
mec = (pipe_id / adev->gfx.mec.num_pipe_per_mec) + 1;
|
||||
pipe = (pipe_id % adev->gfx.mec.num_pipe_per_mec);
|
||||
|
||||
pr_debug("kfd: set HIQ, mec:%d, pipe:%d, queue:%d.\n",
|
||||
mec, pipe, queue_id);
|
||||
|
||||
spin_lock(&adev->gfx.kiq.ring_lock);
|
||||
r = amdgpu_ring_alloc(kiq_ring, 7);
|
||||
if (r) {
|
||||
pr_err("Failed to alloc KIQ (%d).\n", r);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_MAP_QUEUES, 5));
|
||||
amdgpu_ring_write(kiq_ring,
|
||||
PACKET3_MAP_QUEUES_QUEUE_SEL(0) | /* Queue_Sel */
|
||||
PACKET3_MAP_QUEUES_VMID(m->cp_hqd_vmid) | /* VMID */
|
||||
PACKET3_MAP_QUEUES_QUEUE(queue_id) |
|
||||
PACKET3_MAP_QUEUES_PIPE(pipe) |
|
||||
PACKET3_MAP_QUEUES_ME((mec - 1)) |
|
||||
PACKET3_MAP_QUEUES_QUEUE_TYPE(0) | /*queue_type: normal compute queue */
|
||||
PACKET3_MAP_QUEUES_ALLOC_FORMAT(0) | /* alloc format: all_on_one_pipe */
|
||||
PACKET3_MAP_QUEUES_ENGINE_SEL(1) | /* engine_sel: hiq */
|
||||
PACKET3_MAP_QUEUES_NUM_QUEUES(1)); /* num_queues: must be 1 */
|
||||
amdgpu_ring_write(kiq_ring,
|
||||
PACKET3_MAP_QUEUES_DOORBELL_OFFSET(doorbell_off));
|
||||
amdgpu_ring_write(kiq_ring, m->cp_mqd_base_addr_lo);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_mqd_base_addr_hi);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_hqd_pq_wptr_poll_addr_lo);
|
||||
amdgpu_ring_write(kiq_ring, m->cp_hqd_pq_wptr_poll_addr_hi);
|
||||
amdgpu_ring_commit(kiq_ring);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
release_queue(adev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int hqd_dump_v11(struct amdgpu_device *adev,
|
||||
uint32_t pipe_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs)
|
||||
{
|
||||
uint32_t i = 0, reg;
|
||||
#define HQD_N_REGS 56
|
||||
#define DUMP_REG(addr) do { \
|
||||
if (WARN_ON_ONCE(i >= HQD_N_REGS)) \
|
||||
break; \
|
||||
(*dump)[i][0] = (addr) << 2; \
|
||||
(*dump)[i++][1] = RREG32(addr); \
|
||||
} while (0)
|
||||
|
||||
*dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL);
|
||||
if (*dump == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
acquire_queue(adev, pipe_id, queue_id);
|
||||
|
||||
for (reg = SOC15_REG_OFFSET(GC, 0, regCP_MQD_BASE_ADDR);
|
||||
reg <= SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_WPTR_HI); reg++)
|
||||
DUMP_REG(reg);
|
||||
|
||||
release_queue(adev);
|
||||
|
||||
WARN_ON_ONCE(i != HQD_N_REGS);
|
||||
*n_regs = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hqd_sdma_load_v11(struct amdgpu_device *adev, void *mqd,
|
||||
uint32_t __user *wptr, struct mm_struct *mm)
|
||||
{
|
||||
struct v11_sdma_mqd *m;
|
||||
uint32_t sdma_rlc_reg_offset;
|
||||
unsigned long end_jiffies;
|
||||
uint32_t data;
|
||||
uint64_t data64;
|
||||
uint64_t __user *wptr64 = (uint64_t __user *)wptr;
|
||||
|
||||
m = get_sdma_mqd(mqd);
|
||||
sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev, m->sdma_engine_id,
|
||||
m->sdma_queue_id);
|
||||
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_CNTL,
|
||||
m->sdmax_rlcx_rb_cntl & (~SDMA0_QUEUE0_RB_CNTL__RB_ENABLE_MASK));
|
||||
|
||||
end_jiffies = msecs_to_jiffies(2000) + jiffies;
|
||||
while (true) {
|
||||
data = RREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_CONTEXT_STATUS);
|
||||
if (data & SDMA0_QUEUE0_CONTEXT_STATUS__IDLE_MASK)
|
||||
break;
|
||||
if (time_after(jiffies, end_jiffies)) {
|
||||
pr_err("SDMA RLC not idle in %s\n", __func__);
|
||||
return -ETIME;
|
||||
}
|
||||
usleep_range(500, 1000);
|
||||
}
|
||||
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_DOORBELL_OFFSET,
|
||||
m->sdmax_rlcx_doorbell_offset);
|
||||
|
||||
data = REG_SET_FIELD(m->sdmax_rlcx_doorbell, SDMA0_QUEUE0_DOORBELL,
|
||||
ENABLE, 1);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_DOORBELL, data);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_RPTR,
|
||||
m->sdmax_rlcx_rb_rptr);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_RPTR_HI,
|
||||
m->sdmax_rlcx_rb_rptr_hi);
|
||||
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_MINOR_PTR_UPDATE, 1);
|
||||
if (read_user_wptr(mm, wptr64, data64)) {
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_WPTR,
|
||||
lower_32_bits(data64));
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_WPTR_HI,
|
||||
upper_32_bits(data64));
|
||||
} else {
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_WPTR,
|
||||
m->sdmax_rlcx_rb_rptr);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_WPTR_HI,
|
||||
m->sdmax_rlcx_rb_rptr_hi);
|
||||
}
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_MINOR_PTR_UPDATE, 0);
|
||||
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_BASE, m->sdmax_rlcx_rb_base);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_BASE_HI,
|
||||
m->sdmax_rlcx_rb_base_hi);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_RPTR_ADDR_LO,
|
||||
m->sdmax_rlcx_rb_rptr_addr_lo);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_RPTR_ADDR_HI,
|
||||
m->sdmax_rlcx_rb_rptr_addr_hi);
|
||||
|
||||
data = REG_SET_FIELD(m->sdmax_rlcx_rb_cntl, SDMA0_QUEUE0_RB_CNTL,
|
||||
RB_ENABLE, 1);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_CNTL, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hqd_sdma_dump_v11(struct amdgpu_device *adev,
|
||||
uint32_t engine_id, uint32_t queue_id,
|
||||
uint32_t (**dump)[2], uint32_t *n_regs)
|
||||
{
|
||||
uint32_t sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev,
|
||||
engine_id, queue_id);
|
||||
uint32_t i = 0, reg;
|
||||
#undef HQD_N_REGS
|
||||
#define HQD_N_REGS (7+11+1+12+12)
|
||||
|
||||
*dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL);
|
||||
if (*dump == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (reg = regSDMA0_QUEUE0_RB_CNTL;
|
||||
reg <= regSDMA0_QUEUE0_RB_WPTR_HI; reg++)
|
||||
DUMP_REG(sdma_rlc_reg_offset + reg);
|
||||
for (reg = regSDMA0_QUEUE0_RB_RPTR_ADDR_HI;
|
||||
reg <= regSDMA0_QUEUE0_DOORBELL; reg++)
|
||||
DUMP_REG(sdma_rlc_reg_offset + reg);
|
||||
for (reg = regSDMA0_QUEUE0_DOORBELL_LOG;
|
||||
reg <= regSDMA0_QUEUE0_DOORBELL_LOG; reg++)
|
||||
DUMP_REG(sdma_rlc_reg_offset + reg);
|
||||
for (reg = regSDMA0_QUEUE0_DOORBELL_OFFSET;
|
||||
reg <= regSDMA0_QUEUE0_RB_PREEMPT; reg++)
|
||||
DUMP_REG(sdma_rlc_reg_offset + reg);
|
||||
for (reg = regSDMA0_QUEUE0_MIDCMD_DATA0;
|
||||
reg <= regSDMA0_QUEUE0_MIDCMD_CNTL; reg++)
|
||||
DUMP_REG(sdma_rlc_reg_offset + reg);
|
||||
|
||||
WARN_ON_ONCE(i != HQD_N_REGS);
|
||||
*n_regs = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool hqd_is_occupied_v11(struct amdgpu_device *adev, uint64_t queue_address,
|
||||
uint32_t pipe_id, uint32_t queue_id)
|
||||
{
|
||||
uint32_t act;
|
||||
bool retval = false;
|
||||
uint32_t low, high;
|
||||
|
||||
acquire_queue(adev, pipe_id, queue_id);
|
||||
act = RREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_ACTIVE));
|
||||
if (act) {
|
||||
low = lower_32_bits(queue_address >> 8);
|
||||
high = upper_32_bits(queue_address >> 8);
|
||||
|
||||
if (low == RREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_BASE)) &&
|
||||
high == RREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_PQ_BASE_HI)))
|
||||
retval = true;
|
||||
}
|
||||
release_queue(adev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool hqd_sdma_is_occupied_v11(struct amdgpu_device *adev, void *mqd)
|
||||
{
|
||||
struct v11_sdma_mqd *m;
|
||||
uint32_t sdma_rlc_reg_offset;
|
||||
uint32_t sdma_rlc_rb_cntl;
|
||||
|
||||
m = get_sdma_mqd(mqd);
|
||||
sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev, m->sdma_engine_id,
|
||||
m->sdma_queue_id);
|
||||
|
||||
sdma_rlc_rb_cntl = RREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_CNTL);
|
||||
|
||||
if (sdma_rlc_rb_cntl & SDMA0_QUEUE0_RB_CNTL__RB_ENABLE_MASK)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int hqd_destroy_v11(struct amdgpu_device *adev, void *mqd,
|
||||
enum kfd_preempt_type reset_type,
|
||||
unsigned int utimeout, uint32_t pipe_id,
|
||||
uint32_t queue_id)
|
||||
{
|
||||
enum hqd_dequeue_request_type type;
|
||||
unsigned long end_jiffies;
|
||||
uint32_t temp;
|
||||
struct v11_compute_mqd *m = get_mqd(mqd);
|
||||
|
||||
acquire_queue(adev, pipe_id, queue_id);
|
||||
|
||||
if (m->cp_hqd_vmid == 0)
|
||||
WREG32_FIELD15_PREREG(GC, 0, RLC_CP_SCHEDULERS, scheduler1, 0);
|
||||
|
||||
switch (reset_type) {
|
||||
case KFD_PREEMPT_TYPE_WAVEFRONT_DRAIN:
|
||||
type = DRAIN_PIPE;
|
||||
break;
|
||||
case KFD_PREEMPT_TYPE_WAVEFRONT_RESET:
|
||||
type = RESET_WAVES;
|
||||
break;
|
||||
default:
|
||||
type = DRAIN_PIPE;
|
||||
break;
|
||||
}
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_DEQUEUE_REQUEST), type);
|
||||
|
||||
end_jiffies = (utimeout * HZ / 1000) + jiffies;
|
||||
while (true) {
|
||||
temp = RREG32(SOC15_REG_OFFSET(GC, 0, regCP_HQD_ACTIVE));
|
||||
if (!(temp & CP_HQD_ACTIVE__ACTIVE_MASK))
|
||||
break;
|
||||
if (time_after(jiffies, end_jiffies)) {
|
||||
pr_err("cp queue pipe %d queue %d preemption failed\n",
|
||||
pipe_id, queue_id);
|
||||
release_queue(adev);
|
||||
return -ETIME;
|
||||
}
|
||||
usleep_range(500, 1000);
|
||||
}
|
||||
|
||||
release_queue(adev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hqd_sdma_destroy_v11(struct amdgpu_device *adev, void *mqd,
|
||||
unsigned int utimeout)
|
||||
{
|
||||
struct v11_sdma_mqd *m;
|
||||
uint32_t sdma_rlc_reg_offset;
|
||||
uint32_t temp;
|
||||
unsigned long end_jiffies = (utimeout * HZ / 1000) + jiffies;
|
||||
|
||||
m = get_sdma_mqd(mqd);
|
||||
sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev, m->sdma_engine_id,
|
||||
m->sdma_queue_id);
|
||||
|
||||
temp = RREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_CNTL);
|
||||
temp = temp & ~SDMA0_QUEUE0_RB_CNTL__RB_ENABLE_MASK;
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_CNTL, temp);
|
||||
|
||||
while (true) {
|
||||
temp = RREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_CONTEXT_STATUS);
|
||||
if (temp & SDMA0_QUEUE0_CONTEXT_STATUS__IDLE_MASK)
|
||||
break;
|
||||
if (time_after(jiffies, end_jiffies)) {
|
||||
pr_err("SDMA RLC not idle in %s\n", __func__);
|
||||
return -ETIME;
|
||||
}
|
||||
usleep_range(500, 1000);
|
||||
}
|
||||
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_DOORBELL, 0);
|
||||
WREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_CNTL,
|
||||
RREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_CNTL) |
|
||||
SDMA0_QUEUE0_RB_CNTL__RB_ENABLE_MASK);
|
||||
|
||||
m->sdmax_rlcx_rb_rptr = RREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_RPTR);
|
||||
m->sdmax_rlcx_rb_rptr_hi =
|
||||
RREG32(sdma_rlc_reg_offset + regSDMA0_QUEUE0_RB_RPTR_HI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wave_control_execute_v11(struct amdgpu_device *adev,
|
||||
uint32_t gfx_index_val,
|
||||
uint32_t sq_cmd)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regGRBM_GFX_INDEX), gfx_index_val);
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regSQ_CMD), sq_cmd);
|
||||
|
||||
data = REG_SET_FIELD(data, GRBM_GFX_INDEX,
|
||||
INSTANCE_BROADCAST_WRITES, 1);
|
||||
data = REG_SET_FIELD(data, GRBM_GFX_INDEX,
|
||||
SA_BROADCAST_WRITES, 1);
|
||||
data = REG_SET_FIELD(data, GRBM_GFX_INDEX,
|
||||
SE_BROADCAST_WRITES, 1);
|
||||
|
||||
WREG32(SOC15_REG_OFFSET(GC, 0, regGRBM_GFX_INDEX), data);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_vm_context_page_table_base_v11(struct amdgpu_device *adev,
|
||||
uint32_t vmid, uint64_t page_table_base)
|
||||
{
|
||||
if (!amdgpu_amdkfd_is_kfd_vmid(adev, vmid)) {
|
||||
pr_err("trying to set page table base for wrong VMID %u\n",
|
||||
vmid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* SDMA is on gfxhub as well for gfx11 adapters */
|
||||
adev->gfxhub.funcs->setup_vm_pt_regs(adev, vmid, page_table_base);
|
||||
}
|
||||
|
||||
const struct kfd2kgd_calls gfx_v11_kfd2kgd = {
|
||||
.program_sh_mem_settings = program_sh_mem_settings_v11,
|
||||
.set_pasid_vmid_mapping = set_pasid_vmid_mapping_v11,
|
||||
.init_interrupts = init_interrupts_v11,
|
||||
.hqd_load = hqd_load_v11,
|
||||
.hiq_mqd_load = hiq_mqd_load_v11,
|
||||
.hqd_sdma_load = hqd_sdma_load_v11,
|
||||
.hqd_dump = hqd_dump_v11,
|
||||
.hqd_sdma_dump = hqd_sdma_dump_v11,
|
||||
.hqd_is_occupied = hqd_is_occupied_v11,
|
||||
.hqd_sdma_is_occupied = hqd_sdma_is_occupied_v11,
|
||||
.hqd_destroy = hqd_destroy_v11,
|
||||
.hqd_sdma_destroy = hqd_sdma_destroy_v11,
|
||||
.wave_control_execute = wave_control_execute_v11,
|
||||
.get_atc_vmid_pasid_mapping_info = NULL,
|
||||
.set_vm_context_page_table_base = set_vm_context_page_table_base_v11,
|
||||
};
|
||||
|
|
@ -253,53 +253,18 @@ void amdgpu_amdkfd_release_notify(struct amdgpu_bo *bo)
|
|||
static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo,
|
||||
struct amdgpu_amdkfd_fence *ef)
|
||||
{
|
||||
struct dma_resv *resv = bo->tbo.base.resv;
|
||||
struct dma_resv_list *old, *new;
|
||||
unsigned int i, j, k;
|
||||
struct dma_fence *replacement;
|
||||
|
||||
if (!ef)
|
||||
return -EINVAL;
|
||||
|
||||
old = dma_resv_shared_list(resv);
|
||||
if (!old)
|
||||
return 0;
|
||||
|
||||
new = kmalloc(struct_size(new, shared, old->shared_max), GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Go through all the shared fences in the resevation object and sort
|
||||
* the interesting ones to the end of the list.
|
||||
/* TODO: Instead of block before we should use the fence of the page
|
||||
* table update and TLB flush here directly.
|
||||
*/
|
||||
for (i = 0, j = old->shared_count, k = 0; i < old->shared_count; ++i) {
|
||||
struct dma_fence *f;
|
||||
|
||||
f = rcu_dereference_protected(old->shared[i],
|
||||
dma_resv_held(resv));
|
||||
|
||||
if (f->context == ef->base.context)
|
||||
RCU_INIT_POINTER(new->shared[--j], f);
|
||||
else
|
||||
RCU_INIT_POINTER(new->shared[k++], f);
|
||||
}
|
||||
new->shared_max = old->shared_max;
|
||||
new->shared_count = k;
|
||||
|
||||
/* Install the new fence list, seqcount provides the barriers */
|
||||
write_seqcount_begin(&resv->seq);
|
||||
RCU_INIT_POINTER(resv->fence, new);
|
||||
write_seqcount_end(&resv->seq);
|
||||
|
||||
/* Drop the references to the removed fences or move them to ef_list */
|
||||
for (i = j; i < old->shared_count; ++i) {
|
||||
struct dma_fence *f;
|
||||
|
||||
f = rcu_dereference_protected(new->shared[i],
|
||||
dma_resv_held(resv));
|
||||
dma_fence_put(f);
|
||||
}
|
||||
kfree_rcu(old, rcu);
|
||||
|
||||
replacement = dma_fence_get_stub();
|
||||
dma_resv_replace_fences(bo->tbo.base.resv, ef->base.context,
|
||||
replacement, DMA_RESV_USAGE_READ);
|
||||
dma_fence_put(replacement);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1093,8 +1058,7 @@ static void unmap_bo_from_gpuvm(struct kgd_mem *mem,
|
|||
|
||||
static int update_gpuvm_pte(struct kgd_mem *mem,
|
||||
struct kfd_mem_attachment *entry,
|
||||
struct amdgpu_sync *sync,
|
||||
bool *table_freed)
|
||||
struct amdgpu_sync *sync)
|
||||
{
|
||||
struct amdgpu_bo_va *bo_va = entry->bo_va;
|
||||
struct amdgpu_device *adev = entry->adev;
|
||||
|
|
@ -1105,7 +1069,7 @@ static int update_gpuvm_pte(struct kgd_mem *mem,
|
|||
return ret;
|
||||
|
||||
/* Update the page tables */
|
||||
ret = amdgpu_vm_bo_update(adev, bo_va, false, table_freed);
|
||||
ret = amdgpu_vm_bo_update(adev, bo_va, false);
|
||||
if (ret) {
|
||||
pr_err("amdgpu_vm_bo_update failed\n");
|
||||
return ret;
|
||||
|
|
@ -1117,8 +1081,7 @@ static int update_gpuvm_pte(struct kgd_mem *mem,
|
|||
static int map_bo_to_gpuvm(struct kgd_mem *mem,
|
||||
struct kfd_mem_attachment *entry,
|
||||
struct amdgpu_sync *sync,
|
||||
bool no_update_pte,
|
||||
bool *table_freed)
|
||||
bool no_update_pte)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -1135,7 +1098,7 @@ static int map_bo_to_gpuvm(struct kgd_mem *mem,
|
|||
if (no_update_pte)
|
||||
return 0;
|
||||
|
||||
ret = update_gpuvm_pte(mem, entry, sync, table_freed);
|
||||
ret = update_gpuvm_pte(mem, entry, sync);
|
||||
if (ret) {
|
||||
pr_err("update_gpuvm_pte() failed\n");
|
||||
goto update_gpuvm_pte_failed;
|
||||
|
|
@ -1268,7 +1231,7 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
|
|||
AMDGPU_FENCE_OWNER_KFD, false);
|
||||
if (ret)
|
||||
goto wait_pd_fail;
|
||||
ret = dma_resv_reserve_shared(vm->root.bo->tbo.base.resv, 1);
|
||||
ret = dma_resv_reserve_fences(vm->root.bo->tbo.base.resv, 1);
|
||||
if (ret)
|
||||
goto reserve_shared_fail;
|
||||
amdgpu_bo_fence(vm->root.bo,
|
||||
|
|
@ -1520,26 +1483,26 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu(
|
|||
} else if (flags & KFD_IOC_ALLOC_MEM_FLAGS_GTT) {
|
||||
domain = alloc_domain = AMDGPU_GEM_DOMAIN_GTT;
|
||||
alloc_flags = 0;
|
||||
} else if (flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) {
|
||||
} else {
|
||||
domain = AMDGPU_GEM_DOMAIN_GTT;
|
||||
alloc_domain = AMDGPU_GEM_DOMAIN_CPU;
|
||||
alloc_flags = AMDGPU_GEM_CREATE_PREEMPTIBLE;
|
||||
if (!offset || !*offset)
|
||||
|
||||
if (flags & KFD_IOC_ALLOC_MEM_FLAGS_USERPTR) {
|
||||
if (!offset || !*offset)
|
||||
return -EINVAL;
|
||||
user_addr = untagged_addr(*offset);
|
||||
} else if (flags & (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL |
|
||||
KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP)) {
|
||||
bo_type = ttm_bo_type_sg;
|
||||
if (size > UINT_MAX)
|
||||
return -EINVAL;
|
||||
sg = create_doorbell_sg(*offset, size);
|
||||
if (!sg)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
user_addr = untagged_addr(*offset);
|
||||
} else if (flags & (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL |
|
||||
KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP)) {
|
||||
domain = AMDGPU_GEM_DOMAIN_GTT;
|
||||
alloc_domain = AMDGPU_GEM_DOMAIN_CPU;
|
||||
bo_type = ttm_bo_type_sg;
|
||||
alloc_flags = 0;
|
||||
if (size > UINT_MAX)
|
||||
return -EINVAL;
|
||||
sg = create_doorbell_sg(*offset, size);
|
||||
if (!sg)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
*mem = kzalloc(sizeof(struct kgd_mem), GFP_KERNEL);
|
||||
|
|
@ -1745,7 +1708,7 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
|
|||
|
||||
int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
|
||||
struct amdgpu_device *adev, struct kgd_mem *mem,
|
||||
void *drm_priv, bool *table_freed)
|
||||
void *drm_priv)
|
||||
{
|
||||
struct amdgpu_vm *avm = drm_priv_to_vm(drm_priv);
|
||||
int ret;
|
||||
|
|
@ -1832,7 +1795,7 @@ int amdgpu_amdkfd_gpuvm_map_memory_to_gpu(
|
|||
entry->va, entry->va + bo_size, entry);
|
||||
|
||||
ret = map_bo_to_gpuvm(mem, entry, ctx.sync,
|
||||
is_invalid_userptr, table_freed);
|
||||
is_invalid_userptr);
|
||||
if (ret) {
|
||||
pr_err("Failed to map bo to gpuvm\n");
|
||||
goto out_unreserve;
|
||||
|
|
@ -2300,7 +2263,7 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info)
|
|||
continue;
|
||||
|
||||
kfd_mem_dmaunmap_attachment(mem, attachment);
|
||||
ret = update_gpuvm_pte(mem, attachment, &sync, NULL);
|
||||
ret = update_gpuvm_pte(mem, attachment, &sync);
|
||||
if (ret) {
|
||||
pr_err("%s: update PTE failed\n", __func__);
|
||||
/* make sure this gets validated again */
|
||||
|
|
@ -2482,6 +2445,8 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
|
|||
struct amdgpu_bo *bo = mem->bo;
|
||||
uint32_t domain = mem->domain;
|
||||
struct kfd_mem_attachment *attachment;
|
||||
struct dma_resv_iter cursor;
|
||||
struct dma_fence *fence;
|
||||
|
||||
total_size += amdgpu_bo_size(bo);
|
||||
|
||||
|
|
@ -2496,17 +2461,20 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef)
|
|||
goto validate_map_fail;
|
||||
}
|
||||
}
|
||||
ret = amdgpu_sync_fence(&sync_obj, bo->tbo.moving);
|
||||
if (ret) {
|
||||
pr_debug("Memory eviction: Sync BO fence failed. Try again\n");
|
||||
goto validate_map_fail;
|
||||
dma_resv_for_each_fence(&cursor, bo->tbo.base.resv,
|
||||
DMA_RESV_USAGE_KERNEL, fence) {
|
||||
ret = amdgpu_sync_fence(&sync_obj, fence);
|
||||
if (ret) {
|
||||
pr_debug("Memory eviction: Sync BO fence failed. Try again\n");
|
||||
goto validate_map_fail;
|
||||
}
|
||||
}
|
||||
list_for_each_entry(attachment, &mem->attachments, list) {
|
||||
if (!attachment->is_mapped)
|
||||
continue;
|
||||
|
||||
kfd_mem_dmaunmap_attachment(mem, attachment);
|
||||
ret = update_gpuvm_pte(mem, attachment, &sync_obj, NULL);
|
||||
ret = update_gpuvm_pte(mem, attachment, &sync_obj);
|
||||
if (ret) {
|
||||
pr_debug("Memory eviction: update PTE failed. Try again\n");
|
||||
goto validate_map_fail;
|
||||
|
|
@ -2606,7 +2574,7 @@ int amdgpu_amdkfd_add_gws_to_process(void *info, void *gws, struct kgd_mem **mem
|
|||
* Add process eviction fence to bo so they can
|
||||
* evict each other.
|
||||
*/
|
||||
ret = dma_resv_reserve_shared(gws_bo->tbo.base.resv, 1);
|
||||
ret = dma_resv_reserve_fences(gws_bo->tbo.base.resv, 1);
|
||||
if (ret)
|
||||
goto reserve_shared_fail;
|
||||
amdgpu_bo_fence(gws_bo, &process_info->eviction_fence->base, true);
|
||||
|
|
|
|||
|
|
@ -162,12 +162,14 @@ union vram_info {
|
|||
struct atom_vram_info_header_v2_4 v24;
|
||||
struct atom_vram_info_header_v2_5 v25;
|
||||
struct atom_vram_info_header_v2_6 v26;
|
||||
struct atom_vram_info_header_v3_0 v30;
|
||||
};
|
||||
|
||||
union vram_module {
|
||||
struct atom_vram_module_v9 v9;
|
||||
struct atom_vram_module_v10 v10;
|
||||
struct atom_vram_module_v11 v11;
|
||||
struct atom_vram_module_v3_0 v30;
|
||||
};
|
||||
|
||||
static int convert_atom_mem_type_to_vram_type(struct amdgpu_device *adev,
|
||||
|
|
@ -294,88 +296,116 @@ amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
|
|||
vram_info = (union vram_info *)
|
||||
(mode_info->atom_context->bios + data_offset);
|
||||
module_id = (RREG32(adev->bios_scratch_reg_offset + 4) & 0x00ff0000) >> 16;
|
||||
switch (crev) {
|
||||
case 3:
|
||||
if (module_id > vram_info->v23.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v23.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v9.vram_module_size);
|
||||
i++;
|
||||
if (frev == 3) {
|
||||
switch (crev) {
|
||||
/* v30 */
|
||||
case 0:
|
||||
vram_module = (union vram_module *)vram_info->v30.vram_module;
|
||||
mem_vendor = (vram_module->v30.dram_vendor_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
mem_type = vram_info->v30.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_info->v30.channel_num;
|
||||
mem_channel_width = vram_info->v30.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * mem_channel_width;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
mem_type = vram_module->v9.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v9.channel_num;
|
||||
mem_channel_width = vram_module->v9.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
case 4:
|
||||
if (module_id > vram_info->v24.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v24.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v10.vram_module_size);
|
||||
i++;
|
||||
} else if (frev == 2) {
|
||||
switch (crev) {
|
||||
/* v23 */
|
||||
case 3:
|
||||
if (module_id > vram_info->v23.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v23.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v9.vram_module_size);
|
||||
i++;
|
||||
}
|
||||
mem_type = vram_module->v9.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v9.channel_num;
|
||||
mem_channel_width = vram_module->v9.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
/* v24 */
|
||||
case 4:
|
||||
if (module_id > vram_info->v24.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v24.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v10.vram_module_size);
|
||||
i++;
|
||||
}
|
||||
mem_type = vram_module->v10.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v10.channel_num;
|
||||
mem_channel_width = vram_module->v10.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v10.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
/* v25 */
|
||||
case 5:
|
||||
if (module_id > vram_info->v25.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v25.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v11.vram_module_size);
|
||||
i++;
|
||||
}
|
||||
mem_type = vram_module->v11.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v11.channel_num;
|
||||
mem_channel_width = vram_module->v11.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v11.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
/* v26 */
|
||||
case 6:
|
||||
if (module_id > vram_info->v26.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v26.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v9.vram_module_size);
|
||||
i++;
|
||||
}
|
||||
mem_type = vram_module->v9.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v9.channel_num;
|
||||
mem_channel_width = vram_module->v9.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
mem_type = vram_module->v10.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v10.channel_num;
|
||||
mem_channel_width = vram_module->v10.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v10.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
case 5:
|
||||
if (module_id > vram_info->v25.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v25.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v11.vram_module_size);
|
||||
i++;
|
||||
}
|
||||
mem_type = vram_module->v11.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v11.channel_num;
|
||||
mem_channel_width = vram_module->v11.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v11.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
case 6:
|
||||
if (module_id > vram_info->v26.vram_module_num)
|
||||
module_id = 0;
|
||||
vram_module = (union vram_module *)vram_info->v26.vram_module;
|
||||
while (i < module_id) {
|
||||
vram_module = (union vram_module *)
|
||||
((u8 *)vram_module + vram_module->v9.vram_module_size);
|
||||
i++;
|
||||
}
|
||||
mem_type = vram_module->v9.memory_type;
|
||||
if (vram_type)
|
||||
*vram_type = convert_atom_mem_type_to_vram_type(adev, mem_type);
|
||||
mem_channel_number = vram_module->v9.channel_num;
|
||||
mem_channel_width = vram_module->v9.channel_width;
|
||||
if (vram_width)
|
||||
*vram_width = mem_channel_number * (1 << mem_channel_width);
|
||||
mem_vendor = (vram_module->v9.vender_rev_id) & 0xF;
|
||||
if (vram_vendor)
|
||||
*vram_vendor = mem_vendor;
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
/* invalid frev */
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -526,6 +556,14 @@ bool amdgpu_atomfirmware_ras_rom_addr(struct amdgpu_device *adev,
|
|||
|
||||
union smu_info {
|
||||
struct atom_smu_info_v3_1 v31;
|
||||
struct atom_smu_info_v4_0 v40;
|
||||
};
|
||||
|
||||
union gfx_info {
|
||||
struct atom_gfx_info_v2_2 v22;
|
||||
struct atom_gfx_info_v2_4 v24;
|
||||
struct atom_gfx_info_v2_7 v27;
|
||||
struct atom_gfx_info_v3_0 v30;
|
||||
};
|
||||
|
||||
int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
|
||||
|
|
@ -565,7 +603,10 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
|
|||
data_offset);
|
||||
|
||||
/* system clock */
|
||||
spll->reference_freq = le32_to_cpu(smu_info->v31.core_refclk_10khz);
|
||||
if (frev == 3)
|
||||
spll->reference_freq = le32_to_cpu(smu_info->v31.core_refclk_10khz);
|
||||
else if (frev == 4)
|
||||
spll->reference_freq = le32_to_cpu(smu_info->v40.core_refclk_10khz);
|
||||
|
||||
spll->reference_div = 0;
|
||||
spll->min_post_div = 1;
|
||||
|
|
@ -609,22 +650,26 @@ int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev)
|
|||
gfx_info);
|
||||
if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
|
||||
&frev, &crev, &data_offset)) {
|
||||
struct atom_gfx_info_v2_2 *gfx_info = (struct atom_gfx_info_v2_2*)
|
||||
union gfx_info *gfx_info = (union gfx_info *)
|
||||
(mode_info->atom_context->bios + data_offset);
|
||||
if ((frev == 2) && (crev >= 2))
|
||||
spll->reference_freq = le32_to_cpu(gfx_info->rlc_gpu_timer_refclk);
|
||||
ret = 0;
|
||||
if ((frev == 3) ||
|
||||
(frev == 2 && crev == 6)) {
|
||||
spll->reference_freq = le32_to_cpu(gfx_info->v30.golden_tsc_count_lower_refclk);
|
||||
ret = 0;
|
||||
} else if ((frev == 2) &&
|
||||
(crev >= 2) &&
|
||||
(crev != 6)) {
|
||||
spll->reference_freq = le32_to_cpu(gfx_info->v22.rlc_gpu_timer_refclk);
|
||||
ret = 0;
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
union gfx_info {
|
||||
struct atom_gfx_info_v2_4 v24;
|
||||
struct atom_gfx_info_v2_7 v27;
|
||||
};
|
||||
|
||||
int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_mode_info *mode_info = &adev->mode_info;
|
||||
|
|
@ -638,42 +683,58 @@ int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev)
|
|||
&frev, &crev, &data_offset)) {
|
||||
union gfx_info *gfx_info = (union gfx_info *)
|
||||
(mode_info->atom_context->bios + data_offset);
|
||||
switch (crev) {
|
||||
case 4:
|
||||
adev->gfx.config.max_shader_engines = gfx_info->v24.max_shader_engines;
|
||||
adev->gfx.config.max_cu_per_sh = gfx_info->v24.max_cu_per_sh;
|
||||
adev->gfx.config.max_sh_per_se = gfx_info->v24.max_sh_per_se;
|
||||
adev->gfx.config.max_backends_per_se = gfx_info->v24.max_backends_per_se;
|
||||
adev->gfx.config.max_texture_channel_caches = gfx_info->v24.max_texture_channel_caches;
|
||||
adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v24.gc_num_gprs);
|
||||
adev->gfx.config.max_gs_threads = gfx_info->v24.gc_num_max_gs_thds;
|
||||
adev->gfx.config.gs_vgt_table_depth = gfx_info->v24.gc_gs_table_depth;
|
||||
adev->gfx.config.gs_prim_buffer_depth =
|
||||
le16_to_cpu(gfx_info->v24.gc_gsprim_buff_depth);
|
||||
adev->gfx.config.double_offchip_lds_buf =
|
||||
gfx_info->v24.gc_double_offchip_lds_buffer;
|
||||
adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v24.gc_wave_size);
|
||||
adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v24.gc_max_waves_per_simd);
|
||||
adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v24.gc_max_scratch_slots_per_cu;
|
||||
adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v24.gc_lds_size);
|
||||
return 0;
|
||||
case 7:
|
||||
adev->gfx.config.max_shader_engines = gfx_info->v27.max_shader_engines;
|
||||
adev->gfx.config.max_cu_per_sh = gfx_info->v27.max_cu_per_sh;
|
||||
adev->gfx.config.max_sh_per_se = gfx_info->v27.max_sh_per_se;
|
||||
adev->gfx.config.max_backends_per_se = gfx_info->v27.max_backends_per_se;
|
||||
adev->gfx.config.max_texture_channel_caches = gfx_info->v27.max_texture_channel_caches;
|
||||
adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v27.gc_num_gprs);
|
||||
adev->gfx.config.max_gs_threads = gfx_info->v27.gc_num_max_gs_thds;
|
||||
adev->gfx.config.gs_vgt_table_depth = gfx_info->v27.gc_gs_table_depth;
|
||||
adev->gfx.config.gs_prim_buffer_depth = le16_to_cpu(gfx_info->v27.gc_gsprim_buff_depth);
|
||||
adev->gfx.config.double_offchip_lds_buf = gfx_info->v27.gc_double_offchip_lds_buffer;
|
||||
adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v27.gc_wave_size);
|
||||
adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v27.gc_max_waves_per_simd);
|
||||
adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v27.gc_max_scratch_slots_per_cu;
|
||||
adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v27.gc_lds_size);
|
||||
return 0;
|
||||
default:
|
||||
if (frev == 2) {
|
||||
switch (crev) {
|
||||
case 4:
|
||||
adev->gfx.config.max_shader_engines = gfx_info->v24.max_shader_engines;
|
||||
adev->gfx.config.max_cu_per_sh = gfx_info->v24.max_cu_per_sh;
|
||||
adev->gfx.config.max_sh_per_se = gfx_info->v24.max_sh_per_se;
|
||||
adev->gfx.config.max_backends_per_se = gfx_info->v24.max_backends_per_se;
|
||||
adev->gfx.config.max_texture_channel_caches = gfx_info->v24.max_texture_channel_caches;
|
||||
adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v24.gc_num_gprs);
|
||||
adev->gfx.config.max_gs_threads = gfx_info->v24.gc_num_max_gs_thds;
|
||||
adev->gfx.config.gs_vgt_table_depth = gfx_info->v24.gc_gs_table_depth;
|
||||
adev->gfx.config.gs_prim_buffer_depth =
|
||||
le16_to_cpu(gfx_info->v24.gc_gsprim_buff_depth);
|
||||
adev->gfx.config.double_offchip_lds_buf =
|
||||
gfx_info->v24.gc_double_offchip_lds_buffer;
|
||||
adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v24.gc_wave_size);
|
||||
adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v24.gc_max_waves_per_simd);
|
||||
adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v24.gc_max_scratch_slots_per_cu;
|
||||
adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v24.gc_lds_size);
|
||||
return 0;
|
||||
case 7:
|
||||
adev->gfx.config.max_shader_engines = gfx_info->v27.max_shader_engines;
|
||||
adev->gfx.config.max_cu_per_sh = gfx_info->v27.max_cu_per_sh;
|
||||
adev->gfx.config.max_sh_per_se = gfx_info->v27.max_sh_per_se;
|
||||
adev->gfx.config.max_backends_per_se = gfx_info->v27.max_backends_per_se;
|
||||
adev->gfx.config.max_texture_channel_caches = gfx_info->v27.max_texture_channel_caches;
|
||||
adev->gfx.config.max_gprs = le16_to_cpu(gfx_info->v27.gc_num_gprs);
|
||||
adev->gfx.config.max_gs_threads = gfx_info->v27.gc_num_max_gs_thds;
|
||||
adev->gfx.config.gs_vgt_table_depth = gfx_info->v27.gc_gs_table_depth;
|
||||
adev->gfx.config.gs_prim_buffer_depth = le16_to_cpu(gfx_info->v27.gc_gsprim_buff_depth);
|
||||
adev->gfx.config.double_offchip_lds_buf = gfx_info->v27.gc_double_offchip_lds_buffer;
|
||||
adev->gfx.cu_info.wave_front_size = le16_to_cpu(gfx_info->v27.gc_wave_size);
|
||||
adev->gfx.cu_info.max_waves_per_simd = le16_to_cpu(gfx_info->v27.gc_max_waves_per_simd);
|
||||
adev->gfx.cu_info.max_scratch_slots_per_cu = gfx_info->v27.gc_max_scratch_slots_per_cu;
|
||||
adev->gfx.cu_info.lds_size = le16_to_cpu(gfx_info->v27.gc_lds_size);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (frev == 3) {
|
||||
switch (crev) {
|
||||
case 0:
|
||||
adev->gfx.config.max_shader_engines = gfx_info->v30.max_shader_engines;
|
||||
adev->gfx.config.max_cu_per_sh = gfx_info->v30.max_cu_per_sh;
|
||||
adev->gfx.config.max_sh_per_se = gfx_info->v30.max_sh_per_se;
|
||||
adev->gfx.config.max_backends_per_se = gfx_info->v30.max_backends_per_se;
|
||||
adev->gfx.config.max_texture_channel_caches = gfx_info->v30.max_texture_channel_caches;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -731,3 +792,67 @@ int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev)
|
|||
|
||||
return fw_reserved_fb_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to execute asic_init table
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @fb_reset: flag to indicate whether fb is reset or not
|
||||
*
|
||||
* Return 0 if succeed, otherwise failed
|
||||
*/
|
||||
int amdgpu_atomfirmware_asic_init(struct amdgpu_device *adev, bool fb_reset)
|
||||
{
|
||||
struct amdgpu_mode_info *mode_info = &adev->mode_info;
|
||||
struct atom_context *ctx;
|
||||
uint8_t frev, crev;
|
||||
uint16_t data_offset;
|
||||
uint32_t bootup_sclk_in10khz, bootup_mclk_in10khz;
|
||||
struct asic_init_ps_allocation_v2_1 asic_init_ps_v2_1;
|
||||
int index;
|
||||
|
||||
if (!mode_info)
|
||||
return -EINVAL;
|
||||
|
||||
ctx = mode_info->atom_context;
|
||||
if (!ctx)
|
||||
return -EINVAL;
|
||||
|
||||
/* query bootup sclk/mclk from firmware_info table */
|
||||
index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
|
||||
firmwareinfo);
|
||||
if (amdgpu_atom_parse_data_header(ctx, index, NULL,
|
||||
&frev, &crev, &data_offset)) {
|
||||
union firmware_info *firmware_info =
|
||||
(union firmware_info *)(ctx->bios +
|
||||
data_offset);
|
||||
|
||||
bootup_sclk_in10khz =
|
||||
le32_to_cpu(firmware_info->v31.bootup_sclk_in10khz);
|
||||
bootup_mclk_in10khz =
|
||||
le32_to_cpu(firmware_info->v31.bootup_mclk_in10khz);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1,
|
||||
asic_init);
|
||||
if (amdgpu_atom_parse_cmd_header(mode_info->atom_context, index, &frev, &crev)) {
|
||||
if (frev == 2 && crev >= 1) {
|
||||
memset(&asic_init_ps_v2_1, 0, sizeof(asic_init_ps_v2_1));
|
||||
asic_init_ps_v2_1.param.engineparam.sclkfreqin10khz = bootup_sclk_in10khz;
|
||||
asic_init_ps_v2_1.param.memparam.mclkfreqin10khz = bootup_mclk_in10khz;
|
||||
asic_init_ps_v2_1.param.engineparam.engineflag = b3NORMAL_ENGINE_INIT;
|
||||
if (!fb_reset)
|
||||
asic_init_ps_v2_1.param.memparam.memflag = b3DRAM_SELF_REFRESH_EXIT;
|
||||
else
|
||||
asic_init_ps_v2_1.param.memparam.memflag = 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return amdgpu_atom_execute_table(ctx, ATOM_CMD_INIT, (uint32_t *)&asic_init_ps_v2_1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,5 +40,6 @@ bool amdgpu_atomfirmware_ras_rom_addr(struct amdgpu_device *adev, uint8_t* i2c_a
|
|||
bool amdgpu_atomfirmware_mem_training_supported(struct amdgpu_device *adev);
|
||||
bool amdgpu_atomfirmware_dynamic_boot_config_supported(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_get_fw_reserved_fb_size(struct amdgpu_device *adev);
|
||||
int amdgpu_atomfirmware_asic_init(struct amdgpu_device *adev, bool fb_reset);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -471,6 +471,7 @@ bool amdgpu_soc15_read_bios_from_rom(struct amdgpu_device *adev,
|
|||
{
|
||||
u32 *dw_ptr;
|
||||
u32 i, length_dw;
|
||||
u32 rom_offset;
|
||||
u32 rom_index_offset;
|
||||
u32 rom_data_offset;
|
||||
|
||||
|
|
@ -494,8 +495,16 @@ bool amdgpu_soc15_read_bios_from_rom(struct amdgpu_device *adev,
|
|||
rom_data_offset =
|
||||
adev->smuio.funcs->get_rom_data_offset(adev);
|
||||
|
||||
/* set rom index to 0 */
|
||||
WREG32(rom_index_offset, 0);
|
||||
if (adev->nbio.funcs &&
|
||||
adev->nbio.funcs->get_rom_offset) {
|
||||
rom_offset = adev->nbio.funcs->get_rom_offset(adev);
|
||||
rom_offset = rom_offset << 17;
|
||||
} else {
|
||||
rom_offset = 0;
|
||||
}
|
||||
|
||||
/* set rom index to rom_offset */
|
||||
WREG32(rom_index_offset, rom_offset);
|
||||
/* read out the rom data */
|
||||
for (i = 0; i < length_dw; i++)
|
||||
dw_ptr[i] = RREG32(rom_data_offset);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ struct amdgpu_fpriv;
|
|||
struct amdgpu_bo_list_entry {
|
||||
struct ttm_validate_buffer tv;
|
||||
struct amdgpu_bo_va *bo_va;
|
||||
struct dma_fence_chain *chain;
|
||||
uint32_t priority;
|
||||
struct page **user_pages;
|
||||
bool user_invalidated;
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@
|
|||
* Alex Deucher
|
||||
*/
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/dp/drm_dp_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/amdgpu_drm.h>
|
||||
#include "amdgpu.h"
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
|
|||
bo = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
|
||||
p->uf_entry.priority = 0;
|
||||
p->uf_entry.tv.bo = &bo->tbo;
|
||||
/* One for TTM and one for the CS job */
|
||||
p->uf_entry.tv.num_shared = 2;
|
||||
/* One for TTM and two for the CS job */
|
||||
p->uf_entry.tv.num_shared = 3;
|
||||
|
||||
drm_gem_object_put(gobj);
|
||||
|
||||
|
|
@ -545,14 +545,15 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
|||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!e->user_pages) {
|
||||
DRM_ERROR("kvmalloc_array failure\n");
|
||||
return -ENOMEM;
|
||||
r = -ENOMEM;
|
||||
goto out_free_user_pages;
|
||||
}
|
||||
|
||||
r = amdgpu_ttm_tt_get_user_pages(bo, e->user_pages);
|
||||
if (r) {
|
||||
kvfree(e->user_pages);
|
||||
e->user_pages = NULL;
|
||||
return r;
|
||||
goto out_free_user_pages;
|
||||
}
|
||||
|
||||
for (i = 0; i < bo->tbo.ttm->num_pages; i++) {
|
||||
|
|
@ -569,21 +570,13 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
|||
if (unlikely(r != 0)) {
|
||||
if (r != -ERESTARTSYS)
|
||||
DRM_ERROR("ttm_eu_reserve_buffers failed.\n");
|
||||
goto out;
|
||||
goto out_free_user_pages;
|
||||
}
|
||||
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
|
||||
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
|
||||
|
||||
e->bo_va = amdgpu_vm_bo_find(vm, bo);
|
||||
|
||||
if (bo->tbo.base.dma_buf && !amdgpu_bo_explicit_sync(bo)) {
|
||||
e->chain = dma_fence_chain_alloc();
|
||||
if (!e->chain) {
|
||||
r = -ENOMEM;
|
||||
goto error_validate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Move fence waiting after getting reservation lock of
|
||||
|
|
@ -644,14 +637,21 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
|
|||
}
|
||||
|
||||
error_validate:
|
||||
if (r) {
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
|
||||
dma_fence_chain_free(e->chain);
|
||||
e->chain = NULL;
|
||||
}
|
||||
if (r)
|
||||
ttm_eu_backoff_reservation(&p->ticket, &p->validated);
|
||||
|
||||
out_free_user_pages:
|
||||
if (r) {
|
||||
amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) {
|
||||
struct amdgpu_bo *bo = ttm_to_amdgpu_bo(e->tv.bo);
|
||||
|
||||
if (!e->user_pages)
|
||||
continue;
|
||||
amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm);
|
||||
kvfree(e->user_pages);
|
||||
e->user_pages = NULL;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -690,17 +690,9 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error,
|
|||
{
|
||||
unsigned i;
|
||||
|
||||
if (error && backoff) {
|
||||
struct amdgpu_bo_list_entry *e;
|
||||
|
||||
amdgpu_bo_list_for_each_entry(e, parser->bo_list) {
|
||||
dma_fence_chain_free(e->chain);
|
||||
e->chain = NULL;
|
||||
}
|
||||
|
||||
if (error && backoff)
|
||||
ttm_eu_backoff_reservation(&parser->ticket,
|
||||
&parser->validated);
|
||||
}
|
||||
|
||||
for (i = 0; i < parser->num_post_deps; i++) {
|
||||
drm_syncobj_put(parser->post_deps[i].syncobj);
|
||||
|
|
@ -809,22 +801,22 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false, NULL);
|
||||
r = amdgpu_vm_bo_update(adev, fpriv->prt_va, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, fpriv->prt_va->last_pt_update);
|
||||
r = amdgpu_sync_fence(&p->job->sync, fpriv->prt_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) {
|
||||
bo_va = fpriv->csa_va;
|
||||
BUG_ON(!bo_va);
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, bo_va->last_pt_update);
|
||||
r = amdgpu_sync_fence(&p->job->sync, bo_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
|
@ -839,11 +831,11 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
|||
if (bo_va == NULL)
|
||||
continue;
|
||||
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, bo_va->last_pt_update);
|
||||
r = amdgpu_sync_fence(&p->job->sync, bo_va->last_pt_update);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
|
@ -856,7 +848,7 @@ static int amdgpu_cs_vm_handling(struct amdgpu_cs_parser *p)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
r = amdgpu_sync_vm_fence(&p->job->sync, vm->last_update);
|
||||
r = amdgpu_sync_fence(&p->job->sync, vm->last_update);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
|
@ -1280,24 +1272,9 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p,
|
|||
|
||||
amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm);
|
||||
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list) {
|
||||
struct dma_resv *resv = e->tv.bo->base.resv;
|
||||
struct dma_fence_chain *chain = e->chain;
|
||||
|
||||
if (!chain)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Work around dma_resv shortcomings by wrapping up the
|
||||
* submission in a dma_fence_chain and add it as exclusive
|
||||
* fence.
|
||||
*/
|
||||
dma_fence_chain_init(chain, dma_resv_excl_fence(resv),
|
||||
dma_fence_get(p->fence), 1);
|
||||
|
||||
rcu_assign_pointer(resv->fence_excl, &chain->base);
|
||||
e->chain = NULL;
|
||||
}
|
||||
/* Make sure all BOs are remembered as writers */
|
||||
amdgpu_bo_list_for_each_entry(e, p->bo_list)
|
||||
e->tv.num_shared = 0;
|
||||
|
||||
ttm_eu_fence_buffer_objects(&p->ticket, &p->validated, p->fence);
|
||||
mutex_unlock(&p->adev->notifier_lock);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "amdgpu_umr.h"
|
||||
|
||||
#include "amdgpu_reset.h"
|
||||
#include "amdgpu_psp_ta.h"
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
|
|
@ -730,7 +731,7 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
|
|||
return -ENOMEM;
|
||||
|
||||
/* version, increment each time something is added */
|
||||
config[no_regs++] = 4;
|
||||
config[no_regs++] = 5;
|
||||
config[no_regs++] = adev->gfx.config.max_shader_engines;
|
||||
config[no_regs++] = adev->gfx.config.max_tile_pipes;
|
||||
config[no_regs++] = adev->gfx.config.max_cu_per_sh;
|
||||
|
|
@ -757,8 +758,8 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
|
|||
|
||||
/* rev==1 */
|
||||
config[no_regs++] = adev->rev_id;
|
||||
config[no_regs++] = adev->pg_flags;
|
||||
config[no_regs++] = adev->cg_flags;
|
||||
config[no_regs++] = lower_32_bits(adev->pg_flags);
|
||||
config[no_regs++] = lower_32_bits(adev->cg_flags);
|
||||
|
||||
/* rev==2 */
|
||||
config[no_regs++] = adev->family;
|
||||
|
|
@ -773,6 +774,10 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf,
|
|||
/* rev==4 APU flag */
|
||||
config[no_regs++] = adev->flags & AMD_IS_APU ? 1 : 0;
|
||||
|
||||
/* rev==5 PG/CG flag upper 32bit */
|
||||
config[no_regs++] = upper_32_bits(adev->pg_flags);
|
||||
config[no_regs++] = upper_32_bits(adev->cg_flags);
|
||||
|
||||
while (size && (*pos < no_regs * 4)) {
|
||||
uint32_t value;
|
||||
|
||||
|
|
@ -1763,6 +1768,7 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev)
|
|||
DRM_ERROR("registering register debugfs failed (%d).\n", r);
|
||||
|
||||
amdgpu_debugfs_firmware_init(adev);
|
||||
amdgpu_ta_if_debugfs_init(adev);
|
||||
|
||||
#if defined(CONFIG_DRM_AMD_DC)
|
||||
if (amdgpu_device_has_dc_support(adev))
|
||||
|
|
|
|||
|
|
@ -913,7 +913,10 @@ static int amdgpu_device_asic_init(struct amdgpu_device *adev)
|
|||
{
|
||||
amdgpu_asic_pre_asic_init(adev);
|
||||
|
||||
return amdgpu_atom_asic_init(adev->mode_info.atom_context);
|
||||
if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(11, 0, 0))
|
||||
return amdgpu_atomfirmware_asic_init(adev, true);
|
||||
else
|
||||
return amdgpu_atom_asic_init(adev->mode_info.atom_context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1041,19 +1044,25 @@ static int amdgpu_device_doorbell_init(struct amdgpu_device *adev)
|
|||
adev->doorbell.base = pci_resource_start(adev->pdev, 2);
|
||||
adev->doorbell.size = pci_resource_len(adev->pdev, 2);
|
||||
|
||||
adev->doorbell.num_doorbells = min_t(u32, adev->doorbell.size / sizeof(u32),
|
||||
adev->doorbell_index.max_assignment+1);
|
||||
if (adev->doorbell.num_doorbells == 0)
|
||||
return -EINVAL;
|
||||
if (adev->enable_mes) {
|
||||
adev->doorbell.num_doorbells =
|
||||
adev->doorbell.size / sizeof(u32);
|
||||
} else {
|
||||
adev->doorbell.num_doorbells =
|
||||
min_t(u32, adev->doorbell.size / sizeof(u32),
|
||||
adev->doorbell_index.max_assignment+1);
|
||||
if (adev->doorbell.num_doorbells == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* For Vega, reserve and map two pages on doorbell BAR since SDMA
|
||||
* paging queue doorbell use the second page. The
|
||||
* AMDGPU_DOORBELL64_MAX_ASSIGNMENT definition assumes all the
|
||||
* doorbells are in the first page. So with paging queue enabled,
|
||||
* the max num_doorbells should + 1 page (0x400 in dword)
|
||||
*/
|
||||
if (adev->asic_type >= CHIP_VEGA10)
|
||||
adev->doorbell.num_doorbells += 0x400;
|
||||
/* For Vega, reserve and map two pages on doorbell BAR since SDMA
|
||||
* paging queue doorbell use the second page. The
|
||||
* AMDGPU_DOORBELL64_MAX_ASSIGNMENT definition assumes all the
|
||||
* doorbells are in the first page. So with paging queue enabled,
|
||||
* the max num_doorbells should + 1 page (0x400 in dword)
|
||||
*/
|
||||
if (adev->asic_type >= CHIP_VEGA10)
|
||||
adev->doorbell.num_doorbells += 0x400;
|
||||
}
|
||||
|
||||
adev->doorbell.ptr = ioremap(adev->doorbell.base,
|
||||
adev->doorbell.num_doorbells *
|
||||
|
|
@ -1703,7 +1712,7 @@ int amdgpu_device_ip_set_powergating_state(void *dev,
|
|||
* clockgating is enabled.
|
||||
*/
|
||||
void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
|
||||
u32 *flags)
|
||||
u64 *flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -1926,11 +1935,9 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
|
|||
adev->firmware.gpu_info_fw = NULL;
|
||||
|
||||
if (adev->mman.discovery_bin) {
|
||||
amdgpu_discovery_get_gfx_info(adev);
|
||||
|
||||
/*
|
||||
* FIXME: The bounding box is still needed by Navi12, so
|
||||
* temporarily read it from gpu_info firmware. Should be droped
|
||||
* temporarily read it from gpu_info firmware. Should be dropped
|
||||
* when DAL no longer needs it.
|
||||
*/
|
||||
if (adev->asic_type != CHIP_NAVI12)
|
||||
|
|
@ -3663,8 +3670,13 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
if (amdgpu_mcbp)
|
||||
DRM_INFO("MCBP is enabled\n");
|
||||
|
||||
if (amdgpu_mes && adev->asic_type >= CHIP_NAVI10)
|
||||
adev->enable_mes = true;
|
||||
if (adev->asic_type >= CHIP_NAVI10) {
|
||||
if (amdgpu_mes || amdgpu_mes_kiq)
|
||||
adev->enable_mes = true;
|
||||
|
||||
if (amdgpu_mes_kiq)
|
||||
adev->enable_mes_kiq = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset domain needs to be present early, before XGMI hive discovered
|
||||
|
|
@ -3700,7 +3712,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
|||
/* enable PCIE atomic ops */
|
||||
if (amdgpu_sriov_vf(adev))
|
||||
adev->have_atomics_support = ((struct amd_sriov_msg_pf2vf_info *)
|
||||
adev->virt.fw_reserve.p_pf2vf)->pcie_atomic_ops_enabled_flags ==
|
||||
adev->virt.fw_reserve.p_pf2vf)->pcie_atomic_ops_support_flags ==
|
||||
(PCI_EXP_DEVCAP2_ATOMIC_COMP32 | PCI_EXP_DEVCAP2_ATOMIC_COMP64);
|
||||
else
|
||||
adev->have_atomics_support =
|
||||
|
|
@ -3857,6 +3869,14 @@ fence_driver_init:
|
|||
} else
|
||||
adev->ucode_sysfs_en = true;
|
||||
|
||||
r = amdgpu_psp_sysfs_init(adev);
|
||||
if (r) {
|
||||
adev->psp_sysfs_en = false;
|
||||
if (!amdgpu_sriov_vf(adev))
|
||||
DRM_ERROR("Creating psp sysfs failed\n");
|
||||
} else
|
||||
adev->psp_sysfs_en = true;
|
||||
|
||||
/*
|
||||
* Register gpu instance before amdgpu_device_enable_mgpu_fan_boost.
|
||||
* Otherwise the mgpu fan boost feature will be skipped due to the
|
||||
|
|
@ -3960,10 +3980,6 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
|
|||
{
|
||||
dev_info(adev->dev, "amdgpu: finishing device.\n");
|
||||
flush_delayed_work(&adev->delayed_init_work);
|
||||
if (adev->mman.initialized) {
|
||||
flush_delayed_work(&adev->mman.bdev.wq);
|
||||
ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
|
||||
}
|
||||
adev->shutdown = true;
|
||||
|
||||
/* make sure IB test finished before entering exclusive mode
|
||||
|
|
@ -3984,10 +4000,17 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
|
|||
}
|
||||
amdgpu_fence_driver_hw_fini(adev);
|
||||
|
||||
if (adev->mman.initialized) {
|
||||
flush_delayed_work(&adev->mman.bdev.wq);
|
||||
ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
|
||||
}
|
||||
|
||||
if (adev->pm_sysfs_en)
|
||||
amdgpu_pm_sysfs_fini(adev);
|
||||
if (adev->ucode_sysfs_en)
|
||||
amdgpu_ucode_sysfs_fini(adev);
|
||||
if (adev->psp_sysfs_en)
|
||||
amdgpu_psp_sysfs_fini(adev);
|
||||
sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes);
|
||||
|
||||
/* disable ras feature must before hw fini */
|
||||
|
|
@ -4486,6 +4509,7 @@ retry:
|
|||
if (!r) {
|
||||
amdgpu_irq_gpu_reset_resume_helper(adev);
|
||||
r = amdgpu_ib_ring_tests(adev);
|
||||
|
||||
amdgpu_amdkfd_post_reset(adev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct amdgpu_df_funcs {
|
|||
void (*update_medium_grain_clock_gating)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*get_clockgating_state)(struct amdgpu_device *adev,
|
||||
u32 *flags);
|
||||
u64 *flags);
|
||||
void (*enable_ecc_force_par_wr_rmw)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
int (*pmc_start)(struct amdgpu_device *adev, uint64_t config,
|
||||
|
|
|
|||
|
|
@ -47,25 +47,39 @@
|
|||
#include "jpeg_v2_5.h"
|
||||
#include "smuio_v9_0.h"
|
||||
#include "gmc_v10_0.h"
|
||||
#include "gmc_v11_0.h"
|
||||
#include "gfxhub_v2_0.h"
|
||||
#include "mmhub_v2_0.h"
|
||||
#include "nbio_v2_3.h"
|
||||
#include "nbio_v4_3.h"
|
||||
#include "nbio_v7_2.h"
|
||||
#include "nbio_v7_7.h"
|
||||
#include "hdp_v5_0.h"
|
||||
#include "hdp_v5_2.h"
|
||||
#include "hdp_v6_0.h"
|
||||
#include "nv.h"
|
||||
#include "soc21.h"
|
||||
#include "navi10_ih.h"
|
||||
#include "ih_v6_0.h"
|
||||
#include "gfx_v10_0.h"
|
||||
#include "gfx_v11_0.h"
|
||||
#include "sdma_v5_0.h"
|
||||
#include "sdma_v5_2.h"
|
||||
#include "sdma_v6_0.h"
|
||||
#include "lsdma_v6_0.h"
|
||||
#include "vcn_v2_0.h"
|
||||
#include "jpeg_v2_0.h"
|
||||
#include "vcn_v3_0.h"
|
||||
#include "jpeg_v3_0.h"
|
||||
#include "vcn_v4_0.h"
|
||||
#include "jpeg_v4_0.h"
|
||||
#include "amdgpu_vkms.h"
|
||||
#include "mes_v10_1.h"
|
||||
#include "mes_v11_0.h"
|
||||
#include "smuio_v11_0.h"
|
||||
#include "smuio_v11_0_6.h"
|
||||
#include "smuio_v13_0.h"
|
||||
#include "smuio_v13_0_6.h"
|
||||
|
||||
#define FIRMWARE_IP_DISCOVERY "amdgpu/ip_discovery.bin"
|
||||
MODULE_FIRMWARE(FIRMWARE_IP_DISCOVERY);
|
||||
|
|
@ -111,6 +125,7 @@ static const char *hw_id_names[HW_ID_MAX] = {
|
|||
[SDMA1_HWID] = "SDMA1",
|
||||
[SDMA2_HWID] = "SDMA2",
|
||||
[SDMA3_HWID] = "SDMA3",
|
||||
[LSDMA_HWID] = "LSDMA",
|
||||
[ISP_HWID] = "ISP",
|
||||
[DBGU_IO_HWID] = "DBGU_IO",
|
||||
[DF_HWID] = "DF",
|
||||
|
|
@ -160,6 +175,7 @@ static int hw_id_map[MAX_HWIP] = {
|
|||
[SDMA1_HWIP] = SDMA1_HWID,
|
||||
[SDMA2_HWIP] = SDMA2_HWID,
|
||||
[SDMA3_HWIP] = SDMA3_HWID,
|
||||
[LSDMA_HWIP] = LSDMA_HWID,
|
||||
[MMHUB_HWIP] = MMHUB_HWID,
|
||||
[ATHUB_HWIP] = ATHUB_HWID,
|
||||
[NBIO_HWIP] = NBIF_HWID,
|
||||
|
|
@ -271,8 +287,6 @@ 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;
|
||||
uint16_t offset;
|
||||
uint16_t size;
|
||||
uint16_t checksum;
|
||||
|
|
@ -290,7 +304,7 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if(!amdgpu_discovery_verify_binary_signature(adev->mman.discovery_bin)) {
|
||||
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);
|
||||
|
|
@ -324,31 +338,110 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev)
|
|||
info = &bhdr->table_list[IP_DISCOVERY];
|
||||
offset = le16_to_cpu(info->offset);
|
||||
checksum = le16_to_cpu(info->checksum);
|
||||
ihdr = (struct ip_discovery_header *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
if (le32_to_cpu(ihdr->signature) != DISCOVERY_TABLE_SIGNATURE) {
|
||||
dev_err(adev->dev, "invalid ip discovery data table signature\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (offset) {
|
||||
struct ip_discovery_header *ihdr =
|
||||
(struct ip_discovery_header *)(adev->mman.discovery_bin + offset);
|
||||
if (le32_to_cpu(ihdr->signature) != DISCOVERY_TABLE_SIGNATURE) {
|
||||
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)) {
|
||||
dev_err(adev->dev, "invalid ip discovery data table checksum\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
|
||||
le16_to_cpu(ihdr->size), checksum)) {
|
||||
dev_err(adev->dev, "invalid ip discovery data table checksum\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
info = &bhdr->table_list[GC];
|
||||
offset = le16_to_cpu(info->offset);
|
||||
checksum = le16_to_cpu(info->checksum);
|
||||
ghdr = (struct gpu_info_header *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
|
||||
le32_to_cpu(ghdr->size), checksum)) {
|
||||
dev_err(adev->dev, "invalid gc data table checksum\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
if (offset) {
|
||||
struct gpu_info_header *ghdr =
|
||||
(struct gpu_info_header *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
if (le32_to_cpu(ghdr->table_id) != GC_TABLE_ID) {
|
||||
dev_err(adev->dev, "invalid ip discovery gc table id\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
|
||||
le32_to_cpu(ghdr->size), checksum)) {
|
||||
dev_err(adev->dev, "invalid gc data table checksum\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
info = &bhdr->table_list[HARVEST_INFO];
|
||||
offset = le16_to_cpu(info->offset);
|
||||
checksum = le16_to_cpu(info->checksum);
|
||||
|
||||
if (offset) {
|
||||
struct harvest_info_header *hhdr =
|
||||
(struct harvest_info_header *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
if (le32_to_cpu(hhdr->signature) != HARVEST_TABLE_SIGNATURE) {
|
||||
dev_err(adev->dev, "invalid ip discovery harvest table signature\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
|
||||
sizeof(struct harvest_table), checksum)) {
|
||||
dev_err(adev->dev, "invalid harvest data table checksum\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
info = &bhdr->table_list[VCN_INFO];
|
||||
offset = le16_to_cpu(info->offset);
|
||||
checksum = le16_to_cpu(info->checksum);
|
||||
|
||||
if (offset) {
|
||||
struct vcn_info_header *vhdr =
|
||||
(struct vcn_info_header *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
if (le32_to_cpu(vhdr->table_id) != VCN_INFO_TABLE_ID) {
|
||||
dev_err(adev->dev, "invalid ip discovery vcn table id\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
|
||||
le32_to_cpu(vhdr->size_bytes), checksum)) {
|
||||
dev_err(adev->dev, "invalid vcn data table checksum\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
info = &bhdr->table_list[MALL_INFO];
|
||||
offset = le16_to_cpu(info->offset);
|
||||
checksum = le16_to_cpu(info->checksum);
|
||||
|
||||
if (0 && offset) {
|
||||
struct mall_info_header *mhdr =
|
||||
(struct mall_info_header *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
if (le32_to_cpu(mhdr->table_id) != MALL_INFO_TABLE_ID) {
|
||||
dev_err(adev->dev, "invalid ip discovery mall table id\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!amdgpu_discovery_verify_checksum(adev->mman.discovery_bin + offset,
|
||||
le32_to_cpu(mhdr->size_bytes), checksum)) {
|
||||
dev_err(adev->dev, "invalid mall data table checksum\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -430,21 +523,30 @@ static void amdgpu_discovery_read_harvest_bit_per_ip(struct amdgpu_device *adev,
|
|||
}
|
||||
}
|
||||
next_ip:
|
||||
ip_offset += sizeof(*ip) + 4 * (ip->num_base_address - 1);
|
||||
ip_offset += struct_size(ip, base_address, ip->num_base_address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev,
|
||||
uint32_t *vcn_harvest_count)
|
||||
uint32_t *vcn_harvest_count,
|
||||
uint32_t *umc_harvest_count)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
struct harvest_table *harvest_info;
|
||||
u16 offset;
|
||||
int i;
|
||||
|
||||
bhdr = (struct binary_header *)adev->mman.discovery_bin;
|
||||
harvest_info = (struct harvest_table *)(adev->mman.discovery_bin +
|
||||
le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset));
|
||||
offset = le16_to_cpu(bhdr->table_list[HARVEST_INFO].offset);
|
||||
|
||||
if (!offset) {
|
||||
dev_err(adev->dev, "invalid harvest table offset\n");
|
||||
return;
|
||||
}
|
||||
|
||||
harvest_info = (struct harvest_table *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (le16_to_cpu(harvest_info->list[i].hw_id) == 0)
|
||||
break;
|
||||
|
|
@ -460,6 +562,9 @@ static void amdgpu_discovery_read_from_harvest_table(struct amdgpu_device *adev,
|
|||
case DMU_HWID:
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_DMU_MASK;
|
||||
break;
|
||||
case UMC_HWID:
|
||||
(*umc_harvest_count)++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -798,7 +903,7 @@ static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev,
|
|||
res = kobject_add(&ip_hw_instance->kobj, NULL,
|
||||
"%d", ip_hw_instance->num_instance);
|
||||
next_ip:
|
||||
ip_offset += sizeof(*ip) + 4 * (ip->num_base_address - 1);
|
||||
ip_offset += struct_size(ip, base_address, ip->num_base_address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -957,7 +1062,7 @@ static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
|
||||
static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
struct ip_discovery_header *ihdr;
|
||||
|
|
@ -1033,6 +1138,9 @@ int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
|
|||
le16_to_cpu(ip->hw_id) == SDMA3_HWID)
|
||||
adev->sdma.num_instances++;
|
||||
|
||||
if (le16_to_cpu(ip->hw_id) == UMC_HWID)
|
||||
adev->gmc.num_umc++;
|
||||
|
||||
for (k = 0; k < num_base_address; k++) {
|
||||
/*
|
||||
* convert the endianness of base addresses in place,
|
||||
|
|
@ -1063,7 +1171,7 @@ int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev)
|
|||
}
|
||||
|
||||
next_ip:
|
||||
ip_offset += sizeof(*ip) + 4 * (ip->num_base_address - 1);
|
||||
ip_offset += struct_size(ip, base_address, ip->num_base_address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1113,16 +1221,17 @@ int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, int n
|
|||
*revision = ip->revision;
|
||||
return 0;
|
||||
}
|
||||
ip_offset += sizeof(*ip) + 4 * (ip->num_base_address - 1);
|
||||
ip_offset += struct_size(ip, base_address, ip->num_base_address);
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
|
||||
static void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
|
||||
{
|
||||
int vcn_harvest_count = 0;
|
||||
int umc_harvest_count = 0;
|
||||
|
||||
/*
|
||||
* Harvest table does not fit Navi1x and legacy GPUs,
|
||||
|
|
@ -1141,7 +1250,8 @@ void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
|
|||
&vcn_harvest_count);
|
||||
} else {
|
||||
amdgpu_discovery_read_from_harvest_table(adev,
|
||||
&vcn_harvest_count);
|
||||
&vcn_harvest_count,
|
||||
&umc_harvest_count);
|
||||
}
|
||||
|
||||
amdgpu_discovery_harvest_config_quirk(adev);
|
||||
|
|
@ -1150,24 +1260,24 @@ void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev)
|
|||
adev->harvest_ip_mask |= AMD_HARVEST_IP_VCN_MASK;
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_JPEG_MASK;
|
||||
}
|
||||
if ((adev->pdev->device == 0x731E &&
|
||||
(adev->pdev->revision == 0xC6 || adev->pdev->revision == 0xC7)) ||
|
||||
(adev->pdev->device == 0x7340 && adev->pdev->revision == 0xC9) ||
|
||||
(adev->pdev->device == 0x7360 && adev->pdev->revision == 0xC7)) {
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_VCN_MASK;
|
||||
adev->harvest_ip_mask |= AMD_HARVEST_IP_JPEG_MASK;
|
||||
|
||||
if (umc_harvest_count < adev->gmc.num_umc) {
|
||||
adev->gmc.num_umc -= umc_harvest_count;
|
||||
}
|
||||
}
|
||||
|
||||
union gc_info {
|
||||
struct gc_info_v1_0 v1;
|
||||
struct gc_info_v1_1 v1_1;
|
||||
struct gc_info_v1_2 v1_2;
|
||||
struct gc_info_v2_0 v2;
|
||||
};
|
||||
|
||||
int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
|
||||
static int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
union gc_info *gc_info;
|
||||
u16 offset;
|
||||
|
||||
if (!adev->mman.discovery_bin) {
|
||||
DRM_ERROR("ip discovery uninitialized\n");
|
||||
|
|
@ -1175,9 +1285,14 @@ int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
|
|||
}
|
||||
|
||||
bhdr = (struct binary_header *)adev->mman.discovery_bin;
|
||||
gc_info = (union gc_info *)(adev->mman.discovery_bin +
|
||||
le16_to_cpu(bhdr->table_list[GC].offset));
|
||||
switch (gc_info->v1.header.version_major) {
|
||||
offset = le16_to_cpu(bhdr->table_list[GC].offset);
|
||||
|
||||
if (!offset)
|
||||
return 0;
|
||||
|
||||
gc_info = (union gc_info *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
switch (le16_to_cpu(gc_info->v1.header.version_major)) {
|
||||
case 1:
|
||||
adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->v1.gc_num_se);
|
||||
adev->gfx.config.max_cu_per_sh = 2 * (le32_to_cpu(gc_info->v1.gc_num_wgp0_per_sa) +
|
||||
|
|
@ -1197,6 +1312,21 @@ int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
|
|||
adev->gfx.config.num_sc_per_sh = le32_to_cpu(gc_info->v1.gc_num_sc_per_se) /
|
||||
le32_to_cpu(gc_info->v1.gc_num_sa_per_se);
|
||||
adev->gfx.config.num_packer_per_sc = le32_to_cpu(gc_info->v1.gc_num_packer_per_sc);
|
||||
if (gc_info->v1.header.version_minor >= 1) {
|
||||
adev->gfx.config.gc_num_tcp_per_sa = le32_to_cpu(gc_info->v1_1.gc_num_tcp_per_sa);
|
||||
adev->gfx.config.gc_num_sdp_interface = le32_to_cpu(gc_info->v1_1.gc_num_sdp_interface);
|
||||
adev->gfx.config.gc_num_tcps = le32_to_cpu(gc_info->v1_1.gc_num_tcps);
|
||||
}
|
||||
if (gc_info->v1.header.version_minor >= 2) {
|
||||
adev->gfx.config.gc_num_tcp_per_wpg = le32_to_cpu(gc_info->v1_2.gc_num_tcp_per_wpg);
|
||||
adev->gfx.config.gc_tcp_l1_size = le32_to_cpu(gc_info->v1_2.gc_tcp_l1_size);
|
||||
adev->gfx.config.gc_num_sqc_per_wgp = le32_to_cpu(gc_info->v1_2.gc_num_sqc_per_wgp);
|
||||
adev->gfx.config.gc_l1_instruction_cache_size_per_sqc = le32_to_cpu(gc_info->v1_2.gc_l1_instruction_cache_size_per_sqc);
|
||||
adev->gfx.config.gc_l1_data_cache_size_per_sqc = le32_to_cpu(gc_info->v1_2.gc_l1_data_cache_size_per_sqc);
|
||||
adev->gfx.config.gc_gl1c_per_sa = le32_to_cpu(gc_info->v1_2.gc_gl1c_per_sa);
|
||||
adev->gfx.config.gc_gl1c_size_per_instance = le32_to_cpu(gc_info->v1_2.gc_gl1c_size_per_instance);
|
||||
adev->gfx.config.gc_gl2c_per_gpu = le32_to_cpu(gc_info->v1_2.gc_gl2c_per_gpu);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
adev->gfx.config.max_shader_engines = le32_to_cpu(gc_info->v2.gc_num_se);
|
||||
|
|
@ -1220,8 +1350,105 @@ int amdgpu_discovery_get_gfx_info(struct amdgpu_device *adev)
|
|||
default:
|
||||
dev_err(adev->dev,
|
||||
"Unhandled GC info table %d.%d\n",
|
||||
gc_info->v1.header.version_major,
|
||||
gc_info->v1.header.version_minor);
|
||||
le16_to_cpu(gc_info->v1.header.version_major),
|
||||
le16_to_cpu(gc_info->v1.header.version_minor));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
union mall_info {
|
||||
struct mall_info_v1_0 v1;
|
||||
};
|
||||
|
||||
int amdgpu_discovery_get_mall_info(struct amdgpu_device *adev)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
union mall_info *mall_info;
|
||||
u32 u, mall_size_per_umc, m_s_present, half_use;
|
||||
u64 mall_size;
|
||||
u16 offset;
|
||||
|
||||
if (!adev->mman.discovery_bin) {
|
||||
DRM_ERROR("ip discovery uninitialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bhdr = (struct binary_header *)adev->mman.discovery_bin;
|
||||
offset = le16_to_cpu(bhdr->table_list[MALL_INFO].offset);
|
||||
|
||||
if (!offset)
|
||||
return 0;
|
||||
|
||||
mall_info = (union mall_info *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
switch (le16_to_cpu(mall_info->v1.header.version_major)) {
|
||||
case 1:
|
||||
mall_size = 0;
|
||||
mall_size_per_umc = le32_to_cpu(mall_info->v1.mall_size_per_m);
|
||||
m_s_present = le32_to_cpu(mall_info->v1.m_s_present);
|
||||
half_use = le32_to_cpu(mall_info->v1.m_half_use);
|
||||
for (u = 0; u < adev->gmc.num_umc; u++) {
|
||||
if (m_s_present & (1 << u))
|
||||
mall_size += mall_size_per_umc * 2;
|
||||
else if (half_use & (1 << u))
|
||||
mall_size += mall_size_per_umc / 2;
|
||||
else
|
||||
mall_size += mall_size_per_umc;
|
||||
}
|
||||
adev->gmc.mall_size = mall_size;
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Unhandled MALL info table %d.%d\n",
|
||||
le16_to_cpu(mall_info->v1.header.version_major),
|
||||
le16_to_cpu(mall_info->v1.header.version_minor));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
union vcn_info {
|
||||
struct vcn_info_v1_0 v1;
|
||||
};
|
||||
|
||||
static int amdgpu_discovery_get_vcn_info(struct amdgpu_device *adev)
|
||||
{
|
||||
struct binary_header *bhdr;
|
||||
union vcn_info *vcn_info;
|
||||
u16 offset;
|
||||
int v;
|
||||
|
||||
if (!adev->mman.discovery_bin) {
|
||||
DRM_ERROR("ip discovery uninitialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (adev->vcn.num_vcn_inst > VCN_INFO_TABLE_MAX_NUM_INSTANCES) {
|
||||
dev_err(adev->dev, "invalid vcn instances\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bhdr = (struct binary_header *)adev->mman.discovery_bin;
|
||||
offset = le16_to_cpu(bhdr->table_list[VCN_INFO].offset);
|
||||
|
||||
if (!offset)
|
||||
return 0;
|
||||
|
||||
vcn_info = (union vcn_info *)(adev->mman.discovery_bin + offset);
|
||||
|
||||
switch (le16_to_cpu(vcn_info->v1.header.version_major)) {
|
||||
case 1:
|
||||
for (v = 0; v < adev->vcn.num_vcn_inst; v++) {
|
||||
adev->vcn.vcn_codec_disable_mask[v] =
|
||||
le32_to_cpu(vcn_info->v1.instance_info[v].fuse_data.all_bits);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Unhandled VCN info table %d.%d\n",
|
||||
le16_to_cpu(vcn_info->v1.header.version_major),
|
||||
le16_to_cpu(vcn_info->v1.header.version_minor));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1256,6 +1483,11 @@ static int amdgpu_discovery_set_common_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(10, 3, 7):
|
||||
amdgpu_device_ip_block_add(adev, &nv_common_ip_block);
|
||||
break;
|
||||
case IP_VERSION(11, 0, 0):
|
||||
case IP_VERSION(11, 0, 1):
|
||||
case IP_VERSION(11, 0, 2):
|
||||
amdgpu_device_ip_block_add(adev, &soc21_common_ip_block);
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Failed to add common ip block(GC_HWIP:0x%x)\n",
|
||||
|
|
@ -1294,6 +1526,11 @@ static int amdgpu_discovery_set_gmc_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(10, 3, 7):
|
||||
amdgpu_device_ip_block_add(adev, &gmc_v10_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(11, 0, 0):
|
||||
case IP_VERSION(11, 0, 1):
|
||||
case IP_VERSION(11, 0, 2):
|
||||
amdgpu_device_ip_block_add(adev, &gmc_v11_0_ip_block);
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Failed to add gmc ip block(GC_HWIP:0x%x)\n",
|
||||
|
|
@ -1326,6 +1563,11 @@ static int amdgpu_discovery_set_ih_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(5, 2, 1):
|
||||
amdgpu_device_ip_block_add(adev, &navi10_ih_ip_block);
|
||||
break;
|
||||
case IP_VERSION(6, 0, 0):
|
||||
case IP_VERSION(6, 0, 1):
|
||||
case IP_VERSION(6, 0, 2):
|
||||
amdgpu_device_ip_block_add(adev, &ih_v6_0_ip_block);
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Failed to add ih ip block(OSSSYS_HWIP:0x%x)\n",
|
||||
|
|
@ -1364,10 +1606,13 @@ static int amdgpu_discovery_set_psp_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(12, 0, 1):
|
||||
amdgpu_device_ip_block_add(adev, &psp_v12_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(13, 0, 0):
|
||||
case IP_VERSION(13, 0, 1):
|
||||
case IP_VERSION(13, 0, 2):
|
||||
case IP_VERSION(13, 0, 3):
|
||||
case IP_VERSION(13, 0, 4):
|
||||
case IP_VERSION(13, 0, 5):
|
||||
case IP_VERSION(13, 0, 7):
|
||||
case IP_VERSION(13, 0, 8):
|
||||
amdgpu_device_ip_block_add(adev, &psp_v13_0_ip_block);
|
||||
break;
|
||||
|
|
@ -1407,10 +1652,13 @@ static int amdgpu_discovery_set_smu_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(12, 0, 1):
|
||||
amdgpu_device_ip_block_add(adev, &smu_v12_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(13, 0, 0):
|
||||
case IP_VERSION(13, 0, 1):
|
||||
case IP_VERSION(13, 0, 2):
|
||||
case IP_VERSION(13, 0, 3):
|
||||
case IP_VERSION(13, 0, 4):
|
||||
case IP_VERSION(13, 0, 5):
|
||||
case IP_VERSION(13, 0, 7):
|
||||
case IP_VERSION(13, 0, 8):
|
||||
amdgpu_device_ip_block_add(adev, &smu_v13_0_ip_block);
|
||||
break;
|
||||
|
|
@ -1504,6 +1752,11 @@ static int amdgpu_discovery_set_gc_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(10, 3, 7):
|
||||
amdgpu_device_ip_block_add(adev, &gfx_v10_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(11, 0, 0):
|
||||
case IP_VERSION(11, 0, 1):
|
||||
case IP_VERSION(11, 0, 2):
|
||||
amdgpu_device_ip_block_add(adev, &gfx_v11_0_ip_block);
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Failed to add gfx ip block(GC_HWIP:0x%x)\n",
|
||||
|
|
@ -1542,6 +1795,11 @@ static int amdgpu_discovery_set_sdma_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(5, 2, 7):
|
||||
amdgpu_device_ip_block_add(adev, &sdma_v5_2_ip_block);
|
||||
break;
|
||||
case IP_VERSION(6, 0, 0):
|
||||
case IP_VERSION(6, 0, 1):
|
||||
case IP_VERSION(6, 0, 2):
|
||||
amdgpu_device_ip_block_add(adev, &sdma_v6_0_ip_block);
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Failed to add sdma ip block(SDMA0_HWIP:0x%x)\n",
|
||||
|
|
@ -1616,6 +1874,11 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(3, 0, 33):
|
||||
amdgpu_device_ip_block_add(adev, &vcn_v3_0_ip_block);
|
||||
break;
|
||||
case IP_VERSION(4, 0, 0):
|
||||
case IP_VERSION(4, 0, 4):
|
||||
amdgpu_device_ip_block_add(adev, &vcn_v4_0_ip_block);
|
||||
amdgpu_device_ip_block_add(adev, &jpeg_v4_0_ip_block);
|
||||
break;
|
||||
default:
|
||||
dev_err(adev->dev,
|
||||
"Failed to add vcn/jpeg ip block(UVD_HWIP:0x%x)\n",
|
||||
|
|
@ -1641,7 +1904,19 @@ static int amdgpu_discovery_set_mes_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(10, 3, 4):
|
||||
case IP_VERSION(10, 3, 5):
|
||||
case IP_VERSION(10, 3, 6):
|
||||
amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block);
|
||||
if (amdgpu_mes) {
|
||||
amdgpu_device_ip_block_add(adev, &mes_v10_1_ip_block);
|
||||
adev->enable_mes = true;
|
||||
if (amdgpu_mes_kiq)
|
||||
adev->enable_mes_kiq = true;
|
||||
}
|
||||
break;
|
||||
case IP_VERSION(11, 0, 0):
|
||||
case IP_VERSION(11, 0, 1):
|
||||
case IP_VERSION(11, 0, 2):
|
||||
amdgpu_device_ip_block_add(adev, &mes_v11_0_ip_block);
|
||||
adev->enable_mes = true;
|
||||
adev->enable_mes_kiq = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1657,6 +1932,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
case CHIP_VEGA10:
|
||||
vega10_reg_base_init(adev);
|
||||
adev->sdma.num_instances = 2;
|
||||
adev->gmc.num_umc = 4;
|
||||
adev->ip_versions[MMHUB_HWIP][0] = IP_VERSION(9, 0, 0);
|
||||
adev->ip_versions[ATHUB_HWIP][0] = IP_VERSION(9, 0, 0);
|
||||
adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 0, 0);
|
||||
|
|
@ -1678,6 +1954,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
case CHIP_VEGA12:
|
||||
vega10_reg_base_init(adev);
|
||||
adev->sdma.num_instances = 2;
|
||||
adev->gmc.num_umc = 4;
|
||||
adev->ip_versions[MMHUB_HWIP][0] = IP_VERSION(9, 3, 0);
|
||||
adev->ip_versions[ATHUB_HWIP][0] = IP_VERSION(9, 3, 0);
|
||||
adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 0, 1);
|
||||
|
|
@ -1700,6 +1977,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
vega10_reg_base_init(adev);
|
||||
adev->sdma.num_instances = 1;
|
||||
adev->vcn.num_vcn_inst = 1;
|
||||
adev->gmc.num_umc = 2;
|
||||
if (adev->apu_flags & AMD_APU_IS_RAVEN2) {
|
||||
adev->ip_versions[MMHUB_HWIP][0] = IP_VERSION(9, 2, 0);
|
||||
adev->ip_versions[ATHUB_HWIP][0] = IP_VERSION(9, 2, 0);
|
||||
|
|
@ -1737,6 +2015,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
case CHIP_VEGA20:
|
||||
vega20_reg_base_init(adev);
|
||||
adev->sdma.num_instances = 2;
|
||||
adev->gmc.num_umc = 8;
|
||||
adev->ip_versions[MMHUB_HWIP][0] = IP_VERSION(9, 4, 0);
|
||||
adev->ip_versions[ATHUB_HWIP][0] = IP_VERSION(9, 4, 0);
|
||||
adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 2, 0);
|
||||
|
|
@ -1760,6 +2039,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
arct_reg_base_init(adev);
|
||||
adev->sdma.num_instances = 8;
|
||||
adev->vcn.num_vcn_inst = 2;
|
||||
adev->gmc.num_umc = 8;
|
||||
adev->ip_versions[MMHUB_HWIP][0] = IP_VERSION(9, 4, 1);
|
||||
adev->ip_versions[ATHUB_HWIP][0] = IP_VERSION(9, 4, 1);
|
||||
adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 2, 1);
|
||||
|
|
@ -1787,6 +2067,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
aldebaran_reg_base_init(adev);
|
||||
adev->sdma.num_instances = 5;
|
||||
adev->vcn.num_vcn_inst = 2;
|
||||
adev->gmc.num_umc = 4;
|
||||
adev->ip_versions[MMHUB_HWIP][0] = IP_VERSION(9, 4, 2);
|
||||
adev->ip_versions[ATHUB_HWIP][0] = IP_VERSION(9, 4, 2);
|
||||
adev->ip_versions[OSSSYS_HWIP][0] = IP_VERSION(4, 4, 0);
|
||||
|
|
@ -1814,6 +2095,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
return -EINVAL;
|
||||
|
||||
amdgpu_discovery_harvest_ip(adev);
|
||||
amdgpu_discovery_get_gfx_info(adev);
|
||||
amdgpu_discovery_get_mall_info(adev);
|
||||
amdgpu_discovery_get_vcn_info(adev);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1853,6 +2137,13 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(10, 3, 7):
|
||||
adev->family = AMDGPU_FAMILY_GC_10_3_7;
|
||||
break;
|
||||
case IP_VERSION(11, 0, 0):
|
||||
case IP_VERSION(11, 0, 2):
|
||||
adev->family = AMDGPU_FAMILY_GC_11_0_0;
|
||||
break;
|
||||
case IP_VERSION(11, 0, 1):
|
||||
adev->family = AMDGPU_FAMILY_GC_11_0_1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1867,6 +2158,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(10, 3, 3):
|
||||
case IP_VERSION(10, 3, 6):
|
||||
case IP_VERSION(10, 3, 7):
|
||||
case IP_VERSION(11, 0, 1):
|
||||
adev->flags |= AMD_IS_APU;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1920,6 +2212,15 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
adev->nbio.funcs = &nbio_v2_3_funcs;
|
||||
adev->nbio.hdp_flush_reg = &nbio_v2_3_hdp_flush_reg_sc;
|
||||
break;
|
||||
case IP_VERSION(4, 3, 0):
|
||||
case IP_VERSION(4, 3, 1):
|
||||
adev->nbio.funcs = &nbio_v4_3_funcs;
|
||||
adev->nbio.hdp_flush_reg = &nbio_v4_3_hdp_flush_reg;
|
||||
break;
|
||||
case IP_VERSION(7, 7, 0):
|
||||
adev->nbio.funcs = &nbio_v7_7_funcs;
|
||||
adev->nbio.hdp_flush_reg = &nbio_v7_7_hdp_flush_reg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1943,6 +2244,13 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(5, 2, 0):
|
||||
adev->hdp.funcs = &hdp_v5_0_funcs;
|
||||
break;
|
||||
case IP_VERSION(5, 2, 1):
|
||||
adev->hdp.funcs = &hdp_v5_2_funcs;
|
||||
break;
|
||||
case IP_VERSION(6, 0, 0):
|
||||
case IP_VERSION(6, 0, 1):
|
||||
adev->hdp.funcs = &hdp_v6_0_funcs;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1992,6 +2300,19 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
case IP_VERSION(13, 0, 2):
|
||||
adev->smuio.funcs = &smuio_v13_0_funcs;
|
||||
break;
|
||||
case IP_VERSION(13, 0, 6):
|
||||
case IP_VERSION(13, 0, 8):
|
||||
adev->smuio.funcs = &smuio_v13_0_6_funcs;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (adev->ip_versions[LSDMA_HWIP][0]) {
|
||||
case IP_VERSION(6, 0, 0):
|
||||
case IP_VERSION(6, 0, 2):
|
||||
adev->lsdma.funcs = &lsdma_v6_0_funcs;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -2042,8 +2363,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT &&
|
||||
!amdgpu_sriov_vf(adev)) {
|
||||
if ((adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT &&
|
||||
!amdgpu_sriov_vf(adev)) ||
|
||||
(adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO && amdgpu_dpm == 1)) {
|
||||
r = amdgpu_discovery_set_smu_ip_blocks(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
|
@ -2053,11 +2375,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (adev->enable_mes) {
|
||||
r = amdgpu_discovery_set_mes_ip_blocks(adev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
r = amdgpu_discovery_set_mes_ip_blocks(adev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,8 @@
|
|||
#define DISCOVERY_TMR_OFFSET (64 << 10)
|
||||
|
||||
void amdgpu_discovery_fini(struct amdgpu_device *adev);
|
||||
int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev);
|
||||
void amdgpu_discovery_harvest_ip(struct amdgpu_device *adev);
|
||||
int amdgpu_discovery_get_ip_version(struct amdgpu_device *adev, int hw_id, int number_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);
|
||||
|
||||
#endif /* __AMDGPU_DISCOVERY__ */
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@
|
|||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
static int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
|
||||
static void amdgpu_display_flip_callback(struct dma_fence *f,
|
||||
struct dma_fence_cb *cb)
|
||||
{
|
||||
|
|
@ -113,8 +118,9 @@ static void amdgpu_display_flip_work_func(struct work_struct *__work)
|
|||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||
|
||||
|
||||
DRM_DEBUG_DRIVER("crtc:%d[%p], pflip_stat:AMDGPU_FLIP_SUBMITTED, work: %p,\n",
|
||||
amdgpu_crtc->crtc_id, amdgpu_crtc, work);
|
||||
drm_dbg_vbl(adev_to_drm(adev),
|
||||
"crtc:%d[%p], pflip_stat:AMDGPU_FLIP_SUBMITTED, work: %p,\n",
|
||||
amdgpu_crtc->crtc_id, amdgpu_crtc, work);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -200,8 +206,7 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc,
|
|||
goto unpin;
|
||||
}
|
||||
|
||||
/* TODO: Unify this with other drivers */
|
||||
r = dma_resv_get_fences(new_abo->tbo.base.resv, true,
|
||||
r = dma_resv_get_fences(new_abo->tbo.base.resv, DMA_RESV_USAGE_WRITE,
|
||||
&work->shared_count,
|
||||
&work->shared);
|
||||
if (unlikely(r != 0)) {
|
||||
|
|
@ -1039,35 +1044,11 @@ static int amdgpu_display_get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb
|
|||
return r;
|
||||
}
|
||||
|
||||
int amdgpu_display_gem_fb_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rfb->base.obj[0] = obj;
|
||||
drm_helper_mode_fill_fb_struct(dev, &rfb->base, mode_cmd);
|
||||
|
||||
ret = amdgpu_display_framebuffer_init(dev, rfb, mode_cmd, obj);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
drm_dbg_kms(dev, "Failed to init gem fb: %d\n", ret);
|
||||
rfb->base.obj[0] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_display_gem_fb_verify_and_init(
|
||||
struct drm_device *dev, struct amdgpu_framebuffer *rfb,
|
||||
struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
static int amdgpu_display_gem_fb_verify_and_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
struct drm_file *file_priv,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -1099,10 +1080,10 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
static int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
int ret, i;
|
||||
|
|
|
|||
|
|
@ -102,21 +102,9 @@ static int amdgpu_dma_buf_pin(struct dma_buf_attachment *attach)
|
|||
{
|
||||
struct drm_gem_object *obj = attach->dmabuf->priv;
|
||||
struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
|
||||
int r;
|
||||
|
||||
/* pin buffer into GTT */
|
||||
r = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (bo->tbo.moving) {
|
||||
r = dma_fence_wait(bo->tbo.moving, true);
|
||||
if (r) {
|
||||
amdgpu_bo_unpin(bo);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -52,8 +52,11 @@ struct amdgpu_doorbell_index {
|
|||
uint32_t userqueue_end;
|
||||
uint32_t gfx_ring0;
|
||||
uint32_t gfx_ring1;
|
||||
uint32_t gfx_userqueue_start;
|
||||
uint32_t gfx_userqueue_end;
|
||||
uint32_t sdma_engine[8];
|
||||
uint32_t mes_ring;
|
||||
uint32_t mes_ring0;
|
||||
uint32_t mes_ring1;
|
||||
uint32_t ih;
|
||||
union {
|
||||
struct {
|
||||
|
|
@ -174,11 +177,15 @@ typedef enum _AMDGPU_NAVI10_DOORBELL_ASSIGNMENT
|
|||
AMDGPU_NAVI10_DOORBELL_MEC_RING5 = 0x008,
|
||||
AMDGPU_NAVI10_DOORBELL_MEC_RING6 = 0x009,
|
||||
AMDGPU_NAVI10_DOORBELL_MEC_RING7 = 0x00A,
|
||||
AMDGPU_NAVI10_DOORBELL_USERQUEUE_START = 0x00B,
|
||||
AMDGPU_NAVI10_DOORBELL_MES_RING0 = 0x00B,
|
||||
AMDGPU_NAVI10_DOORBELL_MES_RING1 = 0x00C,
|
||||
AMDGPU_NAVI10_DOORBELL_USERQUEUE_START = 0x00D,
|
||||
AMDGPU_NAVI10_DOORBELL_USERQUEUE_END = 0x08A,
|
||||
AMDGPU_NAVI10_DOORBELL_GFX_RING0 = 0x08B,
|
||||
AMDGPU_NAVI10_DOORBELL_GFX_RING1 = 0x08C,
|
||||
AMDGPU_NAVI10_DOORBELL_MES_RING = 0x090,
|
||||
AMDGPU_NAVI10_DOORBELL_GFX_USERQUEUE_START = 0x08D,
|
||||
AMDGPU_NAVI10_DOORBELL_GFX_USERQUEUE_END = 0x0FF,
|
||||
|
||||
/* SDMA:256~335*/
|
||||
AMDGPU_NAVI10_DOORBELL_sDMA_ENGINE0 = 0x100,
|
||||
AMDGPU_NAVI10_DOORBELL_sDMA_ENGINE1 = 0x10A,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@
|
|||
#include <linux/mmu_notifier.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/cc_platform.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_irq.h"
|
||||
|
|
@ -136,7 +135,7 @@ int amdgpu_sched_jobs = 32;
|
|||
int amdgpu_sched_hw_submission = 2;
|
||||
uint amdgpu_pcie_gen_cap;
|
||||
uint amdgpu_pcie_lane_cap;
|
||||
uint amdgpu_cg_mask = 0xffffffff;
|
||||
u64 amdgpu_cg_mask = 0xffffffffffffffff;
|
||||
uint amdgpu_pg_mask = 0xffffffff;
|
||||
uint amdgpu_sdma_phase_quantum = 32;
|
||||
char *amdgpu_disable_cu = NULL;
|
||||
|
|
@ -171,6 +170,7 @@ int amdgpu_async_gfx_ring = 1;
|
|||
int amdgpu_mcbp;
|
||||
int amdgpu_discovery = -1;
|
||||
int amdgpu_mes;
|
||||
int amdgpu_mes_kiq;
|
||||
int amdgpu_noretry = -1;
|
||||
int amdgpu_force_asic_type = -1;
|
||||
int amdgpu_tmz = -1; /* auto */
|
||||
|
|
@ -306,7 +306,7 @@ module_param_named(dpm, amdgpu_dpm, int, 0444);
|
|||
* 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 = force direct if supported, -1 = auto)");
|
||||
MODULE_PARM_DESC(fw_load_type, "firmware loading type (3 = rlc backdoor autoload if supported, 2 = smu load if supported, 1 = psp load, 0 = force direct if supported, -1 = auto)");
|
||||
module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444);
|
||||
|
||||
/**
|
||||
|
|
@ -454,12 +454,12 @@ MODULE_PARM_DESC(pcie_lane_cap, "PCIE Lane Caps (0: autodetect (default))");
|
|||
module_param_named(pcie_lane_cap, amdgpu_pcie_lane_cap, uint, 0444);
|
||||
|
||||
/**
|
||||
* DOC: cg_mask (uint)
|
||||
* DOC: cg_mask (ullong)
|
||||
* Override Clockgating features enabled on GPU (0 = disable clock gating). See the AMD_CG_SUPPORT flags in
|
||||
* drivers/gpu/drm/amd/include/amd_shared.h. The default is 0xffffffff (all enabled).
|
||||
* drivers/gpu/drm/amd/include/amd_shared.h. The default is 0xffffffffffffffff (all enabled).
|
||||
*/
|
||||
MODULE_PARM_DESC(cg_mask, "Clockgating flags mask (0 = disable clock gating)");
|
||||
module_param_named(cg_mask, amdgpu_cg_mask, uint, 0444);
|
||||
module_param_named(cg_mask, amdgpu_cg_mask, ullong, 0444);
|
||||
|
||||
/**
|
||||
* DOC: pg_mask (uint)
|
||||
|
|
@ -636,6 +636,15 @@ MODULE_PARM_DESC(mes,
|
|||
"Enable Micro Engine Scheduler (0 = disabled (default), 1 = enabled)");
|
||||
module_param_named(mes, amdgpu_mes, int, 0444);
|
||||
|
||||
/**
|
||||
* DOC: mes_kiq (int)
|
||||
* Enable Micro Engine Scheduler KIQ. This is a new engine pipe for kiq.
|
||||
* (0 = disabled (default), 1 = enabled)
|
||||
*/
|
||||
MODULE_PARM_DESC(mes_kiq,
|
||||
"Enable Micro Engine Scheduler KIQ (0 = disabled (default), 1 = enabled)");
|
||||
module_param_named(mes_kiq, amdgpu_mes_kiq, int, 0444);
|
||||
|
||||
/**
|
||||
* DOC: noretry (int)
|
||||
* Disable XNACK retry in the SQ by default on GFXv9 hardware. On ASICs that
|
||||
|
|
@ -1950,26 +1959,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
|
|||
|
||||
static const struct drm_driver amdgpu_kms_driver;
|
||||
|
||||
static bool amdgpu_is_fw_framebuffer(resource_size_t base,
|
||||
resource_size_t size)
|
||||
{
|
||||
bool found = false;
|
||||
#if IS_REACHABLE(CONFIG_FB)
|
||||
struct apertures_struct *a;
|
||||
|
||||
a = alloc_apertures(1);
|
||||
if (!a)
|
||||
return false;
|
||||
|
||||
a->ranges[0].base = base;
|
||||
a->ranges[0].size = size;
|
||||
|
||||
found = is_firmware_framebuffer(a);
|
||||
kfree(a);
|
||||
#endif
|
||||
return found;
|
||||
}
|
||||
|
||||
static void amdgpu_get_secondary_funcs(struct amdgpu_device *adev)
|
||||
{
|
||||
struct pci_dev *p = NULL;
|
||||
|
|
@ -2000,8 +1989,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
|
|||
unsigned long flags = ent->driver_data;
|
||||
int ret, retry = 0, i;
|
||||
bool supports_atomic = false;
|
||||
bool is_fw_fb;
|
||||
resource_size_t base, size;
|
||||
|
||||
/* skip devices which are owned by radeon */
|
||||
for (i = 0; i < ARRAY_SIZE(amdgpu_unsupported_pciidlist); i++) {
|
||||
|
|
@ -2068,10 +2055,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
|
|||
}
|
||||
#endif
|
||||
|
||||
base = pci_resource_start(pdev, 0);
|
||||
size = pci_resource_len(pdev, 0);
|
||||
is_fw_fb = amdgpu_is_fw_framebuffer(base, size);
|
||||
|
||||
/* Get rid of things like offb */
|
||||
ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &amdgpu_kms_driver);
|
||||
if (ret)
|
||||
|
|
@ -2084,7 +2067,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
|
|||
adev->dev = &pdev->dev;
|
||||
adev->pdev = pdev;
|
||||
ddev = adev_to_drm(adev);
|
||||
adev->is_fw_fb = is_fw_fb;
|
||||
|
||||
if (!supports_atomic)
|
||||
ddev->driver_features &= ~DRIVER_ATOMIC;
|
||||
|
|
|
|||
|
|
@ -422,8 +422,8 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring,
|
|||
uint64_t index;
|
||||
|
||||
if (ring->funcs->type != AMDGPU_RING_TYPE_UVD) {
|
||||
ring->fence_drv.cpu_addr = &adev->wb.wb[ring->fence_offs];
|
||||
ring->fence_drv.gpu_addr = adev->wb.gpu_addr + (ring->fence_offs * 4);
|
||||
ring->fence_drv.cpu_addr = ring->fence_cpu_addr;
|
||||
ring->fence_drv.gpu_addr = ring->fence_gpu_addr;
|
||||
} else {
|
||||
/* put fence directly behind firmware */
|
||||
index = ALIGN(adev->uvd.fw->size, 8);
|
||||
|
|
|
|||
|
|
@ -526,7 +526,8 @@ int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
|
|||
return -ENOENT;
|
||||
}
|
||||
robj = gem_to_amdgpu_bo(gobj);
|
||||
ret = dma_resv_wait_timeout(robj->tbo.base.resv, true, true, timeout);
|
||||
ret = dma_resv_wait_timeout(robj->tbo.base.resv, DMA_RESV_USAGE_READ,
|
||||
true, timeout);
|
||||
|
||||
/* ret == 0 means not signaled,
|
||||
* ret > 0 means signaled
|
||||
|
|
@ -612,7 +613,7 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
|
|||
|
||||
if (operation == AMDGPU_VA_OP_MAP ||
|
||||
operation == AMDGPU_VA_OP_REPLACE) {
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false, NULL);
|
||||
r = amdgpu_vm_bo_update(adev, bo_va, false);
|
||||
if (r)
|
||||
goto error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,42 +98,6 @@ bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev,
|
|||
adev->gfx.me.queue_bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gfx_scratch_get - Allocate a scratch register
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @reg: scratch register mmio offset
|
||||
*
|
||||
* Allocate a CP scratch register for use by the driver (all asics).
|
||||
* Returns 0 on success or -EINVAL on failure.
|
||||
*/
|
||||
int amdgpu_gfx_scratch_get(struct amdgpu_device *adev, uint32_t *reg)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = ffs(adev->gfx.scratch.free_mask);
|
||||
if (i != 0 && i <= adev->gfx.scratch.num_reg) {
|
||||
i--;
|
||||
adev->gfx.scratch.free_mask &= ~(1u << i);
|
||||
*reg = adev->gfx.scratch.reg_base + i;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gfx_scratch_free - Free a scratch register
|
||||
*
|
||||
* @adev: amdgpu_device pointer
|
||||
* @reg: scratch register mmio offset
|
||||
*
|
||||
* Free a CP scratch register allocated for use by the driver (all asics)
|
||||
*/
|
||||
void amdgpu_gfx_scratch_free(struct amdgpu_device *adev, uint32_t reg)
|
||||
{
|
||||
adev->gfx.scratch.free_mask |= 1u << (reg - adev->gfx.scratch.reg_base);
|
||||
}
|
||||
|
||||
/**
|
||||
* amdgpu_gfx_parse_disable_cu - Parse the disable_cu module parameter
|
||||
*
|
||||
|
|
@ -367,7 +331,7 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev,
|
|||
|
||||
/* create MQD for KIQ */
|
||||
ring = &adev->gfx.kiq.ring;
|
||||
if (!ring->mqd_obj) {
|
||||
if (!adev->enable_mes_kiq && !ring->mqd_obj) {
|
||||
/* originaly the KIQ MQD is put in GTT domain, but for SRIOV VRAM domain is a must
|
||||
* otherwise hypervisor trigger SAVE_VF fail after driver unloaded which mean MQD
|
||||
* deallocated and gart_unbind, to strict diverage we decide to use VRAM domain for
|
||||
|
|
@ -464,7 +428,7 @@ int amdgpu_gfx_disable_kcq(struct amdgpu_device *adev)
|
|||
{
|
||||
struct amdgpu_kiq *kiq = &adev->gfx.kiq;
|
||||
struct amdgpu_ring *kiq_ring = &kiq->ring;
|
||||
int i, r;
|
||||
int i, r = 0;
|
||||
|
||||
if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues)
|
||||
return -EINVAL;
|
||||
|
|
@ -479,7 +443,9 @@ int amdgpu_gfx_disable_kcq(struct amdgpu_device *adev)
|
|||
for (i = 0; i < adev->gfx.num_compute_rings; i++)
|
||||
kiq->pmf->kiq_unmap_queues(kiq_ring, &adev->gfx.compute_ring[i],
|
||||
RESET_QUEUES, 0, 0);
|
||||
r = amdgpu_ring_test_helper(kiq_ring);
|
||||
|
||||
if (adev->gfx.kiq.ring.sched.ready)
|
||||
r = amdgpu_ring_test_helper(kiq_ring);
|
||||
spin_unlock(&adev->gfx.kiq.ring_lock);
|
||||
|
||||
return r;
|
||||
|
|
@ -535,6 +501,9 @@ int amdgpu_gfx_enable_kcq(struct amdgpu_device *adev)
|
|||
return r;
|
||||
}
|
||||
|
||||
if (adev->enable_mes)
|
||||
queue_mask = ~0ULL;
|
||||
|
||||
kiq->pmf->kiq_set_resources(kiq_ring, queue_mask);
|
||||
for (i = 0; i < adev->gfx.num_compute_rings; i++)
|
||||
kiq->pmf->kiq_map_queues(kiq_ring, &adev->gfx.compute_ring[i]);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "clearstate_defs.h"
|
||||
#include "amdgpu_ring.h"
|
||||
#include "amdgpu_rlc.h"
|
||||
#include "amdgpu_imu.h"
|
||||
#include "soc15.h"
|
||||
#include "amdgpu_ras.h"
|
||||
|
||||
|
|
@ -56,6 +57,9 @@ struct amdgpu_mec {
|
|||
u64 hpd_eop_gpu_addr;
|
||||
struct amdgpu_bo *mec_fw_obj;
|
||||
u64 mec_fw_gpu_addr;
|
||||
struct amdgpu_bo *mec_fw_data_obj;
|
||||
u64 mec_fw_data_gpu_addr;
|
||||
|
||||
u32 num_mec;
|
||||
u32 num_pipe_per_mec;
|
||||
u32 num_queue_per_pipe;
|
||||
|
|
@ -106,15 +110,6 @@ struct amdgpu_kiq {
|
|||
const struct kiq_pm4_funcs *pmf;
|
||||
};
|
||||
|
||||
/*
|
||||
* GPU scratch registers structures, functions & helpers
|
||||
*/
|
||||
struct amdgpu_scratch {
|
||||
unsigned num_reg;
|
||||
uint32_t reg_base;
|
||||
uint32_t free_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
* GFX configurations
|
||||
*/
|
||||
|
|
@ -183,6 +178,17 @@ struct amdgpu_gfx_config {
|
|||
uint32_t num_packer_per_sc;
|
||||
uint32_t pa_sc_tile_steering_override;
|
||||
uint64_t tcc_disabled_mask;
|
||||
uint32_t gc_num_tcp_per_sa;
|
||||
uint32_t gc_num_sdp_interface;
|
||||
uint32_t gc_num_tcps;
|
||||
uint32_t gc_num_tcp_per_wpg;
|
||||
uint32_t gc_tcp_l1_size;
|
||||
uint32_t gc_num_sqc_per_wgp;
|
||||
uint32_t gc_l1_instruction_cache_size_per_sqc;
|
||||
uint32_t gc_l1_data_cache_size_per_sqc;
|
||||
uint32_t gc_gl1c_per_sa;
|
||||
uint32_t gc_gl1c_size_per_instance;
|
||||
uint32_t gc_gl2c_per_gpu;
|
||||
};
|
||||
|
||||
struct amdgpu_cu_info {
|
||||
|
|
@ -202,6 +208,7 @@ struct amdgpu_cu_info {
|
|||
struct amdgpu_gfx_ras {
|
||||
struct amdgpu_ras_block_object ras_block;
|
||||
void (*enable_watchdog_timer)(struct amdgpu_device *adev);
|
||||
bool (*query_utcl2_poison_status)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_gfx_funcs {
|
||||
|
|
@ -232,6 +239,10 @@ struct amdgpu_pfp {
|
|||
struct amdgpu_bo *pfp_fw_obj;
|
||||
uint64_t pfp_fw_gpu_addr;
|
||||
uint32_t *pfp_fw_ptr;
|
||||
|
||||
struct amdgpu_bo *pfp_fw_data_obj;
|
||||
uint64_t pfp_fw_data_gpu_addr;
|
||||
uint32_t *pfp_fw_data_ptr;
|
||||
};
|
||||
|
||||
struct amdgpu_ce {
|
||||
|
|
@ -244,6 +255,11 @@ struct amdgpu_me {
|
|||
struct amdgpu_bo *me_fw_obj;
|
||||
uint64_t me_fw_gpu_addr;
|
||||
uint32_t *me_fw_ptr;
|
||||
|
||||
struct amdgpu_bo *me_fw_data_obj;
|
||||
uint64_t me_fw_data_gpu_addr;
|
||||
uint32_t *me_fw_data_ptr;
|
||||
|
||||
uint32_t num_me;
|
||||
uint32_t num_pipe_per_me;
|
||||
uint32_t num_queue_per_pipe;
|
||||
|
|
@ -262,7 +278,8 @@ struct amdgpu_gfx {
|
|||
struct amdgpu_me me;
|
||||
struct amdgpu_mec mec;
|
||||
struct amdgpu_kiq kiq;
|
||||
struct amdgpu_scratch scratch;
|
||||
struct amdgpu_imu imu;
|
||||
bool rs64_enable; /* firmware format */
|
||||
const struct firmware *me_fw; /* ME firmware */
|
||||
uint32_t me_fw_version;
|
||||
const struct firmware *pfp_fw; /* PFP firmware */
|
||||
|
|
@ -275,6 +292,8 @@ struct amdgpu_gfx {
|
|||
uint32_t mec_fw_version;
|
||||
const struct firmware *mec2_fw; /* MEC2 firmware */
|
||||
uint32_t mec2_fw_version;
|
||||
const struct firmware *imu_fw; /* IMU firmware */
|
||||
uint32_t imu_fw_version;
|
||||
uint32_t me_feature_version;
|
||||
uint32_t ce_feature_version;
|
||||
uint32_t pfp_feature_version;
|
||||
|
|
@ -323,8 +342,10 @@ struct amdgpu_gfx {
|
|||
DECLARE_BITMAP (pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES);
|
||||
|
||||
/*ras */
|
||||
struct ras_common_if *ras_if;
|
||||
struct amdgpu_gfx_ras *ras;
|
||||
struct ras_common_if *ras_if;
|
||||
struct amdgpu_gfx_ras *ras;
|
||||
|
||||
bool is_poweron;
|
||||
};
|
||||
|
||||
#define amdgpu_gfx_get_gpu_clock_counter(adev) (adev)->gfx.funcs->get_gpu_clock_counter((adev))
|
||||
|
|
@ -345,9 +366,6 @@ static inline u32 amdgpu_gfx_create_bitmask(u32 bit_width)
|
|||
return (u32)((1ULL << bit_width) - 1);
|
||||
}
|
||||
|
||||
int amdgpu_gfx_scratch_get(struct amdgpu_device *adev, uint32_t *reg);
|
||||
void amdgpu_gfx_scratch_free(struct amdgpu_device *adev, uint32_t reg);
|
||||
|
||||
void amdgpu_gfx_parse_disable_cu(unsigned *mask, unsigned max_se,
|
||||
unsigned max_sh);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@
|
|||
*/
|
||||
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/hypervisor.h>
|
||||
#endif
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_gmc.h"
|
||||
|
|
@ -647,12 +650,14 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev)
|
|||
case CHIP_VEGA10:
|
||||
adev->mman.keep_stolen_vga_memory = true;
|
||||
/*
|
||||
* VEGA10 SRIOV VF needs some firmware reserved area.
|
||||
* VEGA10 SRIOV VF with MS_HYPERV host needs some firmware reserved area.
|
||||
*/
|
||||
if (amdgpu_sriov_vf(adev)) {
|
||||
adev->mman.stolen_reserved_offset = 0x100000;
|
||||
adev->mman.stolen_reserved_size = 0x600000;
|
||||
#ifdef CONFIG_X86
|
||||
if (amdgpu_sriov_vf(adev) && hypervisor_is_type(X86_HYPER_MS_HYPERV)) {
|
||||
adev->mman.stolen_reserved_offset = 0x500000;
|
||||
adev->mman.stolen_reserved_size = 0x200000;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case CHIP_RAVEN:
|
||||
case CHIP_RENOIR:
|
||||
|
|
|
|||
|
|
@ -100,7 +100,9 @@ struct amdgpu_vmhub {
|
|||
uint32_t eng_distance;
|
||||
uint32_t eng_addr_distance; /* include LO32/HI32 */
|
||||
|
||||
uint32_t vm_cntx_cntl;
|
||||
uint32_t vm_cntx_cntl_vm_fault;
|
||||
uint32_t vm_l2_bank_select_reserved_cid2;
|
||||
|
||||
const struct amdgpu_vmhub_funcs *vmhub_funcs;
|
||||
};
|
||||
|
|
@ -257,6 +259,11 @@ struct amdgpu_gmc {
|
|||
struct amdgpu_bo *pdb0_bo;
|
||||
/* CPU kmapped address of pdb0*/
|
||||
void *ptr_pdb0;
|
||||
|
||||
/* MALL size */
|
||||
u64 mall_size;
|
||||
/* number of UMC instances */
|
||||
int num_umc;
|
||||
};
|
||||
|
||||
#define amdgpu_gmc_flush_gpu_tlb(adev, vmid, vmhub, type) ((adev)->gmc.gmc_funcs->flush_gpu_tlb((adev), (vmid), (vmhub), (type)))
|
||||
|
|
|
|||
|
|
@ -26,23 +26,12 @@
|
|||
|
||||
#include "amdgpu.h"
|
||||
|
||||
struct amdgpu_gtt_node {
|
||||
struct ttm_buffer_object *tbo;
|
||||
struct ttm_range_mgr_node base;
|
||||
};
|
||||
|
||||
static inline struct amdgpu_gtt_mgr *
|
||||
to_gtt_mgr(struct ttm_resource_manager *man)
|
||||
{
|
||||
return container_of(man, struct amdgpu_gtt_mgr, manager);
|
||||
}
|
||||
|
||||
static inline struct amdgpu_gtt_node *
|
||||
to_amdgpu_gtt_node(struct ttm_resource *res)
|
||||
{
|
||||
return container_of(res, struct amdgpu_gtt_node, base.base);
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: mem_info_gtt_total
|
||||
*
|
||||
|
|
@ -106,9 +95,9 @@ const struct attribute_group amdgpu_gtt_mgr_attr_group = {
|
|||
*/
|
||||
bool amdgpu_gtt_mgr_has_gart_addr(struct ttm_resource *res)
|
||||
{
|
||||
struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res);
|
||||
struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
|
||||
|
||||
return drm_mm_node_allocated(&node->base.mm_nodes[0]);
|
||||
return drm_mm_node_allocated(&node->mm_nodes[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -128,15 +117,14 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
|
|||
{
|
||||
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
|
||||
uint32_t num_pages = PFN_UP(tbo->base.size);
|
||||
struct amdgpu_gtt_node *node;
|
||||
struct ttm_range_mgr_node *node;
|
||||
int r;
|
||||
|
||||
node = kzalloc(struct_size(node, base.mm_nodes, 1), GFP_KERNEL);
|
||||
node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL);
|
||||
if (!node)
|
||||
return -ENOMEM;
|
||||
|
||||
node->tbo = tbo;
|
||||
ttm_resource_init(tbo, place, &node->base.base);
|
||||
ttm_resource_init(tbo, place, &node->base);
|
||||
if (!(place->flags & TTM_PL_FLAG_TEMPORARY) &&
|
||||
ttm_resource_manager_usage(man) > man->size) {
|
||||
r = -ENOSPC;
|
||||
|
|
@ -145,8 +133,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
|
|||
|
||||
if (place->lpfn) {
|
||||
spin_lock(&mgr->lock);
|
||||
r = drm_mm_insert_node_in_range(&mgr->mm,
|
||||
&node->base.mm_nodes[0],
|
||||
r = drm_mm_insert_node_in_range(&mgr->mm, &node->mm_nodes[0],
|
||||
num_pages, tbo->page_alignment,
|
||||
0, place->fpfn, place->lpfn,
|
||||
DRM_MM_INSERT_BEST);
|
||||
|
|
@ -154,18 +141,18 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man,
|
|||
if (unlikely(r))
|
||||
goto err_free;
|
||||
|
||||
node->base.base.start = node->base.mm_nodes[0].start;
|
||||
node->base.start = node->mm_nodes[0].start;
|
||||
} else {
|
||||
node->base.mm_nodes[0].start = 0;
|
||||
node->base.mm_nodes[0].size = node->base.base.num_pages;
|
||||
node->base.base.start = AMDGPU_BO_INVALID_OFFSET;
|
||||
node->mm_nodes[0].start = 0;
|
||||
node->mm_nodes[0].size = node->base.num_pages;
|
||||
node->base.start = AMDGPU_BO_INVALID_OFFSET;
|
||||
}
|
||||
|
||||
*res = &node->base.base;
|
||||
*res = &node->base;
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
ttm_resource_fini(man, &node->base.base);
|
||||
ttm_resource_fini(man, &node->base);
|
||||
kfree(node);
|
||||
return r;
|
||||
}
|
||||
|
|
@ -181,12 +168,12 @@ err_free:
|
|||
static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
|
||||
struct ttm_resource *res)
|
||||
{
|
||||
struct amdgpu_gtt_node *node = to_amdgpu_gtt_node(res);
|
||||
struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
|
||||
struct amdgpu_gtt_mgr *mgr = to_gtt_mgr(man);
|
||||
|
||||
spin_lock(&mgr->lock);
|
||||
if (drm_mm_node_allocated(&node->base.mm_nodes[0]))
|
||||
drm_mm_remove_node(&node->base.mm_nodes[0]);
|
||||
if (drm_mm_node_allocated(&node->mm_nodes[0]))
|
||||
drm_mm_remove_node(&node->mm_nodes[0]);
|
||||
spin_unlock(&mgr->lock);
|
||||
|
||||
ttm_resource_fini(man, res);
|
||||
|
|
@ -202,15 +189,15 @@ static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man,
|
|||
*/
|
||||
void amdgpu_gtt_mgr_recover(struct amdgpu_gtt_mgr *mgr)
|
||||
{
|
||||
struct amdgpu_gtt_node *node;
|
||||
struct ttm_range_mgr_node *node;
|
||||
struct drm_mm_node *mm_node;
|
||||
struct amdgpu_device *adev;
|
||||
|
||||
adev = container_of(mgr, typeof(*adev), mman.gtt_mgr);
|
||||
spin_lock(&mgr->lock);
|
||||
drm_mm_for_each_node(mm_node, &mgr->mm) {
|
||||
node = container_of(mm_node, typeof(*node), base.mm_nodes[0]);
|
||||
amdgpu_ttm_recover_gart(node->tbo);
|
||||
node = container_of(mm_node, typeof(*node), mm_nodes[0]);
|
||||
amdgpu_ttm_recover_gart(node->base.bo);
|
||||
}
|
||||
spin_unlock(&mgr->lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ struct amdgpu_hdp_funcs {
|
|||
void (*invalidate_hdp)(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring);
|
||||
void (*update_clock_gating)(struct amdgpu_device *adev, bool enable);
|
||||
void (*get_clock_gating_state)(struct amdgpu_device *adev, u32 *flags);
|
||||
void (*get_clock_gating_state)(struct amdgpu_device *adev, u64 *flags);
|
||||
void (*init_registers)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -155,12 +155,12 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned num_ibs,
|
|||
fence_ctx = 0;
|
||||
}
|
||||
|
||||
if (!ring->sched.ready) {
|
||||
if (!ring->sched.ready && !ring->is_mes_queue) {
|
||||
dev_err(adev->dev, "couldn't schedule ib on ring <%s>\n", ring->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vm && !job->vmid) {
|
||||
if (vm && !job->vmid && !ring->is_mes_queue) {
|
||||
dev_err(adev->dev, "VM IB without ID\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -390,6 +390,10 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev)
|
|||
if (!ring->sched.ready || !ring->funcs->test_ib)
|
||||
continue;
|
||||
|
||||
if (adev->enable_mes &&
|
||||
ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
|
||||
continue;
|
||||
|
||||
/* MM engine need more time */
|
||||
if (ring->funcs->type == AMDGPU_RING_TYPE_UVD ||
|
||||
ring->funcs->type == AMDGPU_RING_TYPE_VCE ||
|
||||
|
|
|
|||
|
|
@ -107,36 +107,19 @@ static void amdgpu_pasid_free_cb(struct dma_fence *fence,
|
|||
void amdgpu_pasid_free_delayed(struct dma_resv *resv,
|
||||
u32 pasid)
|
||||
{
|
||||
struct dma_fence *fence, **fences;
|
||||
struct amdgpu_pasid_cb *cb;
|
||||
unsigned count;
|
||||
struct dma_fence *fence;
|
||||
int r;
|
||||
|
||||
r = dma_resv_get_fences(resv, true, &count, &fences);
|
||||
r = dma_resv_get_singleton(resv, DMA_RESV_USAGE_BOOKKEEP, &fence);
|
||||
if (r)
|
||||
goto fallback;
|
||||
|
||||
if (count == 0) {
|
||||
if (!fence) {
|
||||
amdgpu_pasid_free(pasid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 1) {
|
||||
fence = fences[0];
|
||||
kfree(fences);
|
||||
} else {
|
||||
uint64_t context = dma_fence_context_alloc(1);
|
||||
struct dma_fence_array *array;
|
||||
|
||||
array = dma_fence_array_create(count, fences, context,
|
||||
1, false);
|
||||
if (!array) {
|
||||
kfree(fences);
|
||||
goto fallback;
|
||||
}
|
||||
fence = &array->base;
|
||||
}
|
||||
|
||||
cb = kmalloc(sizeof(*cb), GFP_KERNEL);
|
||||
if (!cb) {
|
||||
/* Last resort when we are OOM */
|
||||
|
|
@ -156,7 +139,8 @@ fallback:
|
|||
/* Not enough memory for the delayed delete, as last resort
|
||||
* block for all the fences to complete.
|
||||
*/
|
||||
dma_resv_wait_timeout(resv, true, false, MAX_SCHEDULE_TIMEOUT);
|
||||
dma_resv_wait_timeout(resv, DMA_RESV_USAGE_BOOKKEEP,
|
||||
false, MAX_SCHEDULE_TIMEOUT);
|
||||
amdgpu_pasid_free(pasid);
|
||||
}
|
||||
|
||||
|
|
@ -276,19 +260,15 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
|
|||
struct amdgpu_device *adev = ring->adev;
|
||||
unsigned vmhub = ring->funcs->vmhub;
|
||||
uint64_t fence_context = adev->fence_context + ring->idx;
|
||||
struct dma_fence *updates = sync->last_vm_update;
|
||||
bool needs_flush = vm->use_cpu_for_update;
|
||||
int r = 0;
|
||||
uint64_t updates = amdgpu_vm_tlb_seq(vm);
|
||||
int r;
|
||||
|
||||
*id = vm->reserved_vmid[vmhub];
|
||||
if (updates && (*id)->flushed_updates &&
|
||||
updates->context == (*id)->flushed_updates->context &&
|
||||
!dma_fence_is_later(updates, (*id)->flushed_updates))
|
||||
updates = NULL;
|
||||
|
||||
if ((*id)->owner != vm->immediate.fence_context ||
|
||||
job->vm_pd_addr != (*id)->pd_gpu_addr ||
|
||||
updates || !(*id)->last_flush ||
|
||||
(*id)->pd_gpu_addr != job->vm_pd_addr ||
|
||||
(*id)->flushed_updates < updates ||
|
||||
!(*id)->last_flush ||
|
||||
((*id)->last_flush->context != fence_context &&
|
||||
!dma_fence_is_signaled((*id)->last_flush))) {
|
||||
struct dma_fence *tmp;
|
||||
|
|
@ -302,8 +282,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
|
|||
tmp = amdgpu_sync_peek_fence(&(*id)->active, ring);
|
||||
if (tmp) {
|
||||
*id = NULL;
|
||||
r = amdgpu_sync_fence(sync, tmp);
|
||||
return r;
|
||||
return amdgpu_sync_fence(sync, tmp);
|
||||
}
|
||||
needs_flush = true;
|
||||
}
|
||||
|
|
@ -315,10 +294,7 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm,
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (updates) {
|
||||
dma_fence_put((*id)->flushed_updates);
|
||||
(*id)->flushed_updates = dma_fence_get(updates);
|
||||
}
|
||||
(*id)->flushed_updates = updates;
|
||||
job->vm_needs_flush = needs_flush;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -346,7 +322,7 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
|
|||
unsigned vmhub = ring->funcs->vmhub;
|
||||
struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
||||
uint64_t fence_context = adev->fence_context + ring->idx;
|
||||
struct dma_fence *updates = sync->last_vm_update;
|
||||
uint64_t updates = amdgpu_vm_tlb_seq(vm);
|
||||
int r;
|
||||
|
||||
job->vm_needs_flush = vm->use_cpu_for_update;
|
||||
|
|
@ -354,7 +330,6 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
|
|||
/* Check if we can use a VMID already assigned to this VM */
|
||||
list_for_each_entry_reverse((*id), &id_mgr->ids_lru, list) {
|
||||
bool needs_flush = vm->use_cpu_for_update;
|
||||
struct dma_fence *flushed;
|
||||
|
||||
/* Check all the prerequisites to using this VMID */
|
||||
if ((*id)->owner != vm->immediate.fence_context)
|
||||
|
|
@ -368,8 +343,7 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
|
|||
!dma_fence_is_signaled((*id)->last_flush)))
|
||||
needs_flush = true;
|
||||
|
||||
flushed = (*id)->flushed_updates;
|
||||
if (updates && (!flushed || dma_fence_is_later(updates, flushed)))
|
||||
if ((*id)->flushed_updates < updates)
|
||||
needs_flush = true;
|
||||
|
||||
if (needs_flush && !adev->vm_manager.concurrent_flush)
|
||||
|
|
@ -382,11 +356,7 @@ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm,
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
if (updates && (!flushed || dma_fence_is_later(updates, flushed))) {
|
||||
dma_fence_put((*id)->flushed_updates);
|
||||
(*id)->flushed_updates = dma_fence_get(updates);
|
||||
}
|
||||
|
||||
(*id)->flushed_updates = updates;
|
||||
job->vm_needs_flush |= needs_flush;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -432,8 +402,6 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
|||
goto error;
|
||||
|
||||
if (!id) {
|
||||
struct dma_fence *updates = sync->last_vm_update;
|
||||
|
||||
/* Still no ID to use? Then use the idle one found earlier */
|
||||
id = idle;
|
||||
|
||||
|
|
@ -442,8 +410,7 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
|
|||
if (r)
|
||||
goto error;
|
||||
|
||||
dma_fence_put(id->flushed_updates);
|
||||
id->flushed_updates = dma_fence_get(updates);
|
||||
id->flushed_updates = amdgpu_vm_tlb_seq(vm);
|
||||
job->vm_needs_flush = true;
|
||||
}
|
||||
|
||||
|
|
@ -610,7 +577,6 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
|
|||
struct amdgpu_vmid *id = &id_mgr->ids[j];
|
||||
|
||||
amdgpu_sync_free(&id->active);
|
||||
dma_fence_put(id->flushed_updates);
|
||||
dma_fence_put(id->last_flush);
|
||||
dma_fence_put(id->pasid_mapping);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct amdgpu_vmid {
|
|||
|
||||
uint64_t pd_gpu_addr;
|
||||
/* last flushed PD/PT update */
|
||||
struct dma_fence *flushed_updates;
|
||||
uint64_t flushed_updates;
|
||||
|
||||
uint32_t current_gpu_reset_count;
|
||||
|
||||
|
|
|
|||
51
drivers/gpu/drm/amd/amdgpu/amdgpu_imu.h
Normal file
51
drivers/gpu/drm/amd/amdgpu/amdgpu_imu.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2021 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_IMU_H__
|
||||
#define __AMDGPU_IMU_H__
|
||||
|
||||
struct amdgpu_imu_funcs {
|
||||
int (*init_microcode)(struct amdgpu_device *adev);
|
||||
int (*load_microcode)(struct amdgpu_device *adev);
|
||||
void (*setup_imu)(struct amdgpu_device *adev);
|
||||
int (*start_imu)(struct amdgpu_device *adev);
|
||||
void (*program_rlc_ram)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct imu_rlc_ram_golden {
|
||||
u32 hwip;
|
||||
u32 instance;
|
||||
u32 segment;
|
||||
u32 reg;
|
||||
u32 data;
|
||||
u32 addr_mask;
|
||||
};
|
||||
|
||||
#define IMU_RLC_RAM_GOLDEN_VALUE(ip, inst, reg, data, addr_mask) \
|
||||
{ ip##_HWIP, inst, reg##_BASE_IDX, reg, data, addr_mask }
|
||||
|
||||
struct amdgpu_imu {
|
||||
const struct amdgpu_imu_funcs *funcs;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -193,20 +193,7 @@ static irqreturn_t amdgpu_irq_handler(int irq, void *arg)
|
|||
if (ret == IRQ_HANDLED)
|
||||
pm_runtime_mark_last_busy(dev->dev);
|
||||
|
||||
/* For the hardware that cannot enable bif ring for both ras_controller_irq
|
||||
* and ras_err_evnet_athub_irq ih cookies, the driver has to poll status
|
||||
* register to check whether the interrupt is triggered or not, and properly
|
||||
* ack the interrupt if it is there
|
||||
*/
|
||||
if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__PCIE_BIF)) {
|
||||
if (adev->nbio.ras &&
|
||||
adev->nbio.ras->handle_ras_controller_intr_no_bifring)
|
||||
adev->nbio.ras->handle_ras_controller_intr_no_bifring(adev);
|
||||
|
||||
if (adev->nbio.ras &&
|
||||
adev->nbio.ras->handle_ras_err_event_athub_intr_no_bifring)
|
||||
adev->nbio.ras->handle_ras_err_event_athub_intr_no_bifring(adev);
|
||||
}
|
||||
amdgpu_ras_interrupt_fatal_error_handler(adev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,3 +216,21 @@ int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
|
|||
error:
|
||||
return r;
|
||||
}
|
||||
|
||||
int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev,
|
||||
struct amdgpu_irq_src *source,
|
||||
struct amdgpu_iv_entry *entry)
|
||||
{
|
||||
struct ras_common_if *ras_if = adev->jpeg.ras_if;
|
||||
struct ras_dispatch_if ih_data = {
|
||||
.entry = entry,
|
||||
};
|
||||
|
||||
if (!ras_if)
|
||||
return 0;
|
||||
|
||||
ih_data.head = *ras_if;
|
||||
amdgpu_ras_interrupt_dispatch(adev, &ih_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
#ifndef __AMDGPU_JPEG_H__
|
||||
#define __AMDGPU_JPEG_H__
|
||||
|
||||
#include "amdgpu_ras.h"
|
||||
|
||||
#define AMDGPU_MAX_JPEG_INSTANCES 2
|
||||
|
||||
#define AMDGPU_JPEG_HARVEST_JPEG0 (1 << 0)
|
||||
|
|
@ -39,6 +41,10 @@ struct amdgpu_jpeg_inst {
|
|||
struct amdgpu_jpeg_reg external;
|
||||
};
|
||||
|
||||
struct amdgpu_jpeg_ras {
|
||||
struct amdgpu_ras_block_object ras_block;
|
||||
};
|
||||
|
||||
struct amdgpu_jpeg {
|
||||
uint8_t num_jpeg_inst;
|
||||
struct amdgpu_jpeg_inst inst[AMDGPU_MAX_JPEG_INSTANCES];
|
||||
|
|
@ -48,6 +54,8 @@ struct amdgpu_jpeg {
|
|||
enum amd_powergating_state cur_state;
|
||||
struct mutex jpeg_pg_lock;
|
||||
atomic_t total_submission_cnt;
|
||||
struct ras_common_if *ras_if;
|
||||
struct amdgpu_jpeg_ras *ras;
|
||||
};
|
||||
|
||||
int amdgpu_jpeg_sw_init(struct amdgpu_device *adev);
|
||||
|
|
@ -61,4 +69,8 @@ void amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring);
|
|||
int amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring);
|
||||
int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout);
|
||||
|
||||
int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev,
|
||||
struct amdgpu_irq_src *source,
|
||||
struct amdgpu_iv_entry *entry);
|
||||
|
||||
#endif /*__AMDGPU_JPEG_H__*/
|
||||
|
|
|
|||
|
|
@ -43,6 +43,17 @@
|
|||
#include "amdgpu_display.h"
|
||||
#include "amdgpu_ras.h"
|
||||
|
||||
static void amdgpu_runtime_pm_quirk(struct amdgpu_device *adev)
|
||||
{
|
||||
/*
|
||||
* Add below quirk on several sienna_cichlid cards to disable
|
||||
* runtime pm to fix EMI failures.
|
||||
*/
|
||||
if (((adev->pdev->device == 0x73A1) && (adev->pdev->revision == 0x00)) ||
|
||||
((adev->pdev->device == 0x73BF) && (adev->pdev->revision == 0xCF)))
|
||||
adev->runpm = false;
|
||||
}
|
||||
|
||||
void amdgpu_unregister_gpu_instance(struct amdgpu_device *adev)
|
||||
{
|
||||
struct amdgpu_gpu_instance *gpu_instance;
|
||||
|
|
@ -174,12 +185,9 @@ int amdgpu_driver_load_kms(struct amdgpu_device *adev, unsigned long flags)
|
|||
adev->runpm = true;
|
||||
break;
|
||||
}
|
||||
/* XXX: disable runtime pm if we are the primary adapter
|
||||
* to avoid displays being re-enabled after DPMS.
|
||||
* This needs to be sorted out and fixed properly.
|
||||
*/
|
||||
if (adev->is_fw_fb)
|
||||
adev->runpm = false;
|
||||
|
||||
amdgpu_runtime_pm_quirk(adev);
|
||||
|
||||
if (adev->runpm)
|
||||
dev_info(adev->dev, "Using BACO for runtime pm\n");
|
||||
}
|
||||
|
|
|
|||
91
drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.c
Normal file
91
drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.c
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_lsdma.h"
|
||||
|
||||
#define AMDGPU_LSDMA_MAX_SIZE 0x2000000ULL
|
||||
|
||||
int amdgpu_lsdma_wait_for(struct amdgpu_device *adev,
|
||||
uint32_t reg_index, uint32_t reg_val,
|
||||
uint32_t mask)
|
||||
{
|
||||
uint32_t val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < adev->usec_timeout; i++) {
|
||||
val = RREG32(reg_index);
|
||||
if ((val & mask) == reg_val)
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
int amdgpu_lsdma_copy_mem(struct amdgpu_device *adev,
|
||||
uint64_t src_addr,
|
||||
uint64_t dst_addr,
|
||||
uint64_t mem_size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mem_size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
while (mem_size > 0) {
|
||||
uint64_t current_copy_size = min(mem_size, AMDGPU_LSDMA_MAX_SIZE);
|
||||
|
||||
ret = adev->lsdma.funcs->copy_mem(adev, src_addr, dst_addr, current_copy_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
src_addr += current_copy_size;
|
||||
dst_addr += current_copy_size;
|
||||
mem_size -= current_copy_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amdgpu_lsdma_fill_mem(struct amdgpu_device *adev,
|
||||
uint64_t dst_addr,
|
||||
uint32_t data,
|
||||
uint64_t mem_size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mem_size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
while (mem_size > 0) {
|
||||
uint64_t current_fill_size = min(mem_size, AMDGPU_LSDMA_MAX_SIZE);
|
||||
|
||||
ret = adev->lsdma.funcs->fill_mem(adev, dst_addr, data, current_fill_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
dst_addr += current_fill_size;
|
||||
mem_size -= current_fill_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.h
Normal file
46
drivers/gpu/drm/amd/amdgpu/amdgpu_lsdma.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_LSDMA_H__
|
||||
#define __AMDGPU_LSDMA_H__
|
||||
|
||||
struct amdgpu_lsdma {
|
||||
const struct amdgpu_lsdma_funcs *funcs;
|
||||
};
|
||||
|
||||
struct amdgpu_lsdma_funcs {
|
||||
int (*copy_mem)(struct amdgpu_device *adev, uint64_t src_addr,
|
||||
uint64_t dst_addr, uint64_t size);
|
||||
int (*fill_mem)(struct amdgpu_device *adev, uint64_t dst_addr,
|
||||
uint32_t data, uint64_t size);
|
||||
void (*update_memory_power_gating)(struct amdgpu_device *adev, bool enable);
|
||||
};
|
||||
|
||||
int amdgpu_lsdma_copy_mem(struct amdgpu_device *adev, uint64_t src_addr,
|
||||
uint64_t dst_addr, uint64_t mem_size);
|
||||
int amdgpu_lsdma_fill_mem(struct amdgpu_device *adev, uint64_t dst_addr,
|
||||
uint32_t data, uint64_t mem_size);
|
||||
int amdgpu_lsdma_wait_for(struct amdgpu_device *adev, uint32_t reg_index,
|
||||
uint32_t reg_val, uint32_t mask);
|
||||
|
||||
#endif
|
||||
1227
drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
Normal file
1227
drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -24,6 +24,11 @@
|
|||
#ifndef __AMDGPU_MES_H__
|
||||
#define __AMDGPU_MES_H__
|
||||
|
||||
#include "amdgpu_irq.h"
|
||||
#include "kgd_kfd_interface.h"
|
||||
#include "amdgpu_gfx.h"
|
||||
#include <linux/sched/mm.h>
|
||||
|
||||
#define AMDGPU_MES_MAX_COMPUTE_PIPES 8
|
||||
#define AMDGPU_MES_MAX_GFX_PIPES 2
|
||||
#define AMDGPU_MES_MAX_SDMA_PIPES 2
|
||||
|
|
@ -37,11 +42,29 @@ enum amdgpu_mes_priority_level {
|
|||
AMDGPU_MES_PRIORITY_NUM_LEVELS
|
||||
};
|
||||
|
||||
#define AMDGPU_MES_PROC_CTX_SIZE 0x1000 /* one page area */
|
||||
#define AMDGPU_MES_GANG_CTX_SIZE 0x1000 /* one page area */
|
||||
|
||||
struct amdgpu_mes_funcs;
|
||||
|
||||
enum admgpu_mes_pipe {
|
||||
AMDGPU_MES_SCHED_PIPE = 0,
|
||||
AMDGPU_MES_KIQ_PIPE,
|
||||
AMDGPU_MAX_MES_PIPES = 2,
|
||||
};
|
||||
|
||||
struct amdgpu_mes {
|
||||
struct amdgpu_device *adev;
|
||||
|
||||
struct mutex mutex_hidden;
|
||||
|
||||
struct idr pasid_idr;
|
||||
struct idr gang_id_idr;
|
||||
struct idr queue_id_idr;
|
||||
struct ida doorbell_ida;
|
||||
|
||||
spinlock_t queue_id_lock;
|
||||
|
||||
uint32_t total_max_queue;
|
||||
uint32_t doorbell_id_offset;
|
||||
uint32_t max_doorbell_slices;
|
||||
|
|
@ -51,27 +74,28 @@ struct amdgpu_mes {
|
|||
|
||||
struct amdgpu_ring ring;
|
||||
|
||||
const struct firmware *fw;
|
||||
const struct firmware *fw[AMDGPU_MAX_MES_PIPES];
|
||||
|
||||
/* mes ucode */
|
||||
struct amdgpu_bo *ucode_fw_obj;
|
||||
uint64_t ucode_fw_gpu_addr;
|
||||
uint32_t *ucode_fw_ptr;
|
||||
uint32_t ucode_fw_version;
|
||||
uint64_t uc_start_addr;
|
||||
struct amdgpu_bo *ucode_fw_obj[AMDGPU_MAX_MES_PIPES];
|
||||
uint64_t ucode_fw_gpu_addr[AMDGPU_MAX_MES_PIPES];
|
||||
uint32_t *ucode_fw_ptr[AMDGPU_MAX_MES_PIPES];
|
||||
uint32_t ucode_fw_version[AMDGPU_MAX_MES_PIPES];
|
||||
uint64_t uc_start_addr[AMDGPU_MAX_MES_PIPES];
|
||||
|
||||
/* mes ucode data */
|
||||
struct amdgpu_bo *data_fw_obj;
|
||||
uint64_t data_fw_gpu_addr;
|
||||
uint32_t *data_fw_ptr;
|
||||
uint32_t data_fw_version;
|
||||
uint64_t data_start_addr;
|
||||
struct amdgpu_bo *data_fw_obj[AMDGPU_MAX_MES_PIPES];
|
||||
uint64_t data_fw_gpu_addr[AMDGPU_MAX_MES_PIPES];
|
||||
uint32_t *data_fw_ptr[AMDGPU_MAX_MES_PIPES];
|
||||
uint32_t data_fw_version[AMDGPU_MAX_MES_PIPES];
|
||||
uint64_t data_start_addr[AMDGPU_MAX_MES_PIPES];
|
||||
|
||||
/* eop gpu obj */
|
||||
struct amdgpu_bo *eop_gpu_obj;
|
||||
uint64_t eop_gpu_addr;
|
||||
struct amdgpu_bo *eop_gpu_obj[AMDGPU_MAX_MES_PIPES];
|
||||
uint64_t eop_gpu_addr[AMDGPU_MAX_MES_PIPES];
|
||||
|
||||
void *mqd_backup;
|
||||
void *mqd_backup[AMDGPU_MAX_MES_PIPES];
|
||||
struct amdgpu_irq_src irq[AMDGPU_MAX_MES_PIPES];
|
||||
|
||||
uint32_t vmid_mask_gfxhub;
|
||||
uint32_t vmid_mask_mmhub;
|
||||
|
|
@ -85,11 +109,81 @@ struct amdgpu_mes {
|
|||
uint32_t query_status_fence_offs;
|
||||
uint64_t query_status_fence_gpu_addr;
|
||||
uint64_t *query_status_fence_ptr;
|
||||
uint32_t saved_flags;
|
||||
|
||||
/* initialize kiq pipe */
|
||||
int (*kiq_hw_init)(struct amdgpu_device *adev);
|
||||
int (*kiq_hw_fini)(struct amdgpu_device *adev);
|
||||
|
||||
/* ip specific functions */
|
||||
const struct amdgpu_mes_funcs *funcs;
|
||||
};
|
||||
|
||||
struct amdgpu_mes_process {
|
||||
int pasid;
|
||||
struct amdgpu_vm *vm;
|
||||
uint64_t pd_gpu_addr;
|
||||
struct amdgpu_bo *proc_ctx_bo;
|
||||
uint64_t proc_ctx_gpu_addr;
|
||||
void *proc_ctx_cpu_ptr;
|
||||
uint64_t process_quantum;
|
||||
struct list_head gang_list;
|
||||
uint32_t doorbell_index;
|
||||
unsigned long *doorbell_bitmap;
|
||||
struct mutex doorbell_lock;
|
||||
};
|
||||
|
||||
struct amdgpu_mes_gang {
|
||||
int gang_id;
|
||||
int priority;
|
||||
int inprocess_gang_priority;
|
||||
int global_priority_level;
|
||||
struct list_head list;
|
||||
struct amdgpu_mes_process *process;
|
||||
struct amdgpu_bo *gang_ctx_bo;
|
||||
uint64_t gang_ctx_gpu_addr;
|
||||
void *gang_ctx_cpu_ptr;
|
||||
uint64_t gang_quantum;
|
||||
struct list_head queue_list;
|
||||
};
|
||||
|
||||
struct amdgpu_mes_queue {
|
||||
struct list_head list;
|
||||
struct amdgpu_mes_gang *gang;
|
||||
int queue_id;
|
||||
uint64_t doorbell_off;
|
||||
struct amdgpu_bo *mqd_obj;
|
||||
void *mqd_cpu_ptr;
|
||||
uint64_t mqd_gpu_addr;
|
||||
uint64_t wptr_gpu_addr;
|
||||
int queue_type;
|
||||
int paging;
|
||||
struct amdgpu_ring *ring;
|
||||
};
|
||||
|
||||
struct amdgpu_mes_queue_properties {
|
||||
int queue_type;
|
||||
uint64_t hqd_base_gpu_addr;
|
||||
uint64_t rptr_gpu_addr;
|
||||
uint64_t wptr_gpu_addr;
|
||||
uint32_t queue_size;
|
||||
uint64_t eop_gpu_addr;
|
||||
uint32_t hqd_pipe_priority;
|
||||
uint32_t hqd_queue_priority;
|
||||
bool paging;
|
||||
struct amdgpu_ring *ring;
|
||||
/* out */
|
||||
uint64_t doorbell_off;
|
||||
};
|
||||
|
||||
struct amdgpu_mes_gang_properties {
|
||||
uint32_t priority;
|
||||
uint32_t gang_quantum;
|
||||
uint32_t inprocess_gang_priority;
|
||||
uint32_t priority_level;
|
||||
int global_priority_level;
|
||||
};
|
||||
|
||||
struct mes_add_queue_input {
|
||||
uint32_t process_id;
|
||||
uint64_t page_table_base_addr;
|
||||
|
|
@ -106,6 +200,10 @@ struct mes_add_queue_input {
|
|||
uint64_t wptr_addr;
|
||||
uint32_t queue_type;
|
||||
uint32_t paging;
|
||||
uint32_t gws_base;
|
||||
uint32_t gws_size;
|
||||
uint64_t tba_addr;
|
||||
uint64_t tma_addr;
|
||||
};
|
||||
|
||||
struct mes_remove_queue_input {
|
||||
|
|
@ -113,6 +211,16 @@ struct mes_remove_queue_input {
|
|||
uint64_t gang_context_addr;
|
||||
};
|
||||
|
||||
struct mes_unmap_legacy_queue_input {
|
||||
enum amdgpu_unmap_queues_action action;
|
||||
uint32_t queue_type;
|
||||
uint32_t doorbell_offset;
|
||||
uint32_t pipe_id;
|
||||
uint32_t queue_id;
|
||||
uint64_t trail_fence_addr;
|
||||
uint64_t trail_fence_data;
|
||||
};
|
||||
|
||||
struct mes_suspend_gang_input {
|
||||
bool suspend_all_gangs;
|
||||
uint64_t gang_context_addr;
|
||||
|
|
@ -132,6 +240,9 @@ struct amdgpu_mes_funcs {
|
|||
int (*remove_hw_queue)(struct amdgpu_mes *mes,
|
||||
struct mes_remove_queue_input *input);
|
||||
|
||||
int (*unmap_legacy_queue)(struct amdgpu_mes *mes,
|
||||
struct mes_unmap_legacy_queue_input *input);
|
||||
|
||||
int (*suspend_gang)(struct amdgpu_mes *mes,
|
||||
struct mes_suspend_gang_input *input);
|
||||
|
||||
|
|
@ -139,4 +250,117 @@ struct amdgpu_mes_funcs {
|
|||
struct mes_resume_gang_input *input);
|
||||
};
|
||||
|
||||
#define amdgpu_mes_kiq_hw_init(adev) (adev)->mes.kiq_hw_init((adev))
|
||||
#define amdgpu_mes_kiq_hw_fini(adev) (adev)->mes.kiq_hw_fini((adev))
|
||||
|
||||
int amdgpu_mes_ctx_get_offs(struct amdgpu_ring *ring, unsigned int id_offs);
|
||||
|
||||
int amdgpu_mes_init(struct amdgpu_device *adev);
|
||||
void amdgpu_mes_fini(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_mes_create_process(struct amdgpu_device *adev, int pasid,
|
||||
struct amdgpu_vm *vm);
|
||||
void amdgpu_mes_destroy_process(struct amdgpu_device *adev, int pasid);
|
||||
|
||||
int amdgpu_mes_add_gang(struct amdgpu_device *adev, int pasid,
|
||||
struct amdgpu_mes_gang_properties *gprops,
|
||||
int *gang_id);
|
||||
int amdgpu_mes_remove_gang(struct amdgpu_device *adev, int gang_id);
|
||||
|
||||
int amdgpu_mes_suspend(struct amdgpu_device *adev);
|
||||
int amdgpu_mes_resume(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_mes_add_hw_queue(struct amdgpu_device *adev, int gang_id,
|
||||
struct amdgpu_mes_queue_properties *qprops,
|
||||
int *queue_id);
|
||||
int amdgpu_mes_remove_hw_queue(struct amdgpu_device *adev, int queue_id);
|
||||
|
||||
int amdgpu_mes_unmap_legacy_queue(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring,
|
||||
enum amdgpu_unmap_queues_action action,
|
||||
u64 gpu_addr, u64 seq);
|
||||
|
||||
int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id,
|
||||
int queue_type, int idx,
|
||||
struct amdgpu_mes_ctx_data *ctx_data,
|
||||
struct amdgpu_ring **out);
|
||||
void amdgpu_mes_remove_ring(struct amdgpu_device *adev,
|
||||
struct amdgpu_ring *ring);
|
||||
|
||||
int amdgpu_mes_ctx_alloc_meta_data(struct amdgpu_device *adev,
|
||||
struct amdgpu_mes_ctx_data *ctx_data);
|
||||
void amdgpu_mes_ctx_free_meta_data(struct amdgpu_mes_ctx_data *ctx_data);
|
||||
int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev,
|
||||
struct amdgpu_vm *vm,
|
||||
struct amdgpu_mes_ctx_data *ctx_data);
|
||||
|
||||
int amdgpu_mes_self_test(struct amdgpu_device *adev);
|
||||
|
||||
int amdgpu_mes_alloc_process_doorbells(struct amdgpu_device *adev,
|
||||
unsigned int *doorbell_index);
|
||||
void amdgpu_mes_free_process_doorbells(struct amdgpu_device *adev,
|
||||
unsigned int doorbell_index);
|
||||
unsigned int amdgpu_mes_get_doorbell_dw_offset_in_bar(
|
||||
struct amdgpu_device *adev,
|
||||
uint32_t doorbell_index,
|
||||
unsigned int doorbell_id);
|
||||
int amdgpu_mes_doorbell_process_slice(struct amdgpu_device *adev);
|
||||
|
||||
/*
|
||||
* MES lock can be taken in MMU notifiers.
|
||||
*
|
||||
* A bit more detail about why to set no-FS reclaim with MES lock:
|
||||
*
|
||||
* The purpose of the MMU notifier is to stop GPU access to memory so
|
||||
* that the Linux VM subsystem can move pages around safely. This is
|
||||
* done by preempting user mode queues for the affected process. When
|
||||
* MES is used, MES lock needs to be taken to preempt the queues.
|
||||
*
|
||||
* The MMU notifier callback entry point in the driver is
|
||||
* amdgpu_mn_invalidate_range_start_hsa. The relevant call chain from
|
||||
* there is:
|
||||
* amdgpu_amdkfd_evict_userptr -> kgd2kfd_quiesce_mm ->
|
||||
* kfd_process_evict_queues -> pdd->dev->dqm->ops.evict_process_queues
|
||||
*
|
||||
* The last part of the chain is a function pointer where we take the
|
||||
* MES lock.
|
||||
*
|
||||
* The problem with taking locks in the MMU notifier is, that MMU
|
||||
* notifiers can be called in reclaim-FS context. That's where the
|
||||
* kernel frees up pages to make room for new page allocations under
|
||||
* memory pressure. While we are running in reclaim-FS context, we must
|
||||
* not trigger another memory reclaim operation because that would
|
||||
* recursively reenter the reclaim code and cause a deadlock. The
|
||||
* memalloc_nofs_save/restore calls guarantee that.
|
||||
*
|
||||
* In addition we also need to avoid lock dependencies on other locks taken
|
||||
* under the MES lock, for example reservation locks. Here is a possible
|
||||
* scenario of a deadlock:
|
||||
* Thread A: takes and holds reservation lock | triggers reclaim-FS |
|
||||
* MMU notifier | blocks trying to take MES lock
|
||||
* Thread B: takes and holds MES lock | blocks trying to take reservation lock
|
||||
*
|
||||
* In this scenario Thread B gets involved in a deadlock even without
|
||||
* triggering a reclaim-FS operation itself.
|
||||
* To fix this and break the lock dependency chain you'd need to either:
|
||||
* 1. protect reservation locks with memalloc_nofs_save/restore, or
|
||||
* 2. avoid taking reservation locks under the MES lock.
|
||||
*
|
||||
* Reservation locks are taken all over the kernel in different subsystems, we
|
||||
* have no control over them and their lock dependencies.So the only workable
|
||||
* solution is to avoid taking other locks under the MES lock.
|
||||
* As a result, make sure no reclaim-FS happens while holding this lock anywhere
|
||||
* to prevent deadlocks when an MMU notifier runs in reclaim-FS context.
|
||||
*/
|
||||
static inline void amdgpu_mes_lock(struct amdgpu_mes *mes)
|
||||
{
|
||||
mutex_lock(&mes->mutex_hidden);
|
||||
mes->saved_flags = memalloc_noreclaim_save();
|
||||
}
|
||||
|
||||
static inline void amdgpu_mes_unlock(struct amdgpu_mes *mes)
|
||||
{
|
||||
memalloc_noreclaim_restore(mes->saved_flags);
|
||||
mutex_unlock(&mes->mutex_hidden);
|
||||
}
|
||||
#endif /* __AMDGPU_MES_H__ */
|
||||
|
|
|
|||
121
drivers/gpu/drm/amd/amdgpu/amdgpu_mes_ctx.h
Normal file
121
drivers/gpu/drm/amd/amdgpu/amdgpu_mes_ctx.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright 2019 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_MES_CTX_H__
|
||||
#define __AMDGPU_MES_CTX_H__
|
||||
|
||||
#include "v10_structs.h"
|
||||
|
||||
enum {
|
||||
AMDGPU_MES_CTX_RPTR_OFFS = 0,
|
||||
AMDGPU_MES_CTX_WPTR_OFFS,
|
||||
AMDGPU_MES_CTX_FENCE_OFFS,
|
||||
AMDGPU_MES_CTX_COND_EXE_OFFS,
|
||||
AMDGPU_MES_CTX_TRAIL_FENCE_OFFS,
|
||||
AMDGPU_MES_CTX_MAX_OFFS,
|
||||
};
|
||||
|
||||
enum {
|
||||
AMDGPU_MES_CTX_RING_OFFS = AMDGPU_MES_CTX_MAX_OFFS,
|
||||
AMDGPU_MES_CTX_IB_OFFS,
|
||||
AMDGPU_MES_CTX_PADDING_OFFS,
|
||||
};
|
||||
|
||||
#define AMDGPU_MES_CTX_MAX_GFX_RINGS 1
|
||||
#define AMDGPU_MES_CTX_MAX_COMPUTE_RINGS 4
|
||||
#define AMDGPU_MES_CTX_MAX_SDMA_RINGS 2
|
||||
#define AMDGPU_MES_CTX_MAX_RINGS \
|
||||
(AMDGPU_MES_CTX_MAX_GFX_RINGS + \
|
||||
AMDGPU_MES_CTX_MAX_COMPUTE_RINGS + \
|
||||
AMDGPU_MES_CTX_MAX_SDMA_RINGS)
|
||||
|
||||
#define AMDGPU_CSA_SDMA_SIZE 64
|
||||
#define GFX10_MEC_HPD_SIZE 2048
|
||||
|
||||
struct amdgpu_wb_slot {
|
||||
uint32_t data[8];
|
||||
};
|
||||
|
||||
struct amdgpu_mes_ctx_meta_data {
|
||||
struct {
|
||||
uint8_t ring[PAGE_SIZE * 4];
|
||||
|
||||
/* gfx csa */
|
||||
struct v10_gfx_meta_data gfx_meta_data;
|
||||
|
||||
uint8_t gds_backup[64 * 1024];
|
||||
|
||||
struct amdgpu_wb_slot slots[AMDGPU_MES_CTX_MAX_OFFS];
|
||||
|
||||
/* only for ib test */
|
||||
uint32_t ib[256] __aligned(256);
|
||||
|
||||
uint32_t padding[64];
|
||||
|
||||
} __aligned(PAGE_SIZE) gfx[AMDGPU_MES_CTX_MAX_GFX_RINGS];
|
||||
|
||||
struct {
|
||||
uint8_t ring[PAGE_SIZE * 4];
|
||||
|
||||
uint8_t mec_hpd[GFX10_MEC_HPD_SIZE];
|
||||
|
||||
struct amdgpu_wb_slot slots[AMDGPU_MES_CTX_MAX_OFFS];
|
||||
|
||||
/* only for ib test */
|
||||
uint32_t ib[256] __aligned(256);
|
||||
|
||||
uint32_t padding[64];
|
||||
|
||||
} __aligned(PAGE_SIZE) compute[AMDGPU_MES_CTX_MAX_COMPUTE_RINGS];
|
||||
|
||||
struct {
|
||||
uint8_t ring[PAGE_SIZE * 4];
|
||||
|
||||
/* sdma csa for mcbp */
|
||||
uint8_t sdma_meta_data[AMDGPU_CSA_SDMA_SIZE];
|
||||
|
||||
struct amdgpu_wb_slot slots[AMDGPU_MES_CTX_MAX_OFFS];
|
||||
|
||||
/* only for ib test */
|
||||
uint32_t ib[256] __aligned(256);
|
||||
|
||||
uint32_t padding[64];
|
||||
|
||||
} __aligned(PAGE_SIZE) sdma[AMDGPU_MES_CTX_MAX_SDMA_RINGS];
|
||||
};
|
||||
|
||||
struct amdgpu_mes_ctx_data {
|
||||
struct amdgpu_bo *meta_data_obj;
|
||||
uint64_t meta_data_gpu_addr;
|
||||
struct amdgpu_bo_va *meta_data_va;
|
||||
void *meta_data_ptr;
|
||||
uint32_t gang_ids[AMDGPU_HW_IP_DMA+1];
|
||||
};
|
||||
|
||||
#define AMDGPU_FENCE_MES_QUEUE_FLAG 0x1000000u
|
||||
#define AMDGPU_FENCE_MES_QUEUE_ID_MASK (AMDGPU_FENCE_MES_QUEUE_FLAG - 1)
|
||||
|
||||
#define AMDGPU_FENCE_MES_QUEUE_FLAG 0x1000000u
|
||||
#define AMDGPU_FENCE_MES_QUEUE_ID_MASK (AMDGPU_FENCE_MES_QUEUE_FLAG - 1)
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@ struct amdgpu_mmhub_ras {
|
|||
|
||||
struct amdgpu_mmhub_funcs {
|
||||
u64 (*get_fb_location)(struct amdgpu_device *adev);
|
||||
u64 (*get_mc_fb_offset)(struct amdgpu_device *adev);
|
||||
void (*init)(struct amdgpu_device *adev);
|
||||
int (*gart_enable)(struct amdgpu_device *adev);
|
||||
void (*set_fault_enable_default)(struct amdgpu_device *adev,
|
||||
|
|
@ -34,7 +35,7 @@ struct amdgpu_mmhub_funcs {
|
|||
void (*gart_disable)(struct amdgpu_device *adev);
|
||||
int (*set_clockgating)(struct amdgpu_device *adev,
|
||||
enum amd_clockgating_state state);
|
||||
void (*get_clockgating)(struct amdgpu_device *adev, u32 *flags);
|
||||
void (*get_clockgating)(struct amdgpu_device *adev, u64 *flags);
|
||||
void (*setup_vm_pt_regs)(struct amdgpu_device *adev, uint32_t vmid,
|
||||
uint64_t page_table_base);
|
||||
void (*update_power_gating)(struct amdgpu_device *adev,
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ static bool amdgpu_mn_invalidate_gfx(struct mmu_interval_notifier *mni,
|
|||
|
||||
mmu_interval_set_seq(mni, cur_seq);
|
||||
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, true, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP,
|
||||
false, MAX_SCHEDULE_TIMEOUT);
|
||||
mutex_unlock(&adev->notifier_lock);
|
||||
if (r <= 0)
|
||||
DRM_ERROR("(%ld) failed to wait for user bo\n", r);
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@
|
|||
#ifndef AMDGPU_MODE_H
|
||||
#define AMDGPU_MODE_H
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/dp/drm_dp_helper.h>
|
||||
#include <drm/drm_fixed.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
#include <linux/hrtimer.h>
|
||||
#include "amdgpu_irq.h"
|
||||
|
||||
#include <drm/dp/drm_dp_mst_helper.h>
|
||||
#include <drm/display/drm_dp_mst_helper.h>
|
||||
#include "modules/inc/mod_freesync.h"
|
||||
#include "amdgpu_dm_irq_params.h"
|
||||
|
||||
|
|
@ -592,19 +592,6 @@ int amdgpu_display_get_crtc_scanoutpos(struct drm_device *dev,
|
|||
int *hpos, ktime_t *stime, ktime_t *etime,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
int amdgpu_display_gem_fb_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
int amdgpu_display_gem_fb_verify_and_init(
|
||||
struct drm_device *dev, struct amdgpu_framebuffer *rfb,
|
||||
struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
int amdgpu_display_framebuffer_init(struct drm_device *dev,
|
||||
struct amdgpu_framebuffer *rfb,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd,
|
||||
struct drm_gem_object *obj);
|
||||
|
||||
int amdgpufb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
|
||||
|
||||
void amdgpu_enc_destroy(struct drm_encoder *encoder);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ struct amdgpu_nbio_funcs {
|
|||
bool use_doorbell, int doorbell_index, int doorbell_size);
|
||||
void (*vcn_doorbell_range)(struct amdgpu_device *adev, bool use_doorbell,
|
||||
int doorbell_index, int instance);
|
||||
void (*gc_doorbell_init)(struct amdgpu_device *adev);
|
||||
void (*enable_doorbell_aperture)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*enable_doorbell_selfring_aperture)(struct amdgpu_device *adev,
|
||||
|
|
@ -83,7 +84,7 @@ struct amdgpu_nbio_funcs {
|
|||
void (*update_medium_grain_light_sleep)(struct amdgpu_device *adev,
|
||||
bool enable);
|
||||
void (*get_clockgating_state)(struct amdgpu_device *adev,
|
||||
u32 *flags);
|
||||
u64 *flags);
|
||||
void (*ih_control)(struct amdgpu_device *adev);
|
||||
void (*init_registers)(struct amdgpu_device *adev);
|
||||
void (*remap_hdp_registers)(struct amdgpu_device *adev);
|
||||
|
|
@ -93,6 +94,7 @@ struct amdgpu_nbio_funcs {
|
|||
void (*apply_lc_spc_mode_wa)(struct amdgpu_device *adev);
|
||||
void (*apply_l1_link_width_reconfig_wa)(struct amdgpu_device *adev);
|
||||
void (*clear_doorbell_interrupt)(struct amdgpu_device *adev);
|
||||
u32 (*get_rom_offset)(struct amdgpu_device *adev);
|
||||
};
|
||||
|
||||
struct amdgpu_nbio {
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
|
|||
|
||||
fail:
|
||||
DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
|
||||
man->size << PAGE_SHIFT);
|
||||
man->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -612,9 +612,8 @@ int amdgpu_bo_create(struct amdgpu_device *adev,
|
|||
if (unlikely(r))
|
||||
goto fail_unreserve;
|
||||
|
||||
amdgpu_bo_fence(bo, fence, false);
|
||||
dma_fence_put(bo->tbo.moving);
|
||||
bo->tbo.moving = dma_fence_get(fence);
|
||||
dma_resv_add_fence(bo->tbo.base.resv, fence,
|
||||
DMA_RESV_USAGE_KERNEL);
|
||||
dma_fence_put(fence);
|
||||
}
|
||||
if (!bp->resv)
|
||||
|
|
@ -761,6 +760,11 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
|
|||
if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
|
||||
return -EPERM;
|
||||
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_KERNEL,
|
||||
false, MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
kptr = amdgpu_bo_kptr(bo);
|
||||
if (kptr) {
|
||||
if (ptr)
|
||||
|
|
@ -768,11 +772,6 @@ int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
r = dma_resv_wait_timeout(bo->tbo.base.resv, false, false,
|
||||
MAX_SCHEDULE_TIMEOUT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.resource->num_pages, &bo->kmap);
|
||||
if (r)
|
||||
return r;
|
||||
|
|
@ -1390,11 +1389,17 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
|
|||
bool shared)
|
||||
{
|
||||
struct dma_resv *resv = bo->tbo.base.resv;
|
||||
int r;
|
||||
|
||||
if (shared)
|
||||
dma_resv_add_shared_fence(resv, fence);
|
||||
else
|
||||
dma_resv_add_excl_fence(resv, fence);
|
||||
r = dma_resv_reserve_fences(resv, 1);
|
||||
if (r) {
|
||||
/* As last resort on OOM we block for the fence */
|
||||
dma_fence_wait(fence, false);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_resv_add_fence(resv, fence, shared ? DMA_RESV_USAGE_READ :
|
||||
DMA_RESV_USAGE_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue