mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
Merge tag 'drm-next-2026-06-17' of https://gitlab.freedesktop.org/drm/kernel
Pull drm updates from Dave Airlie:
"Highlights:
- xe: add initial CRI platform support
- amdgpu: initial HDMI 2.1 FRL support
- rust: add some new type concepts for device lifetimes
- scheduler: moves to a fair algorithm and lots of cleanups
But it's mostly the usual mountain of changes across the board.
core:
- add docbook for DRM_IOCTL_SYNCOBJ_EVENTFD
- change signature of drm_connector_attach_hdr_output_metadata_property
- dedup counter and timestamp retrieval in vblank code
- parse AMD VSDB v3 in CTA extension blocks
- add P230, Y7, XYYY2101010, T430, XVUY210101010 formats
- don't call drop master on file close if not master
- use drm_printf_indent in atomic / bridge
- fix 32b format descriptions
- docs: fix toctree
- hdmi: add common TMDS character rates
- fix drm_syncobj_find_fence leak
rust:
- introduce Higher-Ranked lifetime types
- replace drvdata with scoped registration data
- add GPUVM immediate mode abstraction for rust GPU drivers
- introduce DeviceContext type state for drm::Device
bridge:
- clarify drm_bridge_get/put
- create drm_get_bridge_by_endpoint and use it
- analogix_dp: add panel probing
- ite-it6211 - use drm audio hdmi helpers
buddy:
- add lockdep annotations
dp:
- add PR and VRR updates
- mst: fix buffer overflows
- add Adaptive Sync SDP decoding support
- fix OOB reads in dp-mst
ttm:
- bump fpfn/lpfn to 64-bit
scheduler:
- change default to fair scheduler
- map runqueue 1:1 with scheduler
dma-buf:
- port selftests to kunit
- convert dma-buf system/heap allocators to module
- add separate DMABUF_HEAPS_SYSTEM_CC_SHARED Kconfig
udmabuf:
- revert hugetlb support
- fix error with CONFIG_DMA_API_DEBUG
dma-fence:
- fix tracepoints lifetime
- remove unused signal on any support
ras:
- add clear error counter netlink command to drm ras
gpusvm:
- reject VMAs with VM_IO or VM_PFNMAP when creating SVM ranges
- use IOVA allocations
pagemap:
- use IOVA allocations
panels:
- update to use ref counts
- add support for CSW PNB601LS1-2, LGD LP116WHA-SPB1
- add support for waveshare panels
- CMN N116BCN-EA1, CMN N140HCA-EEK, IVO M140NWFQ R5,
- IVO, R140NWFW R0, BOE NT140*, BOE NV133FHM-N4F,
- AUO B140*, AUO B133HAN06.6 and AUO B116XTN02.3 eDP panels
- Surface Pro 12 Panel
xe:
- add CRI PCI-IDs
- debugfs add multi-lrc info
- engine init cleanup
- PF fair scheduling auto provisioning
- system controller support for CRI/Xe3p
- PXP state machine fixes
- Reset/wedge/unload corner case fixes
- Wedge path memory allocation fixes
- PAT type cleanups
- Reject unsafe PAT for CPU cached memory
- OA improvements for CRI device memory
- kernel doc syntax in xe headers
- xe_drm.h documentation fixes
- include guard cleanups
- VF CCS memory pool
- i915/xe step unification
- Xe3p GT tuning fixes
- forcewake cleanup in GT and GuC
- admin-only PF mode
- enable hwmon energy attributes for CRI
- enable GT_MI_USER_INTERRUPT
- refactor emit functions
- oa workarounds
- multi_queue: allow QUEUE_TIMESTAMP register
- convert stolen memory to ttm range manager
- use xe2 style blitter as a feature flag
- make drm_driver const
- add/use IRQ page to HW engine definition
- fix oops when display disabled
i915:
- enable PIPEDMC_ERROR interrupt
- more common display code refactoring
- restructure DP/HDMI sink format handling
- eliminate FB usage from lowlevel pinning code
- panel replay bw optimization
- integrate sharpness filter into the scaler
- new fb_pin abstraction for xe/i915 fb transparent handling
- skip inactive MST connectors on HDCP
- start switching to display specific registers
- use polling when irq unavailable
- Adaptive-sync SDP prep
amdgpu:
- use drm_display_info for AMD VSDB data
- Initial HDMI 2.1 FRL support
- Initial DCN 4.2.1 support
- GART fixes for non-4k pages
- GC 11.5.6/SDMA 6.4.0/and other new IPs
- GFX9/DCE6/Hawaii/SDMA4/GART/Userq fixes
- Finish support for using multiple SDMA queues for TTM operations
- SWSMU updates
- GC 12.1 updates
- SMU 15.0.8 updates
- DCN 4.2 updates
- DC type conversion fixes
- Enable DC power module
- Replay/PSR updates
- SMU 13.x updates
- Compute queue quantum MQD updates
- ASPM fix
- Align VKMS with common implementation
- DC analog support fixes
- UVD 3 fixes
- TCC harvesting fixes for SI
- GC 11 APU module reload fix
- NBIO 6.3.2 support
- IH 7.1 updates
- DC cursor fixes
- VCN/JPEG user fence fixes
- DC support for connectors without DDC
- Prefer ROM BAR for default VGA device
- DC bandwidth fixes
- Add PTL support for profiler
- Introduce dc_plane_cm and migrate surface update color path
- Add FRL registers for HDMI 2.1
- Restructure VM state machine
- Auxless ALPM support
- GEM_OP locking/warning fixes
- switch to system_dfl_wq
amdkfd:
- GPUVM TLB flush fix
- Hotplug fix
- Boundary check fixes
- SVM fixes
- CRIU fixes
- add profiler API
- MES 12.1 updates
msm:
- core:
- fix shrinker documentation
- IFPC enabled for gen8
- PERFCNTR_CONFIG ioctl support
- GPU:
- reworked UBWC handling
- a810 support
- MDSS:
- add support for Milos platform
- reworked UBWC handling
- DisplayPort:
- reworked HPD handling as prep for MST
- DPU:
- Milos platform support
- reworked UBWC handling
- DSI:
- Milos platform support
nova:
- Hopper/Blackwell enablement (GH100/GB100/GB202)
- FSP support
- 32-bit firmware support
- HAL functions
- refactor GSP boot/unload
- GA100 support
- VBIOS hardening/refactoring
- Adopt higher order lifetime types
tyr:
- define register blocks
- add shmem backed GEM objects
- adopt higher order lifetime types
- move clock cleanup into Drop
radeon:
- Hawaii SMU fixes
- CS parser fix
- use struct drm_edid instead of edid
amdxdna:
- export per-client BO memory via fdinfo
- AIE4 device support
- support medium/lower power modes
- expandable device heap support
- revert read-only user-pointer BO mappings
ivpu:
- support frequency limiting
panthor:
- enable GEM shrinker support
- add eviction and reclaim info to fdinfo
v3d:
- enable runtime PM
mgag200:
- support XRGB1555 + C8
ast:
- support XRGB1555 + C8
- use constants for lots of registers
- fix register handling
imagination:
- fence handling refactoring
nouveau:
- fix sched double call
- expose VBIOS on GSP-RM systems
- add GA100 support
virtio:
- add VIRTIO_GPU_F_BLOB_ALIGNMENT flag
- add deferred mapping support
gud:
- add RCade Display Adapter
hibmc:
- fix no connectors usage
mediatek:
- hdmi: convert error handling
- simplify mtk_crtc allocation
exynos:
- move fbdev emulation to drm client buffers
- use drm format helpers for geometry/size
- adopt core DMA tracking
- fix framebuffer offset handling
renesas:
- add RZ/T2H SOC support
versilicon:
- add cursor plane support
tegra:
- use drm client for framebuffer"
* tag 'drm-next-2026-06-17' of https://gitlab.freedesktop.org/drm/kernel: (1731 commits)
dma-buf: move system_cc_shared heap under separate Kconfig
accel/amdxdna: Clear sva pointer after unbind
agp/amd64: Fix broken error propagation in agp_amd64_probe()
accel/amdxdna: Require carveout when PASID and force_iova are disabled
drm/amdkfd: always resume_all after suspend_all
drm/amdgpu/gfx: move fault and EOP IRQ get/put to hw_init/hw_fini
drm/amd/display: Consult MCCS FreeSync cap only if requested & supported
drm/amd/pm: Use strscpy in profile mode parsing
drm/amdkfd: Fix infinite loop parsing CRAT with zero subtype length
drm/amdkfd: fix sysfs topology prop length on buffer truncation
drm/amdgpu: drop retry loop in amdgpu_hmm_range_get_pages
drm/amd/pm: bound OD parameter parsing to stack array size
drm/amd/pm: Stop pp_od_clk_voltage emit at PAGE_SIZE
drm/amdkfd: Unwind debug trap enable on copy_to_user failure
drm/amdgpu: validate the mes firmware version for gfx12.1
drm/amdgpu: validate the mes firmware version for gfx12
drm/amdgpu: compare MES firmware version ucode for gfx11
drm/amdkfd: Add bounds check for AMDKFD_IOC_WAIT_EVENTS
drm/amdgpu: restart the CS if some parts of the VM are still invalidated
drm/amd/display: use unsigned types for local pipe and REG_GET counters
...
This commit is contained in:
30
Documentation/ABI/obsolete/sysfs-driver-ivpu
Normal file
30
Documentation/ABI/obsolete/sysfs-driver-ivpu
Normal file
@@ -0,0 +1,30 @@
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../sched_mode
|
||||
Date: October 2024
|
||||
KernelVersion: 6.12
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Current NPU scheduling mode. Returns one of the following strings:
|
||||
- "HW" - Hardware Scheduler mode
|
||||
- "OS" - Operating System Scheduler mode
|
||||
Read-only.
|
||||
Deprecated since the "OS" scheduling mode is not usable
|
||||
and will be removed from future versions of the driver.
|
||||
Will be removed in 2027
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../npu_max_frequency_mhz
|
||||
Date: April 2025
|
||||
KernelVersion: 6.15
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq.
|
||||
Shows maximum frequency in MHz of the NPU's data processing unit.
|
||||
Read-only.
|
||||
Will be removed in 2027
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../npu_current_frequency_mhz
|
||||
Date: April 2025
|
||||
KernelVersion: 6.15
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Legacy alias for /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq.
|
||||
Shows current frequency in MHz of the NPU's data processing unit.
|
||||
The value is read only when the device is active; otherwise it returns 0.
|
||||
Read-only.
|
||||
Will be removed in 2027
|
||||
65
Documentation/ABI/testing/sysfs-driver-ivpu
Normal file
65
Documentation/ABI/testing/sysfs-driver-ivpu
Normal file
@@ -0,0 +1,65 @@
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../npu_busy_time_us
|
||||
Date: May 2024
|
||||
KernelVersion: 6.11
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Time in microseconds that the device spent executing jobs. The time is
|
||||
counted when and only when there are jobs submitted to firmware. This time
|
||||
can be used to measure the utilization of NPU, either by calculating the
|
||||
difference between two timepoints or monitoring utilization percentage by
|
||||
reading periodically. Recommended read period is 1 second to avoid impact
|
||||
on job submission performance. Read-only.
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../npu_memory_utilization
|
||||
Date: Jan 2025
|
||||
KernelVersion: 6.15
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Current NPU memory utilization in bytes. Reports the total size of all
|
||||
resident buffer objects allocated for NPU use. Read-only.
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_min_freq
|
||||
Date: April 2026
|
||||
KernelVersion: 7.2
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Minimum frequency in MHz supported by the NPU hardware. This is a
|
||||
hardware capability and cannot be changed. Read-only.
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_efficient_freq
|
||||
Date: April 2026
|
||||
KernelVersion: 7.2
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Most efficient operating frequency in MHz for the NPU. This represents
|
||||
the frequency at which the NPU operates most efficiently in terms of power
|
||||
and performance. Read-only.
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../freq/hw_max_freq
|
||||
Date: April 2026
|
||||
KernelVersion: 7.2
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Maximum frequency in MHz supported by the NPU hardware. This is a
|
||||
hardware capability and cannot be changed. Read-only.
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../freq/current_freq
|
||||
Date: April 2026
|
||||
KernelVersion: 7.2
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Current operating frequency in MHz of the NPU. The value is valid only
|
||||
when the device is active; returns 0 when idle. The actual frequency may
|
||||
be lower than the requested range due to power or thermal constraints.
|
||||
Read-only.
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_min_freq
|
||||
Date: April 2026
|
||||
KernelVersion: 7.2
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Configured minimum operating frequency in MHz (50XX devices and newer).
|
||||
Values written are clamped to hardware limits (hw_min_freq to hw_max_freq).
|
||||
If set_min_freq exceeds set_max_freq, the driver clamps set_min_freq to
|
||||
set_max_freq when selecting the operating frequency. Read-write.
|
||||
|
||||
What: /sys/bus/pci/drivers/intel_vpu/.../freq/set_max_freq
|
||||
Date: April 2026
|
||||
KernelVersion: 7.2
|
||||
Contact: dri-devel@lists.freedesktop.org
|
||||
Description: Configured maximum operating frequency in MHz (50XX devices and newer).
|
||||
Values written are clamped to hardware limits (hw_min_freq to hw_max_freq).
|
||||
Read-write.
|
||||
@@ -270,6 +270,31 @@ MERT can report various kinds of telemetry information like the following:
|
||||
* Deep Sleep counter
|
||||
* etc.
|
||||
|
||||
.. _amdxdna-usage-stats:
|
||||
|
||||
Amdxdna DRM client usage stats implementation
|
||||
=============================================
|
||||
|
||||
The amdxdna 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:
|
||||
|
||||
::
|
||||
|
||||
pos: 0
|
||||
flags: 0100002
|
||||
mnt_id: 29
|
||||
ino: 939
|
||||
drm-driver: amdxdna_accel_driver
|
||||
drm-client-id: 3219
|
||||
drm-pdev: 0000:c5:00.1
|
||||
amdxdna_accel_driver-heap-alloc: 60 KiB
|
||||
amdxdna_accel_driver-internal-alloc: 67588 KiB
|
||||
amdxdna_accel_driver-external-alloc: 0
|
||||
drm-total-memory: 67632 KiB
|
||||
drm-shared-memory: 0
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
@@ -36,18 +36,56 @@ properties:
|
||||
|
||||
properties:
|
||||
port@0:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Primary MIPI DSI port-1 for MIPI input or
|
||||
LVDS port-1 for LVDS input or DPI 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
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
required:
|
||||
- data-lanes
|
||||
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
@@ -99,6 +137,7 @@ examples:
|
||||
reg = <0>;
|
||||
|
||||
endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
remote-endpoint = <&dsi0_out>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- doestek,dtc34lm85am # For the Doestek DTC34LM85AM Flat Panel Display (FPD) Transmitter
|
||||
- idt,v103 # For the Triple 10-BIT LVDS Transmitter
|
||||
- onnn,fin3385 # OnSemi FIN3385
|
||||
- ti,ds90c185 # For the TI DS90C185 FPD-Link Serializer
|
||||
- ti,ds90c187 # For the TI DS90C187 FPD-Link Serializer
|
||||
|
||||
@@ -30,6 +30,7 @@ properties:
|
||||
- algoltek,ag6311
|
||||
- asl-tek,cs5263
|
||||
- dumb-vga-dac
|
||||
- mstar,tsumu88adt3-lf-1
|
||||
- parade,ps185hdm
|
||||
- radxa,ra620
|
||||
- realtek,rtd2171
|
||||
|
||||
@@ -10,11 +10,14 @@ maintainers:
|
||||
- Joseph Guo <qijian.guo@nxp.com>
|
||||
|
||||
description:
|
||||
Waveshare bridge board is part of Waveshare panel which converts DSI to DPI.
|
||||
Waveshare bridge board is part of Waveshare panel which converts DSI to DPI
|
||||
or LVDS.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: waveshare,dsi2dpi
|
||||
enum:
|
||||
- waveshare,dsi2dpi
|
||||
- waveshare,dsi2lvds
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -53,7 +56,7 @@ properties:
|
||||
port@1:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Video port for MIPI DPI output panel.
|
||||
Video port for MIPI DPI or LVDS output to the panel.
|
||||
|
||||
required:
|
||||
- port@0
|
||||
|
||||
@@ -16,6 +16,7 @@ properties:
|
||||
- enum:
|
||||
- qcom,apq8064-dsi-ctrl
|
||||
- qcom,kaanapali-dsi-ctrl
|
||||
- qcom,milos-dsi-ctrl
|
||||
- qcom,msm8226-dsi-ctrl
|
||||
- qcom,msm8916-dsi-ctrl
|
||||
- qcom,msm8953-dsi-ctrl
|
||||
@@ -339,6 +340,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,milos-dsi-ctrl
|
||||
- qcom,msm8998-dsi-ctrl
|
||||
- qcom,sa8775p-dsi-ctrl
|
||||
- qcom,sar2130p-dsi-ctrl
|
||||
|
||||
@@ -300,6 +300,36 @@ allOf:
|
||||
required:
|
||||
- qcom,qmp
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,adreno-gmu-810.0
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- description: Core GMU registers
|
||||
reg-names:
|
||||
items:
|
||||
- const: gmu
|
||||
clocks:
|
||||
items:
|
||||
- description: GPU AHB clock
|
||||
- description: GMU clock
|
||||
- description: GPU CX clock
|
||||
- description: GPU AXI clock
|
||||
- description: GPU MEMNOC clock
|
||||
- description: GMU HUB clock
|
||||
clock-names:
|
||||
items:
|
||||
- const: ahb
|
||||
- const: gmu
|
||||
- const: cxo
|
||||
- const: axi
|
||||
- const: memnoc
|
||||
- const: hub
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
||||
@@ -411,6 +411,23 @@ allOf:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,adreno-44010000
|
||||
- qcom,adreno-44070001
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
@@ -434,6 +451,8 @@ allOf:
|
||||
- qcom,adreno-43050a01
|
||||
- qcom,adreno-43050c01
|
||||
- qcom,adreno-43051401
|
||||
- qcom,adreno-44010000
|
||||
- qcom,adreno-44070001
|
||||
|
||||
then: # Starting with A6xx, the clocks are usually defined in the GMU node
|
||||
properties:
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/msm/qcom,milos-mdss.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Milos Display MDSS
|
||||
|
||||
maintainers:
|
||||
- Luca Weiss <luca.weiss@fairphone.com>
|
||||
|
||||
description:
|
||||
Milos MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like
|
||||
DPU display controller, DSI and DP interfaces etc.
|
||||
|
||||
$ref: /schemas/display/msm/mdss-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,milos-mdss
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Display AHB
|
||||
- description: Display hf AXI
|
||||
- description: Display core
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
||||
interconnects:
|
||||
items:
|
||||
- description: Interconnect path from mdp0 port to the data bus
|
||||
- description: Interconnect path from CPU to the reg bus
|
||||
|
||||
interconnect-names:
|
||||
items:
|
||||
- const: mdp0-mem
|
||||
- const: cpu-cfg
|
||||
|
||||
patternProperties:
|
||||
"^display-controller@[0-9a-f]+$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,milos-dpu
|
||||
|
||||
"^displayport-controller@[0-9a-f]+$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,milos-dp
|
||||
|
||||
"^dsi@[0-9a-f]+$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,milos-dsi-ctrl
|
||||
|
||||
"^phy@[0-9a-f]+$":
|
||||
type: object
|
||||
additionalProperties: true
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,milos-dsi-phy-4nm
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,dsi-phy-28nm.h>
|
||||
#include <dt-bindings/clock/qcom,milos-dispcc.h>
|
||||
#include <dt-bindings/clock/qcom,milos-gcc.h>
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
#include <dt-bindings/interconnect/qcom,icc.h>
|
||||
#include <dt-bindings/interconnect/qcom,milos-rpmh.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/qcom,rpmhpd.h>
|
||||
|
||||
display-subsystem@ae00000 {
|
||||
compatible = "qcom,milos-mdss";
|
||||
reg = <0x0ae00000 0x1000>;
|
||||
reg-names = "mdss";
|
||||
|
||||
interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
|
||||
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
|
||||
<&gcc GCC_DISP_HF_AXI_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_MDP_CLK>;
|
||||
|
||||
resets = <&dispcc DISP_CC_MDSS_CORE_BCR>;
|
||||
|
||||
interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS
|
||||
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
|
||||
<&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
|
||||
&cnoc_main SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ACTIVE_ONLY>;
|
||||
interconnect-names = "mdp0-mem",
|
||||
"cpu-cfg";
|
||||
|
||||
power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>;
|
||||
|
||||
iommus = <&apps_smmu 0x1c00 0x2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
display-controller@ae01000 {
|
||||
compatible = "qcom,milos-dpu";
|
||||
reg = <0x0ae01000 0x8f000>,
|
||||
<0x0aeb0000 0x3000>;
|
||||
reg-names = "mdp",
|
||||
"vbif";
|
||||
|
||||
interrupts-extended = <&mdss 0>;
|
||||
|
||||
clocks = <&gcc GCC_DISP_HF_AXI_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_AHB_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_MDP_LUT_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_MDP_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_VSYNC_CLK>;
|
||||
clock-names = "nrt_bus",
|
||||
"iface",
|
||||
"lut",
|
||||
"core",
|
||||
"vsync";
|
||||
|
||||
assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>;
|
||||
assigned-clock-rates = <19200000>;
|
||||
|
||||
operating-points-v2 = <&mdp_opp_table>;
|
||||
|
||||
power-domains = <&rpmhpd RPMHPD_CX>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
dpu_intf1_out: endpoint {
|
||||
remote-endpoint = <&mdss_dsi0_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdp_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp-200000000 {
|
||||
opp-hz = /bits/ 64 <200000000>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>;
|
||||
};
|
||||
|
||||
opp-342000000 {
|
||||
opp-hz = /bits/ 64 <342000000>;
|
||||
required-opps = <&rpmhpd_opp_svs>;
|
||||
};
|
||||
|
||||
opp-402000000 {
|
||||
opp-hz = /bits/ 64 <402000000>;
|
||||
required-opps = <&rpmhpd_opp_svs_l1>;
|
||||
};
|
||||
|
||||
opp-535000000 {
|
||||
opp-hz = /bits/ 64 <535000000>;
|
||||
required-opps = <&rpmhpd_opp_nom>;
|
||||
};
|
||||
|
||||
opp-600000000 {
|
||||
opp-hz = /bits/ 64 <600000000>;
|
||||
required-opps = <&rpmhpd_opp_nom_l1>;
|
||||
};
|
||||
|
||||
opp-630000000 {
|
||||
opp-hz = /bits/ 64 <630000000>;
|
||||
required-opps = <&rpmhpd_opp_turbo>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dsi@ae94000 {
|
||||
compatible = "qcom,milos-dsi-ctrl", "qcom,mdss-dsi-ctrl";
|
||||
reg = <0x0ae94000 0x1000>;
|
||||
reg-names = "dsi_ctrl";
|
||||
|
||||
interrupts-extended = <&mdss 4>;
|
||||
|
||||
clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_PCLK0_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_ESC0_CLK>,
|
||||
<&dispcc DISP_CC_MDSS_AHB_CLK>,
|
||||
<&gcc GCC_DISP_HF_AXI_CLK>;
|
||||
clock-names = "byte",
|
||||
"byte_intf",
|
||||
"pixel",
|
||||
"core",
|
||||
"iface",
|
||||
"bus";
|
||||
|
||||
assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
|
||||
<&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
|
||||
assigned-clock-parents = <&mdss_dsi0_phy DSI_BYTE_PLL_CLK>,
|
||||
<&mdss_dsi0_phy DSI_PIXEL_PLL_CLK>;
|
||||
|
||||
operating-points-v2 = <&mdss_dsi_opp_table>;
|
||||
|
||||
power-domains = <&rpmhpd RPMHPD_CX>;
|
||||
|
||||
phys = <&mdss_dsi0_phy>;
|
||||
phy-names = "dsi";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
mdss_dsi0_in: endpoint {
|
||||
remote-endpoint = <&dpu_intf1_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
mdss_dsi0_out: endpoint {
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdss_dsi_opp_table: opp-table {
|
||||
compatible = "operating-points-v2";
|
||||
|
||||
opp-187500000 {
|
||||
opp-hz = /bits/ 64 <187500000>;
|
||||
required-opps = <&rpmhpd_opp_low_svs>;
|
||||
};
|
||||
|
||||
opp-300000000 {
|
||||
opp-hz = /bits/ 64 <300000000>;
|
||||
required-opps = <&rpmhpd_opp_svs>;
|
||||
};
|
||||
|
||||
opp-358000000 {
|
||||
opp-hz = /bits/ 64 <358000000>;
|
||||
required-opps = <&rpmhpd_opp_svs_l1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mdss_dsi0_phy: phy@ae95000 {
|
||||
compatible = "qcom,milos-dsi-phy-4nm";
|
||||
reg = <0x0ae95000 0x200>,
|
||||
<0x0ae95200 0x300>,
|
||||
<0x0ae95500 0x400>;
|
||||
reg-names = "dsi_phy",
|
||||
"dsi_phy_lane",
|
||||
"dsi_pll";
|
||||
|
||||
clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
|
||||
<&rpmhcc RPMH_CXO_CLK>;
|
||||
clock-names = "iface",
|
||||
"ref";
|
||||
|
||||
#clock-cells = <1>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -18,6 +18,7 @@ properties:
|
||||
- qcom,eliza-dpu
|
||||
- qcom,glymur-dpu
|
||||
- qcom,kaanapali-dpu
|
||||
- qcom,milos-dpu
|
||||
- qcom,sa8775p-dpu
|
||||
- qcom,sm8650-dpu
|
||||
- qcom,sm8750-dpu
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/chipwealth,ch13726a.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Chip Wealth Technology CH13726A AMOLED driver
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||
|
||||
description:
|
||||
Chip Wealth Technology CH13726A is a single-chip solution
|
||||
for AMOLED connected using a MIPI-DSI video interface.
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: ayntec,thor-panel-bottom
|
||||
- const: chipwealth,ch13726a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: DSI virtual channel
|
||||
|
||||
vdd-supply: true
|
||||
vddio-supply: true
|
||||
vdd1v2-supply: true
|
||||
avdd-supply: true
|
||||
|
||||
port: true
|
||||
reset-gpios: true
|
||||
rotation: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- vddio-supply
|
||||
- vdd1v2-supply
|
||||
- avdd-supply
|
||||
- reset-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "ayntec,thor-panel-bottom", "chipwealth,ch13726a";
|
||||
reg = <0>;
|
||||
vdd1v2-supply = <&vreg_l11b_1p2>;
|
||||
vddio-supply = <&vdd_disp_1v8>;
|
||||
vdd-supply = <&vreg_l13b_3p0>;
|
||||
avdd-supply = <&vdd_disp2_2v8>;
|
||||
reset-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,70 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/focaltech,ota7290b.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Focaltech OTA7290B DSI panels
|
||||
|
||||
maintainers:
|
||||
- Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: waveshare,8.8-dsi-touch-a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply:
|
||||
description: supply regulator for VDD, usually 3.3V
|
||||
|
||||
vdda-supply:
|
||||
description: supply regulator for VDDA, 7-10V
|
||||
|
||||
vcc-supply:
|
||||
description: supply regulator for VCCIO, usually 1.5V
|
||||
|
||||
reset-gpios: true
|
||||
backlight: true
|
||||
rotation: true
|
||||
port: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
- vcc-supply
|
||||
- reset-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "waveshare,8.8-dsi-touch-a";
|
||||
reg = <0>;
|
||||
vdd-supply = <&vdd>;
|
||||
vcc-supply = <&vccio>;
|
||||
reset-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
|
||||
backlight = <&backlight>;
|
||||
|
||||
port {
|
||||
endpoint {
|
||||
remote-endpoint = <&mipi_out_panel>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
@@ -30,6 +30,8 @@ properties:
|
||||
- starry,2082109qfh040022-50e
|
||||
# STARRY himax83102-j02 10.51" WUXGA TFT LCD panel
|
||||
- starry,himax83102-j02
|
||||
# Waveshare 12.3-DSI-TOUCH-A panel
|
||||
- waveshare,12.3-dsi-touch-a
|
||||
- const: himax,hx83102
|
||||
|
||||
reg:
|
||||
|
||||
@@ -23,6 +23,8 @@ properties:
|
||||
- hannstar,hsd060bhw4
|
||||
- microchip,ac40t08a-mipi-panel
|
||||
- powkiddy,x55-panel
|
||||
- waveshare,5.0-dsi-touch-a
|
||||
- waveshare,5.5-dsi-touch-a
|
||||
- const: himax,hx8394
|
||||
- items:
|
||||
- enum:
|
||||
|
||||
@@ -24,6 +24,7 @@ properties:
|
||||
- raspberrypi,dsi-7inch
|
||||
- startek,kd050hdfia020
|
||||
- tdo,tl050hdv35
|
||||
- waveshare,7.0-dsi-touch-a
|
||||
- wanchanglong,w552946aaa
|
||||
- wanchanglong,w552946aba
|
||||
- const: ilitek,ili9881c
|
||||
@@ -34,6 +35,7 @@ properties:
|
||||
backlight: true
|
||||
port: true
|
||||
power-supply: true
|
||||
iovcc-supply: true
|
||||
reset-gpios: true
|
||||
rotation: true
|
||||
|
||||
|
||||
@@ -24,6 +24,12 @@ properties:
|
||||
- radxa,display-10hd-ad001
|
||||
- radxa,display-8hd-ad002
|
||||
- taiguanck,xti05101-01a
|
||||
- waveshare,3.4-dsi-touch-c
|
||||
- waveshare,4.0-dsi-touch-c
|
||||
- waveshare,8.0-dsi-touch-a
|
||||
- waveshare,9.0-dsi-touch-b
|
||||
- waveshare,10.1-dsi-touch-a
|
||||
- waveshare,10.1-dsi-touch-b
|
||||
- const: jadard,jd9365da-h3
|
||||
|
||||
reg:
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/novatek,nt35532.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Novatek NT35532-based DSI display panels
|
||||
|
||||
maintainers:
|
||||
- Cristian Cozzolino <cristian_ci@protonmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- flipkart,rimob-panel-nt35532-cs
|
||||
- const: novatek,nt35532
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
backlight: true
|
||||
reset-gpios: true
|
||||
|
||||
avdd-supply:
|
||||
description: positive boost supply regulator
|
||||
|
||||
avee-supply:
|
||||
description: negative boost supply regulator
|
||||
|
||||
vci-supply:
|
||||
description: regulator that supplies the analog voltage
|
||||
|
||||
vddam-supply:
|
||||
description: power supply for MIPI interface
|
||||
|
||||
vddi-supply:
|
||||
description: regulator that supplies the I/O voltage
|
||||
|
||||
port: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- vddi-supply
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
panel@0 {
|
||||
compatible = "flipkart,rimob-panel-nt35532-cs", "novatek,nt35532";
|
||||
reg = <0>;
|
||||
|
||||
backlight = <&pmi8950_wled>;
|
||||
reset-gpios = <&tlmm 61 GPIO_ACTIVE_LOW>;
|
||||
avdd-supply = <&lab>;
|
||||
avee-supply = <&ibb>;
|
||||
vci-supply = <&pm8953_l17>;
|
||||
vddi-supply = <&pm8953_l6>;
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&dsi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -58,6 +58,10 @@ properties:
|
||||
- hydis,hv070wx2-1e0
|
||||
# Jenson Display BL-JT60050-01A 7" WSVGA (1024x600) color TFT LCD LVDS panel
|
||||
- jenson,bl-jt60050-01a
|
||||
# Riverdi RVT101HVLNWC00 10.1" WXGA (1280x800) TFT LCD LVDS panel
|
||||
- riverdi,rvt101hvlnwc00
|
||||
# Riverdi RVT70HSLNWCA0 7.0" WSVGA (1024x600) TFT LCD LVDS panel
|
||||
- riverdi,rvt70hslnwca0
|
||||
# Samsung LTN070NL01 7.0" WSVGA (1024x600) TFT LCD LVDS panel
|
||||
- samsung,ltn070nl01
|
||||
# Samsung LTN101AL03 10.1" WXGA (800x1280) TFT LCD LVDS panel
|
||||
|
||||
@@ -63,6 +63,8 @@ properties:
|
||||
- samsung,s6e3fa7-ams559nk06
|
||||
# Shangai Top Display Optoelectronics 7" TL070WSH30 1024x600 TFT LCD panel
|
||||
- tdo,tl070wsh30
|
||||
# Team Source Display Technology 7" TST070WSBE-196C 1024x600 TFT LCD panel
|
||||
- team-source-display,tst070wsbe-196c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -31,6 +31,8 @@ properties:
|
||||
|
||||
# Ampire AM-1280800N3TZQW-T00H 10.1" WQVGA TFT LCD panel
|
||||
- ampire,am-1280800n3tzqw-t00h
|
||||
# Ampire AM-1280800W8TZQW-T00H 10.1" WXGA TFT LCD panel
|
||||
- ampire,am-1280800w8tzqw-t00h
|
||||
# Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel
|
||||
- ampire,am-480272h3tmqw-t01h
|
||||
# Ampire AM-800480L1TMQW-T00H 5" WVGA TFT LCD panel
|
||||
@@ -97,6 +99,8 @@ properties:
|
||||
- dataimage,fg1001l0dsswmg01
|
||||
# DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface.
|
||||
- dataimage,scf0700c48ggu18
|
||||
# Displaytech DT050BTFT-PTS 5.0" 800x480 TFT LCD Panel
|
||||
- displaytech,dt050btft-pts
|
||||
# DLC Display Co. DLC1010GIG 10.1" WXGA TFT LCD Panel
|
||||
- dlc,dlc1010gig
|
||||
# Emerging Display Technology Corp. 3.5" QVGA TFT LCD panel
|
||||
@@ -232,6 +236,8 @@ properties:
|
||||
- nec,nl12880bc20-05
|
||||
# NEC LCD Technologies,Ltd. WQVGA TFT LCD panel
|
||||
- nec,nl4827hc19-05b
|
||||
# NEC LCD Technologies,Ltd. VGA TFT LCD panel
|
||||
- nec,nl6448bc33-70c
|
||||
# Netron-DY E231732 7.0" WSVGA TFT LCD panel
|
||||
- netron-dy,e231732
|
||||
# Newhaven Display International 480 x 272 TFT LCD panel
|
||||
@@ -304,6 +310,8 @@ properties:
|
||||
- shelly,sca07010-bfn-lnn
|
||||
# Starry KR070PE2T 7" WVGA TFT LCD panel
|
||||
- starry,kr070pe2t
|
||||
# Startek KD070HDFLD092 7" WSVGA TFT LCD panel
|
||||
- startek,kd070hdfld092
|
||||
# Startek KD070WVFPA043-C069A 7" TFT LCD panel
|
||||
- startek,kd070wvfpa
|
||||
# Team Source Display Technology TST043015CMHX 4.3" WQVGA TFT LCD panel
|
||||
@@ -341,10 +349,38 @@ properties:
|
||||
- vivax,tpc9150-panel
|
||||
# VXT 800x480 color TFT LCD panel
|
||||
- vxt,vl050-8048nt-c01
|
||||
# Waveshare 10.1" WXGA (1280x800) LCD panel
|
||||
- waveshare,10.1inch-c-panel
|
||||
# Waveshare 11.9" (320x1480) LCD panel
|
||||
- waveshare,11.9inch-panel
|
||||
# Waveshare 13.3" FHD (1920x1080) LCD panel
|
||||
- waveshare,13.3inch-panel
|
||||
# Waveshare 2.8" VGA (480x640) LCD panel
|
||||
- waveshare,2.8inch-panel
|
||||
# Waveshare 3.4" (800x800) LCD panel
|
||||
- waveshare,3.4inch-c-panel
|
||||
# Waveshare 4.0" WVGA (480x800) LCD panel
|
||||
- waveshare,4.0inch-panel
|
||||
# Waveshare 4.0" (720x720) LCD panel
|
||||
- waveshare,4.0inch-c-panel
|
||||
# Waveshare 5.0" WSVGA (1024x600) LCD panel
|
||||
- waveshare,5.0inch-c-panel
|
||||
# Waveshare 5.0" HD 720p (720x1280) LCD panel
|
||||
- waveshare,5.0inch-d-panel
|
||||
# Waveshare 6.25" (720x1560) LCD panel
|
||||
- waveshare,6.25inch-panel
|
||||
# Waveshare 7.0" WSVGA (1024x600) LCD panel
|
||||
- waveshare,7.0inch-c-panel
|
||||
# Waveshare 7.0" WXGA (1280x800) LCD panel
|
||||
- waveshare,7.0inch-e-panel
|
||||
# Waveshare 7.0" HD 720p (720x1280) LCD panel
|
||||
- waveshare,7.0inch-h-panel
|
||||
# Waveshare 7.9" (400x1280) LCD panel
|
||||
- waveshare,7.9inch-panel
|
||||
# Waveshare 8.0" WXGA (1280x800) LCD panel
|
||||
- waveshare,8.0inch-c-panel
|
||||
# Waveshare 8.8" (480x1920) LCD panel
|
||||
- waveshare,8.8inch-panel
|
||||
# Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel
|
||||
- winstar,wf35ltiacd
|
||||
# Yes Optoelectronics YTC700TLAG-05-201C 7" TFT LCD panel
|
||||
|
||||
@@ -21,6 +21,7 @@ properties:
|
||||
- renesas,r9a07g043u-du # RZ/G2UL
|
||||
- renesas,r9a07g044-du # RZ/G2{L,LC}
|
||||
- renesas,r9a09g057-du # RZ/V2H(P)
|
||||
- renesas,r9a09g077-du # RZ/T2H
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r9a07g054-du # RZ/V2L
|
||||
@@ -28,6 +29,9 @@ properties:
|
||||
- items:
|
||||
- const: renesas,r9a09g056-du # RZ/V2N
|
||||
- const: renesas,r9a09g057-du # RZ/V2H(P) fallback
|
||||
- items:
|
||||
- const: renesas,r9a09g087-du # RZ/N2H
|
||||
- const: renesas,r9a09g077-du # RZ/T2H fallback
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -83,7 +87,6 @@ required:
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- power-domains
|
||||
- ports
|
||||
- renesas,vsps
|
||||
@@ -95,13 +98,16 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a07g043u-du
|
||||
enum:
|
||||
- renesas,r9a07g043u-du
|
||||
- renesas,r9a09g077-du
|
||||
then:
|
||||
properties:
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPI
|
||||
port@1: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
@@ -137,6 +143,17 @@ allOf:
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g077-du
|
||||
then:
|
||||
properties:
|
||||
resets: false
|
||||
else:
|
||||
required:
|
||||
- resets
|
||||
|
||||
examples:
|
||||
# RZ/G2L DU
|
||||
|
||||
@@ -26,6 +26,7 @@ properties:
|
||||
- realtek,rtd1619-mali
|
||||
- renesas,r9a07g044-mali
|
||||
- renesas,r9a07g054-mali
|
||||
- renesas,r9a08g046-mali
|
||||
- renesas,r9a09g047-mali
|
||||
- renesas,r9a09g056-mali
|
||||
- renesas,r9a09g057-mali
|
||||
@@ -150,6 +151,7 @@ allOf:
|
||||
enum:
|
||||
- renesas,r9a07g044-mali
|
||||
- renesas,r9a07g054-mali
|
||||
- renesas,r9a08g046-mali
|
||||
- renesas,r9a09g047-mali
|
||||
- renesas,r9a09g056-mali
|
||||
- renesas,r9a09g057-mali
|
||||
|
||||
@@ -20,6 +20,7 @@ properties:
|
||||
- qcom,dsi-phy-7nm
|
||||
- qcom,dsi-phy-7nm-8150
|
||||
- qcom,kaanapali-dsi-phy-3nm
|
||||
- qcom,milos-dsi-phy-4nm
|
||||
- qcom,sa8775p-dsi-phy-5nm
|
||||
- qcom,sar2130p-dsi-phy-5nm
|
||||
- qcom,sc7280-dsi-phy-7nm
|
||||
|
||||
@@ -437,6 +437,8 @@ patternProperties:
|
||||
description: Diodes, Inc.
|
||||
"^dioo,.*":
|
||||
description: Dioo Microcircuit Co., Ltd
|
||||
"^displaytech,.*":
|
||||
description: Displaytech Ltd.
|
||||
"^djn,.*":
|
||||
description: Shenzhen DJN Optronics Technology Co., Ltd
|
||||
"^dlc,.*":
|
||||
|
||||
@@ -233,8 +233,15 @@ we have a dedicated glossary for Display Core at
|
||||
TC
|
||||
Texture Cache
|
||||
|
||||
TCC
|
||||
Texture Cache per Channel - L2 cache attached to the memory channels.
|
||||
May be used when shader cores are accessing memory.
|
||||
Despite "Texture" in the name, this is used by any kind of memory access.
|
||||
TCCs may be mapped to TCPs, depending on the architecture.
|
||||
|
||||
TCP (AMDGPU)
|
||||
Texture Cache per Pipe. Even though the name "Texture" is part of this
|
||||
Texture Cache per Pipe - L1 cache attached to each CU.
|
||||
Even though the name "Texture" is part of this
|
||||
acronym, the TCP represents the path to memory shaders; i.e., it is not
|
||||
related to texture. The name is a leftover from older designs where shader
|
||||
stages had different cache designs; it refers to the L1 cache in older
|
||||
|
||||
@@ -23,3 +23,4 @@ Next (GCN), Radeon DNA (RDNA), and Compute DNA (CDNA) architectures.
|
||||
debugfs
|
||||
process-isolation
|
||||
amdgpu-glossary
|
||||
ptl
|
||||
|
||||
94
Documentation/gpu/amdgpu/ptl.rst
Normal file
94
Documentation/gpu/amdgpu/ptl.rst
Normal file
@@ -0,0 +1,94 @@
|
||||
=======================================
|
||||
Peak Tops Limiter (PTL) sysfs Interface
|
||||
=======================================
|
||||
|
||||
Overview
|
||||
--------
|
||||
The Peak Tops Limiter (PTL) sysfs interface enables users to control and
|
||||
configure the PTL feature for each GPU individually. All PTL-related
|
||||
sysfs files are located under `/sys/class/drm/cardX/device/ptl/`, where
|
||||
`X` is the GPU index. Through these files, users can enable or disable
|
||||
PTL, set preferred data formats, and query supported formats for each GPU.
|
||||
|
||||
PTL sysfs files
|
||||
----------------
|
||||
The following files are available under `/sys/class/drm/cardX/device/ptl/`:
|
||||
|
||||
- `ptl_enable`
|
||||
- `ptl_format`
|
||||
- `ptl_supported_formats`
|
||||
|
||||
PTL Enable/Disable
|
||||
------------------
|
||||
File: `ptl_enable`
|
||||
Type: Read/Write (rw)
|
||||
|
||||
Read: Returns the current PTL status as a string: `enabled` if PTL
|
||||
is active, or `disabled` if inactive.
|
||||
|
||||
Write:
|
||||
|
||||
- Write `1` or `enabled` to enable PTL
|
||||
- Write `0` or `disabled` to disable PTL
|
||||
|
||||
Examples::
|
||||
|
||||
# Query PTL status
|
||||
cat /sys/class/drm/card1/device/ptl/ptl_enable
|
||||
# Output: enabled
|
||||
|
||||
# Enable PTL
|
||||
sudo bash -c "echo 1 > /sys/class/drm/card1/device/ptl/ptl_enable"
|
||||
|
||||
# Disable PTL
|
||||
sudo bash -c "echo 0 > /sys/class/drm/card1/device/ptl/ptl_enable"
|
||||
|
||||
PTL Format (Preferred Data Formats)
|
||||
-----------------------------------
|
||||
File: `ptl_format`
|
||||
Type: Read/Write (rw)
|
||||
|
||||
Read: Returns the two preferred formats, e.g. `I8,F32`.
|
||||
|
||||
Write: Accepts two formats separated by a comma, e.g. `I8,F32`.
|
||||
|
||||
- Both formats must be supported and different.
|
||||
- If an invalid format is provided (not supported, or both formats are the
|
||||
same), the driver will return "write error: Invalid argument".
|
||||
|
||||
Examples::
|
||||
|
||||
# Query PTL formats
|
||||
cat /sys/class/drm/card1/device/ptl/ptl_format
|
||||
# Output: I8,F32
|
||||
|
||||
# Set PTL formats
|
||||
sudo bash -c "echo I8,F32 > /sys/class/drm/card1/device/ptl/ptl_format"
|
||||
|
||||
Supported Formats
|
||||
-----------------
|
||||
File: `ptl_supported_formats`
|
||||
Type: Read-only (r)
|
||||
|
||||
Read: Returns a comma-separated list of supported formats, e.g.
|
||||
`I8,F16,BF16,F32,F64`.
|
||||
|
||||
Example::
|
||||
|
||||
# Check supported formats
|
||||
cat /sys/class/drm/card1/device/ptl/ptl_supported_formats
|
||||
# Output: I8,F16,BF16,F32,F64
|
||||
|
||||
Behavioral Notes
|
||||
----------------
|
||||
- PTL formats can only be set when PTL is enabled.
|
||||
- If PTL is disabled, `ptl_format` returns `N/A`.
|
||||
- Only two formats can be set at a time, and they must be from the supported set and different..
|
||||
- All commands support per-GPU targeting.
|
||||
- Root permission is required to enable/disable PTL or change formats.
|
||||
- If the hardware does not support PTL, the PTL sysfs directory will not
|
||||
be created.
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
The PTL sysfs nodes are implemented in `drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c`.
|
||||
@@ -2,6 +2,8 @@
|
||||
DRM Driver uAPI
|
||||
===============
|
||||
|
||||
.. contents::
|
||||
|
||||
drm/i915 uAPI
|
||||
=============
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ GPU Driver Documentation
|
||||
amdgpu/index
|
||||
i915
|
||||
imagination/index
|
||||
intel-display/index
|
||||
mcde
|
||||
meson
|
||||
nouveau
|
||||
|
||||
@@ -18,6 +18,8 @@ event handling, memory management, output management, framebuffer
|
||||
management, command submission & fencing, suspend/resume support, and
|
||||
DMA services.
|
||||
|
||||
.. contents::
|
||||
|
||||
Driver Initialization
|
||||
=====================
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ There are a few areas these helpers can grouped into:
|
||||
pipeline: Planes, handling rectangles for visibility checking and scissoring,
|
||||
flip queues and assorted bits.
|
||||
|
||||
.. contents::
|
||||
|
||||
Modeset Helper Reference for Common Vtables
|
||||
===========================================
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
|
||||
.. _drm-kms:
|
||||
|
||||
=========================
|
||||
Kernel Mode Setting (KMS)
|
||||
=========================
|
||||
@@ -15,6 +18,8 @@ be setup by initializing the following fields.
|
||||
- struct drm_mode_config_funcs \*funcs;
|
||||
Mode setting functions.
|
||||
|
||||
.. contents::
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
@@ -206,11 +211,11 @@ Atomic Mode Setting
|
||||
style=dashed
|
||||
label="Free-standing state"
|
||||
|
||||
"drm_atomic_state" -> "duplicated drm_plane_state A"
|
||||
"drm_atomic_state" -> "duplicated drm_plane_state B"
|
||||
"drm_atomic_state" -> "duplicated drm_crtc_state"
|
||||
"drm_atomic_state" -> "duplicated drm_connector_state"
|
||||
"drm_atomic_state" -> "duplicated driver private state"
|
||||
"drm_atomic_commit" -> "duplicated drm_plane_state A"
|
||||
"drm_atomic_commit" -> "duplicated drm_plane_state B"
|
||||
"drm_atomic_commit" -> "duplicated drm_crtc_state"
|
||||
"drm_atomic_commit" -> "duplicated drm_connector_state"
|
||||
"drm_atomic_commit" -> "duplicated driver private state"
|
||||
}
|
||||
|
||||
subgraph cluster_current {
|
||||
@@ -230,7 +235,7 @@ Atomic Mode Setting
|
||||
"driver private object" -> "driver private state"
|
||||
}
|
||||
|
||||
"drm_atomic_state" -> "drm_device" [label="atomic_commit"]
|
||||
"drm_atomic_commit" -> "drm_device" [label="atomic_commit"]
|
||||
"duplicated drm_plane_state A" -> "drm_device"[style=invis]
|
||||
}
|
||||
|
||||
@@ -265,7 +270,7 @@ Taken all together there's two consequences for the atomic design:
|
||||
drm_private_state<drm_private_state>`.
|
||||
|
||||
- An atomic update is assembled and validated as an entirely free-standing pile
|
||||
of structures within the :c:type:`drm_atomic_state <drm_atomic_state>`
|
||||
of structures within the :c:type:`drm_atomic_commit <drm_atomic_commit>`
|
||||
container. Driver private state structures are also tracked in the same
|
||||
structure; see the next chapter. Only when a state is committed is it applied
|
||||
to the driver and modeset objects. This way rolling back an update boils down
|
||||
|
||||
@@ -25,6 +25,8 @@ share it. GEM has simpler initialization and execution requirements than
|
||||
TTM, but has no video RAM management capabilities and is thus limited to
|
||||
UMA devices.
|
||||
|
||||
.. contents::
|
||||
|
||||
The Translation Table Manager (TTM)
|
||||
===================================
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ Key Goals:
|
||||
nodes for different IP blocks, sub-blocks, or other logical subdivisions
|
||||
as applicable.
|
||||
|
||||
.. contents::
|
||||
|
||||
Nodes
|
||||
=====
|
||||
|
||||
@@ -52,6 +54,8 @@ User space tools can:
|
||||
as a parameter.
|
||||
* Query specific error counter values with the ``get-error-counter`` command, using both
|
||||
``node-id`` and ``error-id`` as parameters.
|
||||
* Clear specific error counters with the ``clear-error-counter`` command, using both
|
||||
``node-id`` and ``error-id`` as parameters.
|
||||
|
||||
YAML-based Interface
|
||||
--------------------
|
||||
@@ -101,3 +105,9 @@ Example: Query an error counter for a given node
|
||||
sudo ynl --family drm_ras --do get-error-counter --json '{"node-id":0, "error-id":1}'
|
||||
{'error-id': 1, 'error-name': 'error_name1', 'error-value': 0}
|
||||
|
||||
Example: Clear an error counter for a given node
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo ynl --family drm_ras --do clear-error-counter --json '{"node-id":0, "error-id":1}'
|
||||
None
|
||||
|
||||
@@ -16,6 +16,8 @@ management, and output management.
|
||||
Cover generic ioctls and sysfs layout here. We only need high-level
|
||||
info, since man pages should cover the rest.
|
||||
|
||||
.. contents::
|
||||
|
||||
libdrm Device Lookup
|
||||
====================
|
||||
|
||||
@@ -118,6 +120,10 @@ is already rather painful for the DRM subsystem, with multiple different uAPIs
|
||||
for the same thing co-existing. If we add a few more complete mistakes into the
|
||||
mix every year it would be entirely unmanageable.
|
||||
|
||||
The DRM subsystem has however no concern with independent closed-source
|
||||
userspace implementations. To officialize that position, the DRM uAPI headers
|
||||
are covered by the MIT license.
|
||||
|
||||
.. _drm_render_node:
|
||||
|
||||
Render nodes
|
||||
@@ -761,4 +767,4 @@ Stable uAPI events
|
||||
From ``drivers/gpu/drm/scheduler/gpu_scheduler_trace.h``
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/scheduler/gpu_scheduler_trace.h
|
||||
:doc: uAPI trace events
|
||||
:doc: uAPI trace events
|
||||
|
||||
@@ -16,6 +16,8 @@ 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.
|
||||
|
||||
.. contents::
|
||||
|
||||
File format specification
|
||||
=========================
|
||||
|
||||
@@ -215,3 +217,4 @@ Driver specific implementations
|
||||
* :ref:`panfrost-usage-stats`
|
||||
* :ref:`panthor-usage-stats`
|
||||
* :ref:`xe-usage-stats`
|
||||
* :ref:`amdxdna-usage-stats`
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
|
||||
.. _drm/i915:
|
||||
|
||||
===========================
|
||||
drm/i915 Intel GFX Driver
|
||||
===========================
|
||||
@@ -7,6 +10,9 @@ models) integrated GFX chipsets with both Intel display and rendering
|
||||
blocks. This excludes a set of SoC platforms with an SGX rendering unit,
|
||||
those have basic support through the gma500 drm driver.
|
||||
|
||||
The display, or :ref:`drm-kms`, support for drm/i915 is provided by
|
||||
:ref:`drm/intel-display`, and shared with :ref:`drm/xe <drm/xe>`.
|
||||
|
||||
Core Driver Infrastructure
|
||||
==========================
|
||||
|
||||
@@ -64,200 +70,6 @@ Workarounds
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/gt/intel_workarounds.c
|
||||
:doc: Hardware workarounds
|
||||
|
||||
Display Hardware Handling
|
||||
=========================
|
||||
|
||||
This section covers everything related to the display hardware including
|
||||
the mode setting infrastructure, plane, sprite and cursor handling and
|
||||
display, output probing and related topics.
|
||||
|
||||
Mode Setting Infrastructure
|
||||
---------------------------
|
||||
|
||||
The i915 driver is thus far the only DRM driver which doesn't use the
|
||||
common DRM helper code to implement mode setting sequences. Thus it has
|
||||
its own tailor-made infrastructure for executing a display configuration
|
||||
change.
|
||||
|
||||
Frontbuffer Tracking
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.c
|
||||
:doc: frontbuffer tracking
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.c
|
||||
:internal:
|
||||
|
||||
Display FIFO Underrun Reporting
|
||||
-------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fifo_underrun.c
|
||||
:doc: fifo underrun handling
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fifo_underrun.c
|
||||
:internal:
|
||||
|
||||
Plane Configuration
|
||||
-------------------
|
||||
|
||||
This section covers plane configuration and composition with the primary
|
||||
plane, sprites, cursors and overlays. This includes the infrastructure
|
||||
to do atomic vsync'ed updates of all this state and also tightly coupled
|
||||
topics like watermark setup and computation, framebuffer compression and
|
||||
panel self refresh.
|
||||
|
||||
Atomic Plane Helpers
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_plane.c
|
||||
:doc: atomic plane helpers
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_plane.c
|
||||
:internal:
|
||||
|
||||
Asynchronous Page Flip
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_display.c
|
||||
:doc: asynchronous flip implementation
|
||||
|
||||
Output Probing
|
||||
--------------
|
||||
|
||||
This section covers output probing and related infrastructure like the
|
||||
hotplug interrupt storm detection and mitigation code. Note that the
|
||||
i915 driver still uses most of the common DRM helper code for output
|
||||
probing, so those sections fully apply.
|
||||
|
||||
Hotplug
|
||||
-------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_hotplug.c
|
||||
:doc: Hotplug
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_hotplug.c
|
||||
:internal:
|
||||
|
||||
High Definition Audio
|
||||
---------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_audio.c
|
||||
:doc: High Definition Audio over HDMI and Display Port
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_audio.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: include/drm/intel/i915_component.h
|
||||
:internal:
|
||||
|
||||
Intel HDMI LPE Audio Support
|
||||
----------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_lpe_audio.c
|
||||
:doc: LPE Audio integration for HDMI or DP playback
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_lpe_audio.c
|
||||
:internal:
|
||||
|
||||
Panel Self Refresh PSR (PSR/SRD)
|
||||
--------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_psr.c
|
||||
:doc: Panel Self Refresh (PSR/SRD)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_psr.c
|
||||
:internal:
|
||||
|
||||
Frame Buffer Compression (FBC)
|
||||
------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fbc.c
|
||||
:doc: Frame Buffer Compression (FBC)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fbc.c
|
||||
:internal:
|
||||
|
||||
Display Refresh Rate Switching (DRRS)
|
||||
-------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:doc: Display Refresh Rate Switching (DRRS)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:internal:
|
||||
|
||||
DPIO
|
||||
----
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpio_phy.c
|
||||
:doc: DPIO
|
||||
|
||||
DMC Firmware Support
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c
|
||||
:doc: DMC Firmware Support
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c
|
||||
:internal:
|
||||
|
||||
DMC Flip Queue
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_flipq.c
|
||||
:doc: DMC Flip Queue
|
||||
|
||||
DMC wakelock support
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc_wl.c
|
||||
:doc: DMC wakelock support
|
||||
|
||||
Video BIOS Table (VBT)
|
||||
----------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_bios.c
|
||||
:doc: Video BIOS Table (VBT)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_bios.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_vbt_defs.h
|
||||
:internal:
|
||||
|
||||
Display clocks
|
||||
--------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_cdclk.c
|
||||
:doc: CDCLK / RAWCLK
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_cdclk.c
|
||||
:internal:
|
||||
|
||||
Display PLLs
|
||||
------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpll_mgr.c
|
||||
:doc: Display PLLs
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpll_mgr.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpll_mgr.h
|
||||
:internal:
|
||||
|
||||
Display State Buffer
|
||||
--------------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dsb.c
|
||||
:doc: DSB
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dsb.c
|
||||
:internal:
|
||||
|
||||
GT Programming
|
||||
==============
|
||||
|
||||
@@ -568,7 +380,7 @@ The HuC FW layout is the same as the GuC one, see `GuC Firmware Layout`_
|
||||
|
||||
DMC
|
||||
---
|
||||
See `DMC Firmware Support`_
|
||||
See :ref:`drm/intel-display/dmc`.
|
||||
|
||||
Tracing
|
||||
=======
|
||||
|
||||
@@ -3,6 +3,7 @@ GPU Driver Developer's Guide
|
||||
============================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
introduction
|
||||
drm-internals
|
||||
|
||||
8
Documentation/gpu/intel-display/async-flip.rst
Normal file
8
Documentation/gpu/intel-display/async-flip.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Asynchronous Page Flip
|
||||
======================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_display.c
|
||||
:doc: asynchronous flip implementation
|
||||
11
Documentation/gpu/intel-display/atomic.rst
Normal file
11
Documentation/gpu/intel-display/atomic.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Atomic Modeset Support
|
||||
======================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_atomic.c
|
||||
:doc: atomic modeset support
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_atomic.c
|
||||
:internal:
|
||||
23
Documentation/gpu/intel-display/audio.rst
Normal file
23
Documentation/gpu/intel-display/audio.rst
Normal file
@@ -0,0 +1,23 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
High Definition Audio
|
||||
=====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_audio.c
|
||||
:doc: High Definition Audio over HDMI and Display Port
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_audio.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: include/drm/intel/i915_component.h
|
||||
:internal:
|
||||
|
||||
Intel HDMI LPE Audio Support
|
||||
============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_lpe_audio.c
|
||||
:doc: LPE Audio integration for HDMI or DP playback
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_lpe_audio.c
|
||||
:internal:
|
||||
8
Documentation/gpu/intel-display/casf.rst
Normal file
8
Documentation/gpu/intel-display/casf.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Content Adaptive Sharpness Filter (CASF)
|
||||
========================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_casf.c
|
||||
:doc: Content Adaptive Sharpness Filter (CASF)
|
||||
11
Documentation/gpu/intel-display/cdclk.rst
Normal file
11
Documentation/gpu/intel-display/cdclk.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Display clocks
|
||||
==============
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_cdclk.c
|
||||
:doc: CDCLK / RAWCLK
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_cdclk.c
|
||||
:internal:
|
||||
8
Documentation/gpu/intel-display/cmtg.rst
Normal file
8
Documentation/gpu/intel-display/cmtg.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Common Primary Timing Generator (CMTG)
|
||||
======================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_cmtg.c
|
||||
:doc: Common Primary Timing Generator (CMTG)
|
||||
26
Documentation/gpu/intel-display/dmc.rst
Normal file
26
Documentation/gpu/intel-display/dmc.rst
Normal file
@@ -0,0 +1,26 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
.. _drm/intel-display/dmc:
|
||||
|
||||
DMC Firmware Support
|
||||
====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c
|
||||
:doc: DMC Firmware Support
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc.c
|
||||
:internal:
|
||||
|
||||
|
||||
DMC Flip Queue
|
||||
==============
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_flipq.c
|
||||
:doc: DMC Flip Queue
|
||||
|
||||
DMC wakelock support
|
||||
====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dmc_wl.c
|
||||
:doc: DMC wakelock support
|
||||
8
Documentation/gpu/intel-display/dpio.rst
Normal file
8
Documentation/gpu/intel-display/dpio.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
DPIO
|
||||
====
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpio_phy.c
|
||||
:doc: DPIO
|
||||
14
Documentation/gpu/intel-display/dpll.rst
Normal file
14
Documentation/gpu/intel-display/dpll.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Display PLLs
|
||||
============
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpll_mgr.c
|
||||
:doc: Display PLLs
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpll_mgr.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dpll_mgr.h
|
||||
:internal:
|
||||
11
Documentation/gpu/intel-display/drrs.rst
Normal file
11
Documentation/gpu/intel-display/drrs.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Display Refresh Rate Switching (DRRS)
|
||||
=====================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:doc: Display Refresh Rate Switching (DRRS)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_drrs.c
|
||||
:internal:
|
||||
11
Documentation/gpu/intel-display/dsb.rst
Normal file
11
Documentation/gpu/intel-display/dsb.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Display State Buffer
|
||||
====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dsb.c
|
||||
:doc: DSB
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dsb.c
|
||||
:internal:
|
||||
11
Documentation/gpu/intel-display/fbc.rst
Normal file
11
Documentation/gpu/intel-display/fbc.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Frame Buffer Compression (FBC)
|
||||
==============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fbc.c
|
||||
:doc: Frame Buffer Compression (FBC)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fbc.c
|
||||
:internal:
|
||||
11
Documentation/gpu/intel-display/fifo-underrun.rst
Normal file
11
Documentation/gpu/intel-display/fifo-underrun.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Display FIFO Underrun Reporting
|
||||
===============================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fifo_underrun.c
|
||||
:doc: fifo underrun handling
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_fifo_underrun.c
|
||||
:internal:
|
||||
14
Documentation/gpu/intel-display/frontbuffer.rst
Normal file
14
Documentation/gpu/intel-display/frontbuffer.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Frontbuffer Tracking
|
||||
====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.c
|
||||
:doc: frontbuffer tracking
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_frontbuffer.c
|
||||
:internal:
|
||||
11
Documentation/gpu/intel-display/hotplug.rst
Normal file
11
Documentation/gpu/intel-display/hotplug.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Hotplug
|
||||
=======
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_hotplug.c
|
||||
:doc: Hotplug
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_hotplug.c
|
||||
:internal:
|
||||
44
Documentation/gpu/intel-display/index.rst
Normal file
44
Documentation/gpu/intel-display/index.rst
Normal file
@@ -0,0 +1,44 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
.. _drm/intel-display:
|
||||
|
||||
====================
|
||||
Intel Display Driver
|
||||
====================
|
||||
|
||||
The Intel display driver provides the display, or :ref:`drm-kms`, support for
|
||||
both the :ref:`drm/xe <drm/xe>` and :ref:`drm/i915 <drm/i915>` Intel GPU
|
||||
drivers.
|
||||
|
||||
The source code currently resides under ``drivers/gpu/drm/i915/display`` due to
|
||||
historical reasons, and it's compiled separately into both drm/xe and drm/i915
|
||||
kernel modules.
|
||||
|
||||
The drm/xe and drm/i915 drivers are the "core" or "parent" drivers for display,
|
||||
as they initialize and own the drm device, and pass that on to the display
|
||||
driver. The display driver isn't an independent driver in that sense.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:caption: Detailed display topics
|
||||
|
||||
async-flip
|
||||
atomic
|
||||
audio
|
||||
casf
|
||||
cdclk
|
||||
cmtg
|
||||
dmc
|
||||
dpio
|
||||
dpll
|
||||
drrs
|
||||
dsb
|
||||
fbc
|
||||
fifo-underrun
|
||||
frontbuffer
|
||||
hotplug
|
||||
plane
|
||||
psr
|
||||
snps-phy
|
||||
vbt
|
||||
11
Documentation/gpu/intel-display/plane.rst
Normal file
11
Documentation/gpu/intel-display/plane.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Atomic Plane Helpers
|
||||
====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_plane.c
|
||||
:doc: atomic plane helpers
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_plane.c
|
||||
:internal:
|
||||
11
Documentation/gpu/intel-display/psr.rst
Normal file
11
Documentation/gpu/intel-display/psr.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Panel Self Refresh PSR (PSR/SRD)
|
||||
================================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_psr.c
|
||||
:doc: Panel Self Refresh (PSR/SRD)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_psr.c
|
||||
:internal:
|
||||
8
Documentation/gpu/intel-display/snps-phy.rst
Normal file
8
Documentation/gpu/intel-display/snps-phy.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Synopsis PHY support
|
||||
====================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_snps_phy.c
|
||||
:doc: Synopsis PHY support
|
||||
14
Documentation/gpu/intel-display/vbt.rst
Normal file
14
Documentation/gpu/intel-display/vbt.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
.. SPDX-License-Identifier: MIT
|
||||
.. Copyright © 2026 Intel Corporation
|
||||
|
||||
Video BIOS Table (VBT)
|
||||
======================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_bios.c
|
||||
:doc: Video BIOS Table (VBT)
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_bios.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/i915/display/intel_vbt_defs.h
|
||||
:internal:
|
||||
@@ -16,6 +16,8 @@ found in current kernels.
|
||||
|
||||
[Insert diagram of typical DRM stack here]
|
||||
|
||||
.. contents::
|
||||
|
||||
Style Guidelines
|
||||
================
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ So, one KMS-Obj represents a sub-pipeline of komeda resources.
|
||||
So, for komeda, we treat KMS crtc/plane/connector as users of pipeline and
|
||||
component, and at any one time a pipeline/component only can be used by one
|
||||
user. And pipeline/component will be treated as private object of DRM-KMS; the
|
||||
state will be managed by drm_atomic_state as well.
|
||||
state will be managed by drm_atomic_commit as well.
|
||||
|
||||
How to map plane to Layer(input) pipeline
|
||||
-----------------------------------------
|
||||
@@ -416,8 +416,8 @@ Add :c:type:`drm_private_obj` to :c:type:`komeda_component`, :c:type:`komeda_pip
|
||||
...
|
||||
}
|
||||
|
||||
Tracking component_state/pipeline_state by drm_atomic_state
|
||||
-----------------------------------------------------------
|
||||
Tracking component_state/pipeline_state by drm_atomic_commit
|
||||
------------------------------------------------------------
|
||||
|
||||
Add :c:type:`drm_private_state` and user to :c:type:`komeda_component_state`,
|
||||
:c:type:`komeda_pipeline_state`
|
||||
@@ -454,7 +454,7 @@ similar, usually including the following steps:
|
||||
put the data flow into next stage.
|
||||
Setup 2: check user_state with component features and capabilities to see
|
||||
if requirements can be met; if not, return fail.
|
||||
Setup 3: get component_state from drm_atomic_state, and try set to set
|
||||
Setup 3: get component_state from drm_atomic_commit, and try set to set
|
||||
user to component; fail if component has been assigned to another
|
||||
user already.
|
||||
Setup 3: configure the component_state, like set its input component,
|
||||
|
||||
@@ -46,12 +46,71 @@ region is only accessible to heavy-secure ucode.
|
||||
are of type 0xE0 and can be identified as such. This could be subject to change
|
||||
in future generations.
|
||||
|
||||
IFR Header
|
||||
----------
|
||||
On Kepler and later GPUs, the ROM begins with an Init-from-ROM (IFR) header
|
||||
rather than a standard PCI ROM signature (0xAA55). The driver must parse the
|
||||
IFR header to find where the PCI ROM images actually start.
|
||||
|
||||
Init-from-ROM (IFR) is a special GPU feature used for power management
|
||||
on some Nvidia GPUs. It references data in the VBIOS for its operation,
|
||||
but for drivers the important piece is a header that precedes the
|
||||
VBIOS PCI Expansion ROM.
|
||||
|
||||
Most such GPUs do not need to parse the IFR header in order to find the
|
||||
VBIOS, but the Nvidia GA100 is the exception. GA100 lacks a display engine,
|
||||
so the PRAMIN method (which reads the VBIOS from VRAM via display hardware)
|
||||
is unavailable, forcing the driver to read the ROM directly via PROM.
|
||||
On other similar GPUs, either PRAMIN succeeds before PROM is tried, or the
|
||||
IFR hardware has already applied the ROM offset so that PROM reads
|
||||
transparently skip the IFR header.
|
||||
|
||||
The driver should first check for the standard 0xAA55 signature at offset 0.
|
||||
If found, there is no IFR header and the PCI ROM images start at
|
||||
offset 0. If not found, check for the IFR signature and parse the header to
|
||||
determine the PCI ROM image offset.
|
||||
|
||||
Fixed Header Format
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The IFR header begins with four 32-bit words at fixed offsets::
|
||||
|
||||
Offset Name Fields
|
||||
------ ------- ------
|
||||
0x00 FIXED0 bits 31:0 - Signature (must be 0x4947564E, ASCII "NVGI")
|
||||
0x04 FIXED1 bit 31 - Reserved
|
||||
bits 30:16 - FIXED_DATA_SIZE Fixed data size (offset to extended section)
|
||||
bits 15:8 - VERSIONSW Software version
|
||||
bits 7:0 - Reserved
|
||||
0x08 FIXED2 bit 31 - Reserved
|
||||
bits 30:20 - Reserved (zero)
|
||||
bits 19:0 - TOTAL_DATA_SIZE Total data size
|
||||
|
||||
Finding the PCI ROM Image Offset
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The method to find this offset depends on `VERSIONSW`.
|
||||
|
||||
- **Version 1 and 2**: Read `FIXED_DATA_SIZE` from `FIXED1` to get the extended
|
||||
section offset. The PCI ROM image is the 32-bit value at `FIXED_DATA_SIZE + 4`.
|
||||
|
||||
- **Version 3**: Read `TOTAL_DATA_SIZE` from `FIXED2`. The 32-bit value at that
|
||||
offset is a flash status offset. Add 4096 to get the ROM directory offset,
|
||||
`ROM_DIRECTORY_OFFSET`. The ROM directory must have signature 0x44524652
|
||||
(ASCII "RFRD"). The PCI ROM image offset is the 32-bit value at
|
||||
`ROM_DIRECTORY_OFFSET + 8`.
|
||||
|
||||
The PCI ROM image offset must be 4-byte aligned. All offsets are relative to the
|
||||
start of ROM (BAR0 + 0x300000).
|
||||
|
||||
VBIOS ROM Layout
|
||||
----------------
|
||||
The VBIOS layout is roughly a series of concatenated images laid out as follows::
|
||||
The VBIOS (PCI Expansion ROM) is a series of concatenated images laid out as
|
||||
follows. On GPUs with an IFR header, this layout begins at the image offset
|
||||
determined by parsing the IFR header. On older GPUs, it begins at offset 0::
|
||||
|
||||
+----------------------------------------------------------------------------+
|
||||
| VBIOS (Starting at ROM_OFFSET: 0x300000) |
|
||||
| VBIOS (Starting at ROM_OFFSET: 0x300000 + IFR image offset) |
|
||||
+----------------------------------------------------------------------------+
|
||||
| +-----------------------------------------------+ |
|
||||
| | PciAt Image (Type 0x00) | |
|
||||
@@ -173,7 +232,7 @@ Falcon data in the VBIOS which contains the PMU lookup table. This lookup table
|
||||
used to find the required Falcon ucode based on an application ID.
|
||||
|
||||
The location of the PMU lookup table is found by scanning the BIT (`BIOS Information Table`_)
|
||||
tokens for a token with the id `BIT_TOKEN_ID_FALCON_DATA` (0x70) which indicates the
|
||||
tokens for a token with the Falcon data token id (0x70) which indicates the
|
||||
offset of the same from the start of the VBIOS image. Unfortunately, the offset
|
||||
does not account for the EFI image located between the PciAt and FwSec images.
|
||||
The `vbios.rs` code compensates for this with appropriate arithmetic.
|
||||
|
||||
@@ -18,23 +18,9 @@ host such documentation:
|
||||
|
||||
.. toctree::
|
||||
|
||||
gpusvm.rst
|
||||
|
||||
.. toctree::
|
||||
|
||||
i915_gem_lmem.rst
|
||||
|
||||
.. toctree::
|
||||
|
||||
i915_scheduler.rst
|
||||
|
||||
.. toctree::
|
||||
|
||||
i915_small_bar.rst
|
||||
|
||||
.. toctree::
|
||||
|
||||
i915_vm_bind.rst
|
||||
|
||||
.. toctree::
|
||||
color_pipeline.rst
|
||||
gpusvm
|
||||
i915_gem_lmem
|
||||
i915_scheduler
|
||||
i915_small_bar
|
||||
i915_vm_bind
|
||||
color_pipeline
|
||||
|
||||
@@ -152,29 +152,6 @@ Contact: Simona Vetter, respective driver maintainers
|
||||
|
||||
Level: Advanced
|
||||
|
||||
Rename drm_atomic_state
|
||||
-----------------------
|
||||
|
||||
The KMS framework uses two slightly different definitions for the ``state``
|
||||
concept. For a given object (plane, CRTC, encoder, etc., so
|
||||
``drm_$OBJECT_state``), the state is the entire state of that object. However,
|
||||
at the device level, ``drm_atomic_state`` refers to a state update for a
|
||||
limited number of objects.
|
||||
|
||||
The state isn't the entire device state, but only the full state of some
|
||||
objects in that device. This is confusing to newcomers, and
|
||||
``drm_atomic_state`` should be renamed to something clearer like
|
||||
``drm_atomic_commit``.
|
||||
|
||||
In addition to renaming the structure itself, it would also imply renaming some
|
||||
related functions (``drm_atomic_state_alloc``, ``drm_atomic_state_get``,
|
||||
``drm_atomic_state_put``, ``drm_atomic_state_init``,
|
||||
``__drm_atomic_state_free``, etc.).
|
||||
|
||||
Contact: Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
Level: Advanced
|
||||
|
||||
Fallout from atomic KMS
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.. SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
|
||||
.. _drm/xe:
|
||||
|
||||
=======================
|
||||
drm/xe Intel GFX Driver
|
||||
=======================
|
||||
@@ -8,6 +10,9 @@ The drm/xe driver supports some future GFX cards with rendering, display,
|
||||
compute and media. Support for currently available platforms like TGL, ADL,
|
||||
DG2, etc is provided to prototype the driver.
|
||||
|
||||
The display, or :ref:`drm-kms`, support for drm/xe is provided by
|
||||
:ref:`drm/intel-display`, and shared with :ref:`drm/i915 <drm/i915>`.
|
||||
|
||||
.. toctree::
|
||||
:titlesonly:
|
||||
|
||||
@@ -29,3 +34,4 @@ DG2, etc is provided to prototype the driver.
|
||||
xe_device
|
||||
xe-drm-usage-stats.rst
|
||||
xe_configfs
|
||||
xe_gt_stats
|
||||
|
||||
@@ -7,10 +7,10 @@ Firmware
|
||||
Firmware Layout
|
||||
===============
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_uc_fw_abi.h
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/abi/uc_fw_abi.h
|
||||
:doc: CSS-based Firmware Layout
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_uc_fw_abi.h
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/abi/uc_fw_abi.h
|
||||
:doc: GSC-based Firmware Layout
|
||||
|
||||
Write Once Protected Content Memory (WOPCM) Layout
|
||||
|
||||
11
Documentation/gpu/xe/xe_gt_stats.rst
Normal file
11
Documentation/gpu/xe/xe_gt_stats.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
.. SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
|
||||
================
|
||||
Xe GT Statistics
|
||||
================
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_gt_stats.c
|
||||
:doc: Xe GT Statistics
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_gt_stats_types.h
|
||||
:internal:
|
||||
@@ -99,7 +99,7 @@ operations:
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
attributes: &id-attrs
|
||||
- node-id
|
||||
- error-id
|
||||
reply:
|
||||
@@ -113,3 +113,14 @@ operations:
|
||||
- node-id
|
||||
reply:
|
||||
attributes: *errorinfo
|
||||
-
|
||||
name: clear-error-counter
|
||||
doc: >-
|
||||
Clear error counter for a given node.
|
||||
The request includes the error-id and node-id of the
|
||||
counter to be cleared.
|
||||
attribute-set: error-counter-attrs
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes: *id-attrs
|
||||
|
||||
15
MAINTAINERS
15
MAINTAINERS
@@ -7852,11 +7852,13 @@ F: drivers/soc/ti/smartreflex.c
|
||||
F: include/linux/power/smartreflex.h
|
||||
|
||||
DRM ACCEL DRIVERS FOR INTEL VPU
|
||||
M: Maciej Falkowski <maciej.falkowski@linux.intel.com>
|
||||
M: Karol Wachowski <karol.wachowski@linux.intel.com>
|
||||
M: Andrzej Kacprowski <andrzej.kacprowski@linux.intel.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Supported
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
F: Documentation/ABI/obsolete/sysfs-driver-ivpu
|
||||
F: Documentation/ABI/testing/sysfs-driver-ivpu
|
||||
F: drivers/accel/ivpu/
|
||||
F: include/uapi/drm/ivpu_accel.h
|
||||
|
||||
@@ -8165,6 +8167,12 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
F: Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml
|
||||
F: drivers/gpu/drm/panel/panel-novatek-nt35510.c
|
||||
|
||||
DRM DRIVER FOR NOVATEK NT35532 PANELS
|
||||
M: Cristian Cozzolino <cristian_ci@protonmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/panel/novatek,nt35532.yaml
|
||||
F: drivers/gpu/drm/panel/panel-novatek-nt35532.c
|
||||
|
||||
DRM DRIVER FOR NOVATEK NT35560 PANELS
|
||||
M: Linus Walleij <linusw@kernel.org>
|
||||
S: Maintained
|
||||
@@ -8573,6 +8581,7 @@ M: Robert Foss <rfoss@kernel.org>
|
||||
R: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
|
||||
R: Jonas Karlman <jonas@kwiboo.se>
|
||||
R: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
R: Luca Ceresoli <luca.ceresoli@bootlin.com>
|
||||
S: Maintained
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
F: Documentation/devicetree/bindings/display/bridge/
|
||||
@@ -8896,6 +8905,8 @@ S: Supported
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
F: drivers/gpu/drm/drm_gpuvm.c
|
||||
F: include/drm/drm_gpuvm.h
|
||||
F: rust/helpers/drm_gpuvm.c
|
||||
F: rust/kernel/drm/gpuvm/
|
||||
|
||||
DRM LOG
|
||||
M: Jocelyn Falempe <jfalempe@redhat.com>
|
||||
@@ -15032,7 +15043,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git
|
||||
F: drivers/hid/hid-lg-g15.c
|
||||
|
||||
LONTIUM LT8912B MIPI TO HDMI BRIDGE
|
||||
M: Adrien Grassein <adrien.grassein@gmail.com>
|
||||
M: Francesco Dolcini <francesco@dolcini.it>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml
|
||||
F: drivers/gpu/drm/bridge/lontium-lt8912b.c
|
||||
|
||||
@@ -1414,6 +1414,9 @@ CONFIG_RZ_DMAC=y
|
||||
CONFIG_TI_K3_UDMA=y
|
||||
CONFIG_TI_K3_UDMA_GLUE_LAYER=y
|
||||
CONFIG_STM32_DMA3=m
|
||||
CONFIG_DMABUF_HEAPS=y
|
||||
CONFIG_DMABUF_HEAPS_SYSTEM=m
|
||||
CONFIG_DMABUF_HEAPS_CMA=m
|
||||
CONFIG_VFIO=y
|
||||
CONFIG_VFIO_PCI=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
amdxdna-y := \
|
||||
aie.o \
|
||||
aie_psp.o \
|
||||
aie_smu.o \
|
||||
aie2_ctx.o \
|
||||
aie2_error.o \
|
||||
aie2_message.o \
|
||||
aie2_pci.o \
|
||||
aie2_pm.o \
|
||||
aie2_psp.o \
|
||||
aie2_smu.o \
|
||||
aie2_solver.o \
|
||||
aie4_ctx.o \
|
||||
aie4_message.o \
|
||||
aie4_pci.o \
|
||||
amdxdna_cbuf.o \
|
||||
amdxdna_ctx.o \
|
||||
amdxdna_gem.o \
|
||||
amdxdna_iommu.o \
|
||||
@@ -19,7 +24,11 @@ amdxdna-y := \
|
||||
amdxdna_sysfs.o \
|
||||
amdxdna_ubuf.o \
|
||||
npu1_regs.o \
|
||||
npu3_regs.o \
|
||||
npu4_regs.o \
|
||||
npu5_regs.o \
|
||||
npu6_regs.o
|
||||
|
||||
amdxdna-$(CONFIG_PCI_IOV) += aie4_sriov.o
|
||||
amdxdna-$(CONFIG_DEBUG_FS) += amdxdna_debugfs.o
|
||||
obj-$(CONFIG_DRM_ACCEL_AMDXDNA) = amdxdna.o
|
||||
|
||||
167
drivers/accel/amdxdna/aie.c
Normal file
167
drivers/accel/amdxdna/aie.c
Normal file
@@ -0,0 +1,167 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "amdxdna_mailbox_helper.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
void aie_dump_mgmt_chann_debug(struct aie_device *aie)
|
||||
{
|
||||
struct amdxdna_dev *xdna = aie->xdna;
|
||||
|
||||
XDNA_DBG(xdna, "i2x tail 0x%x", aie->mgmt_i2x.mb_tail_ptr_reg);
|
||||
XDNA_DBG(xdna, "i2x head 0x%x", aie->mgmt_i2x.mb_head_ptr_reg);
|
||||
XDNA_DBG(xdna, "i2x ringbuf 0x%x", aie->mgmt_i2x.rb_start_addr);
|
||||
XDNA_DBG(xdna, "i2x rsize 0x%x", aie->mgmt_i2x.rb_size);
|
||||
XDNA_DBG(xdna, "x2i tail 0x%x", aie->mgmt_x2i.mb_tail_ptr_reg);
|
||||
XDNA_DBG(xdna, "x2i head 0x%x", aie->mgmt_x2i.mb_head_ptr_reg);
|
||||
XDNA_DBG(xdna, "x2i ringbuf 0x%x", aie->mgmt_x2i.rb_start_addr);
|
||||
XDNA_DBG(xdna, "x2i rsize 0x%x", aie->mgmt_x2i.rb_size);
|
||||
XDNA_DBG(xdna, "x2i chann index 0x%x", aie->mgmt_chan_idx);
|
||||
XDNA_DBG(xdna, "mailbox protocol major 0x%x", aie->mgmt_prot_major);
|
||||
XDNA_DBG(xdna, "mailbox protocol minor 0x%x", aie->mgmt_prot_minor);
|
||||
}
|
||||
|
||||
void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann)
|
||||
{
|
||||
struct amdxdna_dev *xdna = aie->xdna;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
if (!*chann)
|
||||
return;
|
||||
|
||||
xdna_mailbox_stop_channel(*chann);
|
||||
xdna_mailbox_free_channel(*chann);
|
||||
*chann = NULL;
|
||||
}
|
||||
|
||||
int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg)
|
||||
{
|
||||
struct amdxdna_dev *xdna = aie->xdna;
|
||||
struct xdna_notify *hdl = msg->handle;
|
||||
int ret;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
if (!aie->mgmt_chann)
|
||||
return -ENODEV;
|
||||
|
||||
ret = xdna_send_msg_wait(xdna, aie->mgmt_chann, msg);
|
||||
if (ret == -ETIME)
|
||||
aie_destroy_chann(aie, &aie->mgmt_chann);
|
||||
|
||||
if (!ret && *hdl->status) {
|
||||
XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x",
|
||||
msg->opcode, *hdl->data);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor)
|
||||
{
|
||||
const struct amdxdna_fw_feature_tbl *feature;
|
||||
bool found = false;
|
||||
|
||||
for (feature = aie->xdna->dev_info->fw_feature_tbl;
|
||||
feature->major; feature++) {
|
||||
if (feature->major != fw_major)
|
||||
continue;
|
||||
if (fw_minor < feature->min_minor)
|
||||
continue;
|
||||
if (feature->max_minor > 0 && fw_minor > feature->max_minor)
|
||||
continue;
|
||||
|
||||
aie->feature_mask |= feature->features;
|
||||
|
||||
/* firmware version matches one of the driver support entry */
|
||||
found = true;
|
||||
}
|
||||
|
||||
return found ? 0 : -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void amdxdna_update_vbnv(struct amdxdna_dev *xdna,
|
||||
const struct amdxdna_rev_vbnv *tbl,
|
||||
u32 rev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; tbl[i].vbnv; i++) {
|
||||
if (tbl[i].revision == rev) {
|
||||
xdna->vbnv = tbl[i].vbnv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void amdxdna_vbnv_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
const struct amdxdna_dev_info *info = xdna->dev_info;
|
||||
u32 rev;
|
||||
|
||||
xdna->vbnv = info->default_vbnv;
|
||||
|
||||
if (!info->ops->get_dev_revision || !info->rev_vbnv_tbl)
|
||||
return;
|
||||
|
||||
if (info->ops->get_dev_revision(xdna, &rev))
|
||||
return;
|
||||
|
||||
amdxdna_update_vbnv(xdna, info->rev_vbnv_tbl, rev);
|
||||
}
|
||||
|
||||
int amdxdna_get_metadata(struct aie_device *aie,
|
||||
struct amdxdna_client *client,
|
||||
struct amdxdna_drm_get_info *args)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 buf_sz;
|
||||
|
||||
buf_sz = min(args->buffer_size, sizeof(aie->metadata));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &aie->metadata, buf_sz))
|
||||
ret = -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *amdxdna_alloc_msg_buffer(struct amdxdna_dev *xdna, u32 *size,
|
||||
dma_addr_t *dma_addr)
|
||||
{
|
||||
void *vaddr;
|
||||
int order;
|
||||
|
||||
*size = max_t(u32, *size, SZ_8K);
|
||||
order = get_order(*size);
|
||||
if (order > MAX_PAGE_ORDER)
|
||||
return ERR_PTR(-EINVAL);
|
||||
*size = PAGE_SIZE << order;
|
||||
|
||||
if (amdxdna_iova_on(xdna))
|
||||
return amdxdna_iommu_alloc(xdna, *size, dma_addr);
|
||||
|
||||
vaddr = dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr,
|
||||
DMA_FROM_DEVICE, GFP_KERNEL);
|
||||
if (!vaddr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
void amdxdna_free_msg_buffer(struct amdxdna_dev *xdna, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_addr)
|
||||
{
|
||||
if (amdxdna_iova_on(xdna)) {
|
||||
amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_free_noncoherent(xdna->ddev.dev, size, cpu_addr, dma_addr, DMA_FROM_DEVICE);
|
||||
}
|
||||
120
drivers/accel/amdxdna/aie.h
Normal file
120
drivers/accel/amdxdna/aie.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
#ifndef _AIE_H_
|
||||
#define _AIE_H_
|
||||
|
||||
#include <drm/amdxdna_accel.h>
|
||||
#include "amdxdna_pci_drv.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
|
||||
#define AIE_INTERVAL 20000 /* us */
|
||||
#define AIE_TIMEOUT 1000000 /* us */
|
||||
|
||||
struct psp_device;
|
||||
struct smu_device;
|
||||
|
||||
struct aie_device {
|
||||
struct amdxdna_dev *xdna;
|
||||
struct mailbox_channel *mgmt_chann;
|
||||
struct xdna_mailbox_chann_res mgmt_x2i;
|
||||
struct xdna_mailbox_chann_res mgmt_i2x;
|
||||
u32 mgmt_chan_idx;
|
||||
u32 mgmt_prot_major;
|
||||
u32 mgmt_prot_minor;
|
||||
unsigned long feature_mask;
|
||||
|
||||
struct psp_device *psp_hdl;
|
||||
struct smu_device *smu_hdl;
|
||||
|
||||
struct amdxdna_drm_query_aie_metadata metadata;
|
||||
};
|
||||
|
||||
#define DECLARE_AIE_MSG(name, op) \
|
||||
DECLARE_XDNA_MSG_COMMON(name, op, -1)
|
||||
#define AIE_FEATURE_ON(aie, feature) test_bit(feature, &(aie)->feature_mask)
|
||||
|
||||
#define PSP_REG_BAR(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].bar_idx)
|
||||
#define PSP_REG_OFF(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].offset)
|
||||
|
||||
#define SMU_REG_BAR(ndev, idx) ((ndev)->priv->smu_regs_off[(idx)].bar_idx)
|
||||
#define SMU_REG_OFF(ndev, idx) ((ndev)->priv->smu_regs_off[(idx)].offset)
|
||||
|
||||
#define DEFINE_BAR_OFFSET(reg_name, bar, reg_addr) \
|
||||
[reg_name] = {bar##_BAR_INDEX, (reg_addr) - bar##_BAR_BASE}
|
||||
|
||||
enum smu_reg_idx {
|
||||
SMU_CMD_REG = 0,
|
||||
SMU_ARG_REG,
|
||||
SMU_INTR_REG,
|
||||
SMU_RESP_REG,
|
||||
SMU_OUT_REG,
|
||||
SMU_MAX_REGS /* Keep this at the end */
|
||||
};
|
||||
|
||||
enum psp_reg_idx {
|
||||
PSP_CMD_REG = 0,
|
||||
PSP_ARG0_REG,
|
||||
PSP_ARG1_REG,
|
||||
PSP_ARG2_REG,
|
||||
PSP_NUM_IN_REGS, /* number of input registers */
|
||||
PSP_INTR_REG = PSP_NUM_IN_REGS,
|
||||
PSP_STATUS_REG,
|
||||
PSP_RESP_REG,
|
||||
PSP_PWAITMODE_REG,
|
||||
PSP_MAX_REGS /* Keep this at the end */
|
||||
};
|
||||
|
||||
struct aie_bar_off_pair {
|
||||
int bar_idx;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
struct smu_config {
|
||||
void __iomem *smu_regs[SMU_MAX_REGS];
|
||||
};
|
||||
|
||||
struct psp_config {
|
||||
const void *fw_buf;
|
||||
u32 fw_size;
|
||||
const void *certfw_buf;
|
||||
u32 certfw_size;
|
||||
void __iomem *psp_regs[PSP_MAX_REGS];
|
||||
u32 arg2_mask;
|
||||
u32 notify_val;
|
||||
};
|
||||
|
||||
/* Device revision to VBNV string mapping table entry */
|
||||
struct amdxdna_rev_vbnv {
|
||||
u32 revision;
|
||||
const char *vbnv;
|
||||
};
|
||||
|
||||
/* aie.c */
|
||||
void aie_dump_mgmt_chann_debug(struct aie_device *aie);
|
||||
void aie_destroy_chann(struct aie_device *aie, struct mailbox_channel **chann);
|
||||
int aie_send_mgmt_msg_wait(struct aie_device *aie, struct xdna_mailbox_msg *msg);
|
||||
int aie_check_protocol(struct aie_device *aie, u32 fw_major, u32 fw_minor);
|
||||
void amdxdna_vbnv_init(struct amdxdna_dev *xdna);
|
||||
int amdxdna_get_metadata(struct aie_device *aie, struct amdxdna_client *client,
|
||||
struct amdxdna_drm_get_info *args);
|
||||
void *amdxdna_alloc_msg_buffer(struct amdxdna_dev *xdna, u32 *size,
|
||||
dma_addr_t *dma_addr);
|
||||
void amdxdna_free_msg_buffer(struct amdxdna_dev *xdna, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_addr);
|
||||
|
||||
/* aie_psp.c */
|
||||
struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf);
|
||||
int aie_psp_start(struct psp_device *psp);
|
||||
void aie_psp_stop(struct psp_device *psp);
|
||||
int aie_psp_waitmode_poll(struct psp_device *psp);
|
||||
|
||||
/* aie_smu.c */
|
||||
struct smu_device *aiem_smu_create(struct drm_device *ddev, struct smu_config *conf);
|
||||
int aie_smu_init(struct smu_device *smu);
|
||||
void aie_smu_fini(struct smu_device *smu);
|
||||
int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk);
|
||||
int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level);
|
||||
|
||||
#endif /* _AIE_H_ */
|
||||
@@ -27,7 +27,9 @@ static bool force_cmdlist = true;
|
||||
module_param(force_cmdlist, bool, 0600);
|
||||
MODULE_PARM_DESC(force_cmdlist, "Force use command list (Default true)");
|
||||
|
||||
#define HWCTX_MAX_TIMEOUT 60000 /* milliseconds */
|
||||
uint tdr_timeout_ms = 2000;
|
||||
module_param(tdr_timeout_ms, int, 0400);
|
||||
MODULE_PARM_DESC(tdr_timeout_ms, "TDR (Timeout Detection and Recovery) timeout in milliseconds (0 = disable)");
|
||||
|
||||
struct aie2_ctx_health {
|
||||
struct amdxdna_ctx_health header;
|
||||
@@ -39,11 +41,30 @@ struct aie2_ctx_health {
|
||||
u32 fatal_error_app_module;
|
||||
};
|
||||
|
||||
static inline void aie2_tdr_signal(struct amdxdna_dev *xdna)
|
||||
{
|
||||
WRITE_ONCE(xdna->dev_handle->tdr_status, AIE2_TDR_SIGNALED);
|
||||
}
|
||||
|
||||
static bool aie2_tdr_detect(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
|
||||
if (READ_ONCE(ndev->tdr_status) == AIE2_TDR_WAIT) {
|
||||
XDNA_ERR(xdna, "TDR timeout detected");
|
||||
return true;
|
||||
}
|
||||
|
||||
WRITE_ONCE(ndev->tdr_status, AIE2_TDR_WAIT);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void aie2_job_release(struct kref *ref)
|
||||
{
|
||||
struct amdxdna_sched_job *job;
|
||||
|
||||
job = container_of(ref, struct amdxdna_sched_job, refcnt);
|
||||
|
||||
amdxdna_sched_job_cleanup(job);
|
||||
atomic64_inc(&job->hwctx->job_free_cnt);
|
||||
wake_up(&job->hwctx->priv->job_free_wq);
|
||||
@@ -70,6 +91,7 @@ static void aie2_hwctx_stop(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwct
|
||||
static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_gem_obj *heap = hwctx->priv->heap;
|
||||
unsigned long heap_id;
|
||||
int ret;
|
||||
|
||||
ret = aie2_create_context(xdna->dev_handle, hwctx);
|
||||
@@ -86,6 +108,17 @@ static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hw
|
||||
goto out;
|
||||
}
|
||||
|
||||
xa_for_each_range(&hwctx->client->dev_heap_xa, heap_id, heap, 1,
|
||||
hwctx->last_attached_heap) {
|
||||
ret = aie2_add_host_buf(xdna->dev_handle, hwctx->fw_ctx_id,
|
||||
amdxdna_obj_dma_addr(heap),
|
||||
heap->mem.size);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Add heap %ld failed ret %d", heap_id, ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = aie2_config_cu(hwctx, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Config cu failed, ret %d", ret);
|
||||
@@ -175,8 +208,10 @@ aie2_sched_notify(struct amdxdna_sched_job *job)
|
||||
{
|
||||
struct dma_fence *fence = job->fence;
|
||||
|
||||
trace_xdna_job(&job->base, job->hwctx->name, "signaled fence", job->seq);
|
||||
trace_xdna_job(&job->base, job->hwctx->name, "signaling fence",
|
||||
job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO);
|
||||
|
||||
aie2_tdr_signal(job->hwctx->client->xdna);
|
||||
job->hwctx->priv->completed++;
|
||||
dma_fence_signal(fence);
|
||||
|
||||
@@ -270,17 +305,13 @@ aie2_sched_drvcmd_resp_handler(void *handle, void __iomem *data, size_t size)
|
||||
struct amdxdna_sched_job *job = handle;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!data))
|
||||
goto out;
|
||||
|
||||
if (unlikely(size != sizeof(u32))) {
|
||||
if (unlikely(!data || size != sizeof(u32))) {
|
||||
job->drv_cmd->result = U32_MAX;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
} else {
|
||||
job->drv_cmd->result = readl(data);
|
||||
}
|
||||
|
||||
job->drv_cmd->result = readl(data);
|
||||
|
||||
out:
|
||||
aie2_sched_notify(job);
|
||||
return ret;
|
||||
}
|
||||
@@ -345,6 +376,9 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
||||
struct dma_fence *fence;
|
||||
int ret;
|
||||
|
||||
trace_xdna_job(sched_job, hwctx->name, "job run",
|
||||
job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO);
|
||||
|
||||
if (!hwctx->priv->mbox_chann)
|
||||
return NULL;
|
||||
|
||||
@@ -360,6 +394,7 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
||||
ret = aie2_sync_bo(hwctx, job, aie2_sched_drvcmd_resp_handler);
|
||||
break;
|
||||
case ATTACH_DEBUG_BO:
|
||||
case DETACH_DEBUG_BO:
|
||||
ret = aie2_config_debug_bo(hwctx, job, aie2_sched_drvcmd_resp_handler);
|
||||
break;
|
||||
default:
|
||||
@@ -384,8 +419,11 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
||||
aie2_job_put(job);
|
||||
mmput(job->mm);
|
||||
fence = ERR_PTR(ret);
|
||||
} else {
|
||||
aie2_tdr_signal(hwctx->client->xdna);
|
||||
}
|
||||
trace_xdna_job(sched_job, hwctx->name, "sent to device", job->seq);
|
||||
trace_xdna_job(sched_job, hwctx->name, "sent to device",
|
||||
job->seq, job->drv_cmd ? job->drv_cmd->opcode : DEFAULT_IO);
|
||||
|
||||
return fence;
|
||||
}
|
||||
@@ -395,7 +433,9 @@ static void aie2_sched_job_free(struct drm_sched_job *sched_job)
|
||||
struct amdxdna_sched_job *job = drm_job_to_xdna_job(sched_job);
|
||||
struct amdxdna_hwctx *hwctx = job->hwctx;
|
||||
|
||||
trace_xdna_job(sched_job, hwctx->name, "job free", job->seq);
|
||||
/* job->drv_cmd could be freed, so use DEFAULT_IO */
|
||||
trace_xdna_job(sched_job, hwctx->name, "job free",
|
||||
job->seq, DEFAULT_IO);
|
||||
if (!job->job_done)
|
||||
up(&hwctx->priv->job_sem);
|
||||
|
||||
@@ -413,10 +453,12 @@ aie2_sched_job_timedout(struct drm_sched_job *sched_job)
|
||||
int ret;
|
||||
|
||||
xdna = hwctx->client->xdna;
|
||||
trace_xdna_job(sched_job, hwctx->name, "job timedout", job->seq);
|
||||
job->job_timeout = true;
|
||||
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
guard(mutex)(&xdna->dev_lock);
|
||||
|
||||
if (!aie2_tdr_detect(xdna))
|
||||
return DRM_GPU_SCHED_STAT_NO_HANG;
|
||||
|
||||
report = kzalloc_obj(*report);
|
||||
if (!report)
|
||||
goto reset_hwctx;
|
||||
@@ -428,10 +470,10 @@ aie2_sched_job_timedout(struct drm_sched_job *sched_job)
|
||||
job->aie2_job_health = report;
|
||||
|
||||
reset_hwctx:
|
||||
job->job_timeout = true;
|
||||
aie2_hwctx_stop(xdna, hwctx, sched_job);
|
||||
|
||||
aie2_hwctx_restart(xdna, hwctx);
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
|
||||
return DRM_GPU_SCHED_STAT_RESET;
|
||||
}
|
||||
@@ -456,12 +498,12 @@ static int aie2_hwctx_col_list(struct amdxdna_hwctx *hwctx)
|
||||
}
|
||||
|
||||
ndev = xdna->dev_handle;
|
||||
if (unlikely(!ndev->metadata.core.row_count)) {
|
||||
if (unlikely(!ndev->aie.metadata.core.row_count)) {
|
||||
XDNA_WARN(xdna, "Core tile row count is zero");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hwctx->num_col = hwctx->num_tiles / ndev->metadata.core.row_count;
|
||||
hwctx->num_col = hwctx->num_tiles / ndev->aie.metadata.core.row_count;
|
||||
if (!hwctx->num_col || hwctx->num_col > ndev->total_col) {
|
||||
XDNA_ERR(xdna, "Invalid num_col %d", hwctx->num_col);
|
||||
return -EINVAL;
|
||||
@@ -513,22 +555,24 @@ static int aie2_alloc_resource(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_dev *xdna = hwctx->client->xdna;
|
||||
struct alloc_requests *xrs_req;
|
||||
u32 temporal_only_col = 0;
|
||||
int ret;
|
||||
|
||||
if (AIE2_FEATURE_ON(xdna->dev_handle, AIE2_TEMPORAL_ONLY)) {
|
||||
hwctx->num_unused_col = xdna->dev_handle->total_col - hwctx->num_col;
|
||||
hwctx->num_col = xdna->dev_handle->total_col;
|
||||
return aie2_create_context(xdna->dev_handle, hwctx);
|
||||
}
|
||||
|
||||
xrs_req = kzalloc_obj(*xrs_req);
|
||||
if (!xrs_req)
|
||||
return -ENOMEM;
|
||||
|
||||
xrs_req->cdo.start_cols = hwctx->col_list;
|
||||
xrs_req->cdo.cols_len = hwctx->col_list_len;
|
||||
xrs_req->cdo.ncols = hwctx->num_col;
|
||||
xrs_req->cdo.qos_cap.opc = hwctx->max_opc;
|
||||
if (AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_TEMPORAL_ONLY)) {
|
||||
xrs_req->cdo.start_cols = &temporal_only_col;
|
||||
xrs_req->cdo.cols_len = 1;
|
||||
xrs_req->cdo.ncols = xdna->dev_handle->total_col;
|
||||
} else {
|
||||
xrs_req->cdo.start_cols = hwctx->col_list;
|
||||
xrs_req->cdo.cols_len = hwctx->col_list_len;
|
||||
xrs_req->cdo.ncols = hwctx->num_col;
|
||||
}
|
||||
/* Use platform opc */
|
||||
xrs_req->cdo.qos_cap.opc = xdna->dev_handle->priv->col_opc * hwctx->num_col;
|
||||
|
||||
xrs_req->rqos.gops = hwctx->qos.gops;
|
||||
xrs_req->rqos.fps = hwctx->qos.fps;
|
||||
@@ -552,15 +596,9 @@ static void aie2_release_resource(struct amdxdna_hwctx *hwctx)
|
||||
struct amdxdna_dev *xdna = hwctx->client->xdna;
|
||||
int ret;
|
||||
|
||||
if (AIE2_FEATURE_ON(xdna->dev_handle, AIE2_TEMPORAL_ONLY)) {
|
||||
ret = aie2_destroy_context(xdna->dev_handle, hwctx);
|
||||
if (ret && ret != -ENODEV)
|
||||
XDNA_ERR(xdna, "Destroy temporal only context failed, ret %d", ret);
|
||||
} else {
|
||||
ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret);
|
||||
}
|
||||
ret = xrs_release_resource(xdna->xrs_hdl, (uintptr_t)hwctx);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "Release AIE resource failed, ret %d", ret);
|
||||
}
|
||||
|
||||
static int aie2_ctx_syncobj_create(struct amdxdna_hwctx *hwctx)
|
||||
@@ -605,9 +643,8 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
const struct drm_sched_init_args args = {
|
||||
.ops = &sched_ops,
|
||||
.num_rqs = DRM_SCHED_PRIORITY_COUNT,
|
||||
.credit_limit = HWCTX_MAX_CMDS,
|
||||
.timeout = msecs_to_jiffies(HWCTX_MAX_TIMEOUT),
|
||||
.timeout = msecs_to_jiffies(tdr_timeout_ms),
|
||||
.name = "amdxdna_js",
|
||||
.dev = xdna->ddev.dev,
|
||||
};
|
||||
@@ -622,7 +659,7 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
||||
hwctx->priv = priv;
|
||||
|
||||
mutex_lock(&client->mm_lock);
|
||||
heap = client->dev_heap;
|
||||
heap = xa_load(&client->dev_heap_xa, 0);
|
||||
if (!heap) {
|
||||
XDNA_ERR(xdna, "The client dev heap object not exist");
|
||||
mutex_unlock(&client->mm_lock);
|
||||
@@ -704,6 +741,12 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
|
||||
goto release_resource;
|
||||
}
|
||||
|
||||
ret = amdxdna_update_heap(client, hwctx);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Update heap failed, ret %d", ret);
|
||||
goto release_resource;
|
||||
}
|
||||
|
||||
ret = aie2_ctx_syncobj_create(hwctx);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Create syncobj failed, ret %d", ret);
|
||||
@@ -893,6 +936,7 @@ static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl,
|
||||
aie2_cmd_wait(hwctx, seq);
|
||||
if (cmd.result) {
|
||||
XDNA_ERR(xdna, "Response failure 0x%x", cmd.result);
|
||||
ret = -EINVAL;
|
||||
goto put_obj;
|
||||
}
|
||||
|
||||
@@ -1136,3 +1180,28 @@ void aie2_hmm_invalidate(struct amdxdna_gem_obj *abo,
|
||||
else if (ret == -ERESTARTSYS)
|
||||
XDNA_DBG(xdna, "Wait for bo interrupted by signal");
|
||||
}
|
||||
|
||||
int aie2_hwctx_heap_expand(struct amdxdna_hwctx *hwctx,
|
||||
struct amdxdna_gem_obj *heap)
|
||||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
u64 addr;
|
||||
int ret;
|
||||
|
||||
ret = amdxdna_pm_resume_get_locked(xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
addr = amdxdna_obj_dma_addr(heap);
|
||||
ret = aie2_add_host_buf(xdna->dev_handle, hwctx->fw_ctx_id,
|
||||
addr, heap->mem.size);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Add heap failed hwctx %s 0x%lx ret %d",
|
||||
hwctx->name, heap->mem.size, ret);
|
||||
}
|
||||
|
||||
amdxdna_pm_suspend_put(xdna);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "aie2_msg_priv.h"
|
||||
#include "aie2_pci.h"
|
||||
#include "amdxdna_error.h"
|
||||
@@ -249,12 +250,12 @@ static u32 aie2_error_backtrack(struct amdxdna_dev_hdl *ndev, void *err_info, u3
|
||||
enum aie_error_category cat;
|
||||
|
||||
cat = aie_get_error_category(err->row, err->event_id, err->mod_type);
|
||||
XDNA_ERR(ndev->xdna, "Row: %d, Col: %d, module %d, event ID %d, category %d",
|
||||
XDNA_ERR(ndev->aie.xdna, "Row: %d, Col: %d, module %d, event ID %d, category %d",
|
||||
err->row, err->col, err->mod_type,
|
||||
err->event_id, cat);
|
||||
|
||||
if (err->col >= 32) {
|
||||
XDNA_WARN(ndev->xdna, "Invalid column number");
|
||||
XDNA_WARN(ndev->aie.xdna, "Invalid column number");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -294,7 +295,7 @@ static void aie2_error_worker(struct work_struct *err_work)
|
||||
|
||||
e = container_of(err_work, struct async_event, work);
|
||||
|
||||
xdna = e->ndev->xdna;
|
||||
xdna = e->ndev->aie.xdna;
|
||||
|
||||
if (e->resp.status == MAX_AIE2_STATUS_CODE)
|
||||
return;
|
||||
@@ -329,7 +330,7 @@ static void aie2_error_worker(struct work_struct *err_work)
|
||||
|
||||
void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct async_events *events;
|
||||
|
||||
events = ndev->async_events;
|
||||
@@ -338,13 +339,13 @@ void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev)
|
||||
destroy_workqueue(events->wq);
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
|
||||
aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr);
|
||||
amdxdna_free_msg_buffer(xdna, events->size, events->buf, events->addr);
|
||||
kfree(events);
|
||||
}
|
||||
|
||||
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
u32 total_col = ndev->total_col;
|
||||
u32 total_size = ASYNC_BUF_SIZE * total_col;
|
||||
struct async_events *events;
|
||||
@@ -354,7 +355,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
|
||||
if (!events)
|
||||
return -ENOMEM;
|
||||
|
||||
events->buf = aie2_alloc_msg_buffer(ndev, &total_size, &events->addr);
|
||||
events->buf = amdxdna_alloc_msg_buffer(xdna, &total_size, &events->addr);
|
||||
if (IS_ERR(events->buf)) {
|
||||
ret = PTR_ERR(events->buf);
|
||||
goto free_events;
|
||||
@@ -394,7 +395,7 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
|
||||
free_wq:
|
||||
destroy_workqueue(events->wq);
|
||||
free_buf:
|
||||
aie2_free_msg_buffer(ndev, events->size, events->buf, events->addr);
|
||||
amdxdna_free_msg_buffer(xdna, events->size, events->buf, events->addr);
|
||||
free_events:
|
||||
kfree(events);
|
||||
return ret;
|
||||
@@ -402,12 +403,15 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
|
||||
|
||||
int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev, struct amdxdna_drm_get_array *args)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
if (!args->num_element)
|
||||
return -EINVAL;
|
||||
|
||||
args->num_element = 1;
|
||||
args->element_size = sizeof(ndev->last_async_err);
|
||||
args->element_size = min(args->element_size, sizeof(ndev->last_async_err));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer),
|
||||
&ndev->last_async_err, args->element_size))
|
||||
return -EFAULT;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "aie2_msg_priv.h"
|
||||
#include "aie2_pci.h"
|
||||
#include "amdxdna_ctx.h"
|
||||
@@ -24,103 +25,40 @@
|
||||
#include "amdxdna_mailbox_helper.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
#define DECLARE_AIE2_MSG(name, op) \
|
||||
DECLARE_XDNA_MSG_COMMON(name, op, MAX_AIE2_STATUS_CODE)
|
||||
|
||||
#define EXEC_MSG_OPS(xdna) ((xdna)->dev_handle->exec_msg_ops)
|
||||
|
||||
static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev,
|
||||
struct xdna_mailbox_msg *msg)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
struct xdna_notify *hdl = msg->handle;
|
||||
int ret;
|
||||
|
||||
if (!ndev->mgmt_chann)
|
||||
return -ENODEV;
|
||||
|
||||
ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg);
|
||||
if (ret == -ETIME)
|
||||
aie2_destroy_mgmt_chann(ndev);
|
||||
|
||||
if (!ret && *hdl->status != AIE2_STATUS_SUCCESS) {
|
||||
XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x",
|
||||
msg->opcode, *hdl->data);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size,
|
||||
dma_addr_t *dma_addr)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
void *vaddr;
|
||||
int order;
|
||||
|
||||
*size = max(*size, SZ_8K);
|
||||
order = get_order(*size);
|
||||
if (order > MAX_PAGE_ORDER)
|
||||
return ERR_PTR(-EINVAL);
|
||||
*size = PAGE_SIZE << order;
|
||||
|
||||
if (amdxdna_iova_on(xdna))
|
||||
return amdxdna_iommu_alloc(xdna, *size, dma_addr);
|
||||
|
||||
vaddr = dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr,
|
||||
DMA_FROM_DEVICE, GFP_KERNEL);
|
||||
if (!vaddr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
return vaddr;
|
||||
}
|
||||
|
||||
void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_addr)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
|
||||
if (amdxdna_iova_on(xdna)) {
|
||||
amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_free_noncoherent(xdna->ddev.dev, size, cpu_addr, dma_addr, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND);
|
||||
DECLARE_AIE_MSG(suspend, MSG_OP_SUSPEND);
|
||||
int ret;
|
||||
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Failed to suspend fw, ret %d", ret);
|
||||
XDNA_ERR(ndev->aie.xdna, "Failed to suspend fw, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return aie2_psp_waitmode_poll(ndev->psp_hdl);
|
||||
return aie_psp_waitmode_poll(ndev->aie.psp_hdl);
|
||||
}
|
||||
|
||||
int aie2_resume_fw(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
DECLARE_AIE2_MSG(suspend, MSG_OP_RESUME);
|
||||
DECLARE_AIE_MSG(suspend, MSG_OP_RESUME);
|
||||
|
||||
return aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
return aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
}
|
||||
|
||||
int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value)
|
||||
{
|
||||
DECLARE_AIE2_MSG(set_runtime_cfg, MSG_OP_SET_RUNTIME_CONFIG);
|
||||
DECLARE_AIE_MSG(set_runtime_cfg, MSG_OP_SET_RUNTIME_CONFIG);
|
||||
int ret;
|
||||
|
||||
req.type = type;
|
||||
req.value = value;
|
||||
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Failed to set runtime config, ret %d", ret);
|
||||
XDNA_ERR(ndev->aie.xdna, "Failed to set runtime config, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -129,13 +67,13 @@ int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value)
|
||||
|
||||
int aie2_get_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 *value)
|
||||
{
|
||||
DECLARE_AIE2_MSG(get_runtime_cfg, MSG_OP_GET_RUNTIME_CONFIG);
|
||||
DECLARE_AIE_MSG(get_runtime_cfg, MSG_OP_GET_RUNTIME_CONFIG);
|
||||
int ret;
|
||||
|
||||
req.type = type;
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Failed to get runtime config, ret %d", ret);
|
||||
XDNA_ERR(ndev->aie.xdna, "Failed to get runtime config, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -145,20 +83,21 @@ int aie2_get_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 *value)
|
||||
|
||||
int aie2_assign_mgmt_pasid(struct amdxdna_dev_hdl *ndev, u16 pasid)
|
||||
{
|
||||
DECLARE_AIE2_MSG(assign_mgmt_pasid, MSG_OP_ASSIGN_MGMT_PASID);
|
||||
DECLARE_AIE_MSG(assign_mgmt_pasid, MSG_OP_ASSIGN_MGMT_PASID);
|
||||
|
||||
req.pasid = pasid;
|
||||
|
||||
return aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
return aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
}
|
||||
|
||||
int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *version)
|
||||
int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_drm_query_aie_version *version)
|
||||
{
|
||||
DECLARE_AIE2_MSG(aie_version_info, MSG_OP_QUERY_AIE_VERSION);
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
DECLARE_AIE_MSG(aie_version_info, MSG_OP_QUERY_AIE_VERSION);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -171,16 +110,17 @@ int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *ver
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata)
|
||||
int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_drm_query_aie_metadata *metadata)
|
||||
{
|
||||
DECLARE_AIE2_MSG(aie_tile_info, MSG_OP_QUERY_AIE_TILE_INFO);
|
||||
DECLARE_AIE_MSG(aie_tile_info, MSG_OP_QUERY_AIE_TILE_INFO);
|
||||
int ret;
|
||||
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
metadata->size = resp.info.size;
|
||||
metadata->col_size = resp.info.size;
|
||||
metadata->cols = resp.info.cols;
|
||||
metadata->rows = resp.info.rows;
|
||||
|
||||
@@ -211,10 +151,10 @@ int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *m
|
||||
int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_fw_ver *fw_ver)
|
||||
{
|
||||
DECLARE_AIE2_MSG(firmware_version, MSG_OP_GET_FIRMWARE_VERSION);
|
||||
DECLARE_AIE_MSG(firmware_version, MSG_OP_GET_FIRMWARE_VERSION);
|
||||
int ret;
|
||||
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -228,12 +168,12 @@ int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev,
|
||||
|
||||
static int aie2_destroy_context_req(struct amdxdna_dev_hdl *ndev, u32 id)
|
||||
{
|
||||
DECLARE_AIE2_MSG(destroy_ctx, MSG_OP_DESTROY_CONTEXT);
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
DECLARE_AIE_MSG(destroy_ctx, MSG_OP_DESTROY_CONTEXT);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
req.context_id = id;
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret && ret != -ENODEV)
|
||||
XDNA_WARN(xdna, "Destroy context failed, ret %d", ret);
|
||||
else if (ret == -ENODEV)
|
||||
@@ -245,7 +185,7 @@ static int aie2_destroy_context_req(struct amdxdna_dev_hdl *ndev, u32 id)
|
||||
static u32 aie2_get_context_priority(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
if (!AIE2_FEATURE_ON(ndev, AIE2_PREEMPT))
|
||||
if (!AIE_FEATURE_ON(&ndev->aie, AIE2_PREEMPT))
|
||||
return PRIORITY_HIGH;
|
||||
|
||||
switch (hwctx->qos.priority) {
|
||||
@@ -264,8 +204,8 @@ static u32 aie2_get_context_priority(struct amdxdna_dev_hdl *ndev,
|
||||
|
||||
int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
DECLARE_AIE2_MSG(create_ctx, MSG_OP_CREATE_CONTEXT);
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
DECLARE_AIE_MSG(create_ctx, MSG_OP_CREATE_CONTEXT);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct xdna_mailbox_chann_res x2i;
|
||||
struct xdna_mailbox_chann_res i2x;
|
||||
struct cq_pair *cq_pair;
|
||||
@@ -280,7 +220,7 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
|
||||
req.pasid = amdxdna_pasid_on(hwctx->client) ? hwctx->client->pasid : 0;
|
||||
req.context_priority = aie2_get_context_priority(ndev, hwctx);
|
||||
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -344,7 +284,7 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
|
||||
|
||||
int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
if (!hwctx->priv->mbox_chann)
|
||||
@@ -361,25 +301,59 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwc
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aie2_map_host_buf(struct amdxdna_dev_hdl *ndev, u32 context_id, u64 addr, u64 size)
|
||||
static int aie2_send_host_buf_msgs(struct amdxdna_dev_hdl *ndev, u32 context_id,
|
||||
u64 addr, u64 size, u32 initial_opcode)
|
||||
{
|
||||
DECLARE_AIE2_MSG(map_host_buffer, MSG_OP_MAP_HOST_BUFFER);
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
DECLARE_AIE_MSG(map_host_buffer, MSG_OP_MAP_HOST_BUFFER);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
size_t chunk_size;
|
||||
int ret;
|
||||
|
||||
req.context_id = context_id;
|
||||
req.buf_addr = addr;
|
||||
req.buf_size = size;
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
chunk_size = xdna->dev_info->dev_mem_size;
|
||||
if (!size || !IS_ALIGNED(size, chunk_size)) {
|
||||
XDNA_ERR(xdna, "Invalid size 0x%llx for chunk 0x%lx",
|
||||
size, chunk_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
XDNA_DBG(xdna, "fw ctx %d map host buf addr 0x%llx size 0x%llx",
|
||||
context_id, addr, size);
|
||||
msg.opcode = initial_opcode;
|
||||
do {
|
||||
req.context_id = context_id;
|
||||
req.buf_addr = addr;
|
||||
req.buf_size = chunk_size;
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "fw ctx %d addr 0x%llx size 0x%lx",
|
||||
context_id, addr, chunk_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
XDNA_DBG(xdna, "fw ctx %d host buf op 0x%x addr 0x%llx size 0x%lx",
|
||||
context_id, msg.opcode, addr, chunk_size);
|
||||
|
||||
addr += chunk_size;
|
||||
size -= chunk_size;
|
||||
msg.opcode = MSG_OP_ADD_HOST_BUFFER;
|
||||
} while (size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie2_map_host_buf(struct amdxdna_dev_hdl *ndev, u32 context_id, u64 addr, u64 size)
|
||||
{
|
||||
return aie2_send_host_buf_msgs(ndev, context_id, addr, size,
|
||||
MSG_OP_MAP_HOST_BUFFER);
|
||||
}
|
||||
|
||||
int aie2_add_host_buf(struct amdxdna_dev_hdl *ndev, u32 context_id, u64 addr, u64 size)
|
||||
{
|
||||
if (!AIE_FEATURE_ON(&ndev->aie, AIE2_ADD_HOST_BUFFER))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return aie2_send_host_buf_msgs(ndev, context_id, addr, size,
|
||||
MSG_OP_ADD_HOST_BUFFER);
|
||||
}
|
||||
|
||||
static int amdxdna_hwctx_col_map(struct amdxdna_hwctx *hwctx, void *arg)
|
||||
{
|
||||
u32 *bitmap = arg;
|
||||
@@ -392,15 +366,16 @@ static int amdxdna_hwctx_col_map(struct amdxdna_hwctx *hwctx, void *arg)
|
||||
int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf,
|
||||
u32 size, u32 *cols_filled)
|
||||
{
|
||||
DECLARE_AIE2_MSG(aie_column_info, MSG_OP_QUERY_COL_STATUS);
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
u32 buf_sz = size, aie_bitmap = 0;
|
||||
DECLARE_AIE_MSG(aie_column_info, MSG_OP_QUERY_COL_STATUS);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
u32 buf_sz, aie_bitmap = 0;
|
||||
struct amdxdna_client *client;
|
||||
dma_addr_t dma_addr;
|
||||
u8 *buff_addr;
|
||||
int ret;
|
||||
|
||||
buff_addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr);
|
||||
buf_sz = ndev->aie.metadata.cols * ndev->aie.metadata.col_size;
|
||||
buff_addr = amdxdna_alloc_msg_buffer(xdna, &buf_sz, &dma_addr);
|
||||
if (IS_ERR(buff_addr))
|
||||
return PTR_ERR(buff_addr);
|
||||
|
||||
@@ -414,8 +389,8 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf,
|
||||
req.num_cols = hweight32(aie_bitmap);
|
||||
req.aie_bitmap = aie_bitmap;
|
||||
|
||||
drm_clflush_virt_range(buff_addr, size); /* device can access */
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
drm_clflush_virt_range(buff_addr, req.dump_buff_size); /* device can access */
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Error during NPU query, status %d", ret);
|
||||
goto fail;
|
||||
@@ -423,13 +398,14 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf,
|
||||
|
||||
XDNA_DBG(xdna, "Query NPU status completed");
|
||||
|
||||
if (size < resp.size) {
|
||||
if (buf_sz < resp.size) {
|
||||
ret = -EINVAL;
|
||||
XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", size, resp.size);
|
||||
XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", buf_sz, resp.size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (copy_to_user(buf, buff_addr, resp.size)) {
|
||||
size = min(size, resp.size);
|
||||
if (copy_to_user(buf, buff_addr, size)) {
|
||||
ret = -EFAULT;
|
||||
XDNA_ERR(xdna, "Failed to copy NPU status to user space");
|
||||
goto fail;
|
||||
@@ -438,7 +414,7 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf,
|
||||
*cols_filled = aie_bitmap;
|
||||
|
||||
fail:
|
||||
aie2_free_msg_buffer(ndev, buf_sz, buff_addr, dma_addr);
|
||||
amdxdna_free_msg_buffer(xdna, buf_sz, buff_addr, dma_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -446,17 +422,18 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev,
|
||||
char __user *buf, u32 size,
|
||||
struct amdxdna_drm_query_telemetry_header *header)
|
||||
{
|
||||
DECLARE_AIE2_MSG(get_telemetry, MSG_OP_GET_TELEMETRY);
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
DECLARE_AIE_MSG(get_telemetry, MSG_OP_GET_TELEMETRY);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
dma_addr_t dma_addr;
|
||||
u32 buf_sz = size;
|
||||
u32 buf_sz;
|
||||
u8 *addr;
|
||||
int ret;
|
||||
|
||||
if (header->type >= MAX_TELEMETRY_TYPE)
|
||||
return -EINVAL;
|
||||
|
||||
addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr);
|
||||
buf_sz = min(size, SZ_4M);
|
||||
addr = amdxdna_alloc_msg_buffer(xdna, &buf_sz, &dma_addr);
|
||||
if (IS_ERR(addr))
|
||||
return PTR_ERR(addr);
|
||||
|
||||
@@ -464,20 +441,21 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev,
|
||||
req.buf_size = buf_sz;
|
||||
req.type = header->type;
|
||||
|
||||
drm_clflush_virt_range(addr, size); /* device can access */
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
drm_clflush_virt_range(addr, req.buf_size); /* device can access */
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Query telemetry failed, status %d", ret);
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
if (size < resp.size) {
|
||||
if (buf_sz < resp.size) {
|
||||
ret = -EINVAL;
|
||||
XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", size, resp.size);
|
||||
XDNA_ERR(xdna, "Bad buffer size. Available: %u. Needs: %u", buf_sz, resp.size);
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
if (copy_to_user(buf, addr, resp.size)) {
|
||||
size = min(size, resp.size);
|
||||
if (copy_to_user(buf, addr, size)) {
|
||||
ret = -EFAULT;
|
||||
XDNA_ERR(xdna, "Failed to copy telemetry to user space");
|
||||
goto free_buf;
|
||||
@@ -487,7 +465,7 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev,
|
||||
header->minor = resp.minor;
|
||||
|
||||
free_buf:
|
||||
aie2_free_msg_buffer(ndev, buf_sz, addr, dma_addr);
|
||||
amdxdna_free_msg_buffer(xdna, buf_sz, addr, dma_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -506,8 +484,8 @@ int aie2_register_asyn_event_msg(struct amdxdna_dev_hdl *ndev, dma_addr_t addr,
|
||||
req.buf_addr = addr;
|
||||
req.buf_size = size;
|
||||
|
||||
XDNA_DBG(ndev->xdna, "Register addr 0x%llx size 0x%x", addr, size);
|
||||
return xdna_mailbox_send_msg(ndev->mgmt_chann, &msg, TX_TIMEOUT);
|
||||
XDNA_DBG(ndev->aie.xdna, "Register addr 0x%llx size 0x%x", addr, size);
|
||||
return xdna_mailbox_send_msg(ndev->aie.mgmt_chann, &msg, TX_TIMEOUT);
|
||||
}
|
||||
|
||||
int aie2_config_cu(struct amdxdna_hwctx *hwctx,
|
||||
@@ -866,7 +844,6 @@ static int aie2_init_exec_req(void *req, struct amdxdna_gem_obj *cmd_abo,
|
||||
int ret;
|
||||
u32 op;
|
||||
|
||||
|
||||
op = amdxdna_cmd_get_op(cmd_abo);
|
||||
switch (op) {
|
||||
case ERT_START_CU:
|
||||
@@ -915,12 +892,12 @@ aie2_cmdlist_fill_slot(void *slot, struct amdxdna_gem_obj *cmd_abo,
|
||||
ret = EXEC_MSG_OPS(xdna)->fill_dpu_slot(cmd_abo, slot, size);
|
||||
break;
|
||||
case ERT_START_NPU_PREEMPT:
|
||||
if (!AIE2_FEATURE_ON(xdna->dev_handle, AIE2_PREEMPT))
|
||||
if (!AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_PREEMPT))
|
||||
return -EOPNOTSUPP;
|
||||
ret = EXEC_MSG_OPS(xdna)->fill_preempt_slot(cmd_abo, slot, size);
|
||||
break;
|
||||
case ERT_START_NPU_PREEMPT_ELF:
|
||||
if (!AIE2_FEATURE_ON(xdna->dev_handle, AIE2_PREEMPT))
|
||||
if (!AIE_FEATURE_ON(&xdna->dev_handle->aie, AIE2_PREEMPT))
|
||||
return -EOPNOTSUPP;
|
||||
ret = EXEC_MSG_OPS(xdna)->fill_elf_slot(cmd_abo, slot, size);
|
||||
break;
|
||||
@@ -935,26 +912,12 @@ aie2_cmdlist_fill_slot(void *slot, struct amdxdna_gem_obj *cmd_abo,
|
||||
|
||||
void aie2_msg_init(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
if (AIE2_FEATURE_ON(ndev, AIE2_NPU_COMMAND))
|
||||
if (AIE_FEATURE_ON(&ndev->aie, AIE2_NPU_COMMAND))
|
||||
ndev->exec_msg_ops = &npu_exec_message_ops;
|
||||
else
|
||||
ndev->exec_msg_ops = &legacy_exec_message_ops;
|
||||
}
|
||||
|
||||
void aie2_destroy_mgmt_chann(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
if (!ndev->mgmt_chann)
|
||||
return;
|
||||
|
||||
xdna_mailbox_stop_channel(ndev->mgmt_chann);
|
||||
xdna_mailbox_free_channel(ndev->mgmt_chann);
|
||||
ndev->mgmt_chann = NULL;
|
||||
}
|
||||
|
||||
static inline struct amdxdna_gem_obj *
|
||||
aie2_cmdlist_get_cmd_buf(struct amdxdna_sched_job *job)
|
||||
{
|
||||
@@ -1199,20 +1162,20 @@ int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *
|
||||
int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id,
|
||||
struct app_health_report *report)
|
||||
{
|
||||
DECLARE_AIE2_MSG(get_app_health, MSG_OP_GET_APP_HEALTH);
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
DECLARE_AIE_MSG(get_app_health, MSG_OP_GET_APP_HEALTH);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct app_health_report *buf;
|
||||
dma_addr_t dma_addr;
|
||||
u32 buf_size;
|
||||
int ret;
|
||||
|
||||
if (!AIE2_FEATURE_ON(ndev, AIE2_APP_HEALTH)) {
|
||||
if (!AIE_FEATURE_ON(&ndev->aie, AIE2_APP_HEALTH)) {
|
||||
XDNA_DBG(xdna, "App health feature not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
buf_size = sizeof(*report);
|
||||
buf = aie2_alloc_msg_buffer(ndev, &buf_size, &dma_addr);
|
||||
buf = amdxdna_alloc_msg_buffer(xdna, &buf_size, &dma_addr);
|
||||
if (IS_ERR(buf)) {
|
||||
XDNA_ERR(xdna, "Failed to allocate buffer for app health");
|
||||
return PTR_ERR(buf);
|
||||
@@ -1222,8 +1185,8 @@ int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id,
|
||||
req.context_id = context_id;
|
||||
req.buf_size = buf_size;
|
||||
|
||||
drm_clflush_virt_range(buf, sizeof(*report));
|
||||
ret = aie2_send_mgmt_msg_wait(ndev, &msg);
|
||||
drm_clflush_virt_range(buf, req.buf_size);
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Get app health failed, ret %d status 0x%x", ret, resp.status);
|
||||
goto free_buf;
|
||||
@@ -1233,6 +1196,75 @@ int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id,
|
||||
memcpy(report, buf, sizeof(*report));
|
||||
|
||||
free_buf:
|
||||
aie2_free_msg_buffer(ndev, buf_size, buf, dma_addr);
|
||||
amdxdna_free_msg_buffer(xdna, buf_size, buf, dma_addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
aie2_runtime_update_ctx_prop(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_hwctx *ctx, u32 type, u32 value)
|
||||
{
|
||||
DECLARE_AIE_MSG(update_property, MSG_OP_UPDATE_PROPERTY);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
if (!AIE_FEATURE_ON(&ndev->aie, AIE2_UPDATE_PROPERTY))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ctx)
|
||||
req.context_id = ctx->fw_ctx_id;
|
||||
else
|
||||
req.context_id = AIE2_UPDATE_PROPERTY_ALL_CTX;
|
||||
|
||||
req.time_quota_us = value;
|
||||
req.type = type;
|
||||
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "%s update property failed, type %d ret %d",
|
||||
ctx ? ctx->name : "ctx.all", type, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie2_update_prop_time_quota(struct amdxdna_dev_hdl *ndev, u32 us)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
ret = aie2_runtime_update_ctx_prop(ndev, NULL, UPDATE_PROPERTY_TIME_QUOTA, us);
|
||||
if (ret == -EOPNOTSUPP) {
|
||||
XDNA_DBG(xdna, "update time quota not support, skipped");
|
||||
ret = 0;
|
||||
} else if (!ret) {
|
||||
XDNA_DBG(xdna, "Ctx exec time quantum updated to %u us", us);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aie2_get_dev_revision(struct amdxdna_dev_hdl *ndev, enum aie2_dev_revision *rev)
|
||||
{
|
||||
DECLARE_AIE_MSG(get_dev_revision, MSG_OP_GET_DEV_REVISION);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
if (!AIE_FEATURE_ON(&ndev->aie, AIE2_GET_DEV_REVISION))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*rev = resp.rev;
|
||||
|
||||
if (*rev < AIE2_DEV_REVISION_STXA || *rev >= AIE2_DEV_REVISION_UNKN) {
|
||||
XDNA_ERR(xdna, "Unknown device revision: %d (raw fuse: 0x%x)",
|
||||
*rev, resp.raw_fuse_data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
XDNA_DBG(xdna, "Device revision: %d (raw fuse: 0x%x)", *rev, resp.raw_fuse_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,10 @@ enum aie2_msg_opcode {
|
||||
MSG_OP_SET_RUNTIME_CONFIG = 0x10A,
|
||||
MSG_OP_GET_RUNTIME_CONFIG = 0x10B,
|
||||
MSG_OP_REGISTER_ASYNC_EVENT_MSG = 0x10C,
|
||||
MSG_OP_UPDATE_PROPERTY = 0x113,
|
||||
MSG_OP_GET_APP_HEALTH = 0x114,
|
||||
MSG_OP_ADD_HOST_BUFFER = 0x115,
|
||||
MSG_OP_GET_DEV_REVISION = 0x117,
|
||||
MSG_OP_MAX_DRV_OPCODE,
|
||||
MSG_OP_GET_PROTOCOL_VERSION = 0x301,
|
||||
MSG_OP_MAX_OPCODE
|
||||
@@ -460,7 +463,7 @@ struct fatal_error_info {
|
||||
__u32 exception_pc; /* Program Counter at the time of the exception */
|
||||
__u32 app_module; /* Error module name */
|
||||
__u32 task_index; /* Index of the task in which the error occurred */
|
||||
__u32 reserved[128];
|
||||
__u32 reserved[127];
|
||||
};
|
||||
|
||||
struct app_health_report {
|
||||
@@ -503,4 +506,41 @@ struct get_app_health_resp {
|
||||
__u32 required_buffer_size;
|
||||
__u32 reserved[7];
|
||||
} __packed;
|
||||
|
||||
struct update_property_req {
|
||||
#define UPDATE_PROPERTY_TIME_QUOTA 0
|
||||
__u32 type;
|
||||
#define AIE2_UPDATE_PROPERTY_ALL_CTX 0xFF
|
||||
__u8 context_id;
|
||||
__u8 reserved[7];
|
||||
__u32 time_quota_us;
|
||||
__u32 reserved1;
|
||||
} __packed;
|
||||
|
||||
struct update_property_resp {
|
||||
enum aie2_msg_status status;
|
||||
} __packed;
|
||||
|
||||
enum aie2_dev_revision {
|
||||
AIE2_DEV_REVISION_STXA = 1,
|
||||
AIE2_DEV_REVISION_STXB,
|
||||
AIE2_DEV_REVISION_KRK1,
|
||||
AIE2_DEV_REVISION_KRK2,
|
||||
AIE2_DEV_REVISION_HALO,
|
||||
AIE2_DEV_REVISION_GPT1,
|
||||
AIE2_DEV_REVISION_GPT2,
|
||||
AIE2_DEV_REVISION_GPT3,
|
||||
AIE2_DEV_REVISION_UNKN,
|
||||
};
|
||||
|
||||
struct get_dev_revision_req {
|
||||
__u32 place_holder;
|
||||
} __packed;
|
||||
|
||||
struct get_dev_revision_resp {
|
||||
enum aie2_msg_status status;
|
||||
enum aie2_dev_revision rev;
|
||||
__u32 raw_fuse_data;
|
||||
} __packed;
|
||||
|
||||
#endif /* _AIE2_MSG_PRIV_H_ */
|
||||
|
||||
@@ -33,6 +33,8 @@ static int aie2_max_col = XRS_MAX_COL;
|
||||
module_param(aie2_max_col, uint, 0600);
|
||||
MODULE_PARM_DESC(aie2_max_col, "Maximum column could be used");
|
||||
|
||||
#define DEFAULT_TIME_QUANTUM 30000 /* microseconds */
|
||||
|
||||
static char *npu_fw[] = {
|
||||
"npu_7.sbin",
|
||||
"npu.sbin"
|
||||
@@ -60,45 +62,6 @@ struct mgmt_mbox_chann_info {
|
||||
__u32 rsvd[4];
|
||||
};
|
||||
|
||||
static int aie2_check_protocol(struct amdxdna_dev_hdl *ndev, u32 fw_major, u32 fw_minor)
|
||||
{
|
||||
const struct aie2_fw_feature_tbl *feature;
|
||||
bool found = false;
|
||||
|
||||
for (feature = ndev->priv->fw_feature_tbl; feature->major; feature++) {
|
||||
if (feature->major != fw_major)
|
||||
continue;
|
||||
if (fw_minor < feature->min_minor)
|
||||
continue;
|
||||
if (feature->max_minor > 0 && fw_minor > feature->max_minor)
|
||||
continue;
|
||||
|
||||
ndev->feature_mask |= feature->features;
|
||||
|
||||
/* firmware version matches one of the driver support entry */
|
||||
found = true;
|
||||
}
|
||||
|
||||
return found ? 0 : -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void aie2_dump_chann_info_debug(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
|
||||
XDNA_DBG(xdna, "i2x tail 0x%x", ndev->mgmt_i2x.mb_tail_ptr_reg);
|
||||
XDNA_DBG(xdna, "i2x head 0x%x", ndev->mgmt_i2x.mb_head_ptr_reg);
|
||||
XDNA_DBG(xdna, "i2x ringbuf 0x%x", ndev->mgmt_i2x.rb_start_addr);
|
||||
XDNA_DBG(xdna, "i2x rsize 0x%x", ndev->mgmt_i2x.rb_size);
|
||||
XDNA_DBG(xdna, "x2i tail 0x%x", ndev->mgmt_x2i.mb_tail_ptr_reg);
|
||||
XDNA_DBG(xdna, "x2i head 0x%x", ndev->mgmt_x2i.mb_head_ptr_reg);
|
||||
XDNA_DBG(xdna, "x2i ringbuf 0x%x", ndev->mgmt_x2i.rb_start_addr);
|
||||
XDNA_DBG(xdna, "x2i rsize 0x%x", ndev->mgmt_x2i.rb_size);
|
||||
XDNA_DBG(xdna, "x2i chann index 0x%x", ndev->mgmt_chan_idx);
|
||||
XDNA_DBG(xdna, "mailbox protocol major 0x%x", ndev->mgmt_prot_major);
|
||||
XDNA_DBG(xdna, "mailbox protocol minor 0x%x", ndev->mgmt_prot_minor);
|
||||
}
|
||||
|
||||
static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct mgmt_mbox_chann_info info_regs;
|
||||
@@ -118,7 +81,7 @@ static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev)
|
||||
* is alive.
|
||||
*/
|
||||
ret = readx_poll_timeout(readl, SRAM_GET_ADDR(ndev, FW_ALIVE_OFF),
|
||||
addr, addr, AIE2_INTERVAL, AIE2_TIMEOUT);
|
||||
addr, addr, AIE_INTERVAL, AIE_TIMEOUT);
|
||||
if (ret || !addr)
|
||||
return -ETIME;
|
||||
|
||||
@@ -128,13 +91,13 @@ static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev)
|
||||
reg[i] = readl(ndev->sram_base + off + i * sizeof(u32));
|
||||
|
||||
if (info_regs.magic != MGMT_MBOX_MAGIC) {
|
||||
XDNA_ERR(ndev->xdna, "Invalid mbox magic 0x%x", info_regs.magic);
|
||||
XDNA_ERR(ndev->aie.xdna, "Invalid mbox magic 0x%x", info_regs.magic);
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
i2x = &ndev->mgmt_i2x;
|
||||
x2i = &ndev->mgmt_x2i;
|
||||
i2x = &ndev->aie.mgmt_i2x;
|
||||
x2i = &ndev->aie.mgmt_x2i;
|
||||
|
||||
i2x->mb_head_ptr_reg = AIE2_MBOX_OFF(ndev, info_regs.i2x_head);
|
||||
i2x->mb_tail_ptr_reg = AIE2_MBOX_OFF(ndev, info_regs.i2x_tail);
|
||||
@@ -146,14 +109,15 @@ static int aie2_get_mgmt_chann_info(struct amdxdna_dev_hdl *ndev)
|
||||
x2i->rb_start_addr = AIE2_SRAM_OFF(ndev, info_regs.x2i_buf);
|
||||
x2i->rb_size = info_regs.x2i_buf_sz;
|
||||
|
||||
ndev->mgmt_chan_idx = info_regs.msi_id;
|
||||
ndev->mgmt_prot_major = info_regs.prot_major;
|
||||
ndev->mgmt_prot_minor = info_regs.prot_minor;
|
||||
ndev->aie.mgmt_chan_idx = info_regs.msi_id;
|
||||
ndev->aie.mgmt_prot_major = info_regs.prot_major;
|
||||
ndev->aie.mgmt_prot_minor = info_regs.prot_minor;
|
||||
|
||||
ret = aie2_check_protocol(ndev, ndev->mgmt_prot_major, ndev->mgmt_prot_minor);
|
||||
ret = aie_check_protocol(&ndev->aie, ndev->aie.mgmt_prot_major,
|
||||
ndev->aie.mgmt_prot_minor);
|
||||
|
||||
done:
|
||||
aie2_dump_chann_info_debug(ndev);
|
||||
aie_dump_mgmt_chann_debug(&ndev->aie);
|
||||
|
||||
/* Must clear address at FW_ALIVE_OFF */
|
||||
writel(0, SRAM_GET_ADDR(ndev, FW_ALIVE_OFF));
|
||||
@@ -173,13 +137,14 @@ int aie2_runtime_cfg(struct amdxdna_dev_hdl *ndev,
|
||||
continue;
|
||||
|
||||
if (cfg->feature_mask &&
|
||||
bitmap_subset(&cfg->feature_mask, &ndev->feature_mask, AIE2_FEATURE_MAX))
|
||||
bitmap_subset(&cfg->feature_mask, &ndev->aie.feature_mask,
|
||||
AIE2_FEATURE_MAX))
|
||||
continue;
|
||||
|
||||
value = val ? *val : cfg->value;
|
||||
ret = aie2_set_runtime_cfg(ndev, cfg->type, value);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Set type %d value %d failed",
|
||||
XDNA_ERR(ndev->aie.xdna, "Set type %d value %d failed",
|
||||
cfg->type, value);
|
||||
return ret;
|
||||
}
|
||||
@@ -194,13 +159,13 @@ static int aie2_xdna_reset(struct amdxdna_dev_hdl *ndev)
|
||||
|
||||
ret = aie2_suspend_fw(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Suspend firmware failed");
|
||||
XDNA_ERR(ndev->aie.xdna, "Suspend firmware failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_resume_fw(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Resume firmware failed");
|
||||
XDNA_ERR(ndev->aie.xdna, "Resume firmware failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -213,19 +178,25 @@ static int aie2_mgmt_fw_init(struct amdxdna_dev_hdl *ndev)
|
||||
|
||||
ret = aie2_runtime_cfg(ndev, AIE2_RT_CFG_INIT, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Runtime config failed");
|
||||
XDNA_ERR(ndev->aie.xdna, "Runtime config failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_assign_mgmt_pasid(ndev, 0);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Can not assign PASID");
|
||||
XDNA_ERR(ndev->aie.xdna, "Can not assign PASID");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_update_prop_time_quota(ndev, DEFAULT_TIME_QUANTUM);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->aie.xdna, "Failed to update execution time quantum");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_xdna_reset(ndev);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Reset firmware failed");
|
||||
XDNA_ERR(ndev->aie.xdna, "Reset firmware failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -236,25 +207,25 @@ static int aie2_mgmt_fw_query(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie2_query_firmware_version(ndev, &ndev->xdna->fw_ver);
|
||||
ret = aie2_query_firmware_version(ndev, &ndev->aie.xdna->fw_ver);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "query firmware version failed");
|
||||
XDNA_ERR(ndev->aie.xdna, "query firmware version failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_query_aie_version(ndev, &ndev->version);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Query AIE version failed");
|
||||
XDNA_ERR(ndev->aie.xdna, "Query AIE version failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_query_aie_metadata(ndev, &ndev->metadata);
|
||||
ret = aie2_query_aie_metadata(ndev, &ndev->aie.metadata);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Query AIE metadata failed");
|
||||
XDNA_ERR(ndev->aie.xdna, "Query AIE metadata failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ndev->total_col = min(aie2_max_col, ndev->metadata.cols);
|
||||
ndev->total_col = min(aie2_max_col, ndev->aie.metadata.cols);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -262,8 +233,8 @@ static int aie2_mgmt_fw_query(struct amdxdna_dev_hdl *ndev)
|
||||
static void aie2_mgmt_fw_fini(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
if (aie2_suspend_fw(ndev))
|
||||
XDNA_ERR(ndev->xdna, "Suspend_fw failed");
|
||||
XDNA_DBG(ndev->xdna, "Firmware suspended");
|
||||
XDNA_ERR(ndev->aie.xdna, "Suspend_fw failed");
|
||||
XDNA_DBG(ndev->aie.xdna, "Firmware suspended");
|
||||
}
|
||||
|
||||
static int aie2_xrs_load(void *cb_arg, struct xrs_action_load *action)
|
||||
@@ -275,6 +246,7 @@ static int aie2_xrs_load(void *cb_arg, struct xrs_action_load *action)
|
||||
xdna = hwctx->client->xdna;
|
||||
|
||||
hwctx->start_col = action->part.start_col;
|
||||
hwctx->num_unused_col = action->part.ncols - hwctx->num_col;
|
||||
hwctx->num_col = action->part.ncols;
|
||||
ret = aie2_create_context(xdna->dev_handle, hwctx);
|
||||
if (ret)
|
||||
@@ -319,6 +291,12 @@ static struct xrs_action_ops aie2_xrs_actions = {
|
||||
.set_dft_dpm_level = aie2_xrs_set_dft_dpm_level,
|
||||
};
|
||||
|
||||
static void aie2_smu_fini(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
ndev->priv->hw_ops->set_dpm(ndev, 0);
|
||||
aie_smu_fini(ndev->aie.smu_hdl);
|
||||
}
|
||||
|
||||
static void aie2_hw_stop(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
@@ -331,10 +309,10 @@ static void aie2_hw_stop(struct amdxdna_dev *xdna)
|
||||
|
||||
aie2_runtime_cfg(ndev, AIE2_RT_CFG_CLK_GATING, NULL);
|
||||
aie2_mgmt_fw_fini(ndev);
|
||||
aie2_destroy_mgmt_chann(ndev);
|
||||
aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann);
|
||||
drmm_kfree(&xdna->ddev, ndev->mbox);
|
||||
ndev->mbox = NULL;
|
||||
aie2_psp_stop(ndev->psp_hdl);
|
||||
aie_psp_stop(ndev->aie.psp_hdl);
|
||||
aie2_smu_fini(ndev);
|
||||
aie2_error_async_events_free(ndev);
|
||||
pci_disable_device(pdev);
|
||||
@@ -374,20 +352,20 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
||||
goto disable_dev;
|
||||
}
|
||||
|
||||
ndev->mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
|
||||
if (!ndev->mgmt_chann) {
|
||||
ndev->aie.mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
|
||||
if (!ndev->aie.mgmt_chann) {
|
||||
XDNA_ERR(xdna, "failed to alloc channel");
|
||||
ret = -ENODEV;
|
||||
goto disable_dev;
|
||||
}
|
||||
|
||||
ret = aie2_smu_init(ndev);
|
||||
ret = aie_smu_init(ndev->aie.smu_hdl);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to init smu, ret %d", ret);
|
||||
goto free_channel;
|
||||
}
|
||||
|
||||
ret = aie2_psp_start(ndev->psp_hdl);
|
||||
ret = aie_psp_start(ndev->aie.psp_hdl);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to start psp, ret %d", ret);
|
||||
goto fini_smu;
|
||||
@@ -399,17 +377,17 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
||||
goto stop_psp;
|
||||
}
|
||||
|
||||
mgmt_mb_irq = pci_irq_vector(pdev, ndev->mgmt_chan_idx);
|
||||
mgmt_mb_irq = pci_irq_vector(pdev, ndev->aie.mgmt_chan_idx);
|
||||
if (mgmt_mb_irq < 0) {
|
||||
ret = mgmt_mb_irq;
|
||||
XDNA_ERR(xdna, "failed to alloc irq vector, ret %d", ret);
|
||||
goto stop_psp;
|
||||
}
|
||||
|
||||
xdna_mailbox_intr_reg = ndev->mgmt_i2x.mb_head_ptr_reg + 4;
|
||||
ret = xdna_mailbox_start_channel(ndev->mgmt_chann,
|
||||
&ndev->mgmt_x2i,
|
||||
&ndev->mgmt_i2x,
|
||||
xdna_mailbox_intr_reg = ndev->aie.mgmt_i2x.mb_head_ptr_reg + 4;
|
||||
ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
|
||||
&ndev->aie.mgmt_x2i,
|
||||
&ndev->aie.mgmt_i2x,
|
||||
xdna_mailbox_intr_reg,
|
||||
mgmt_mb_irq);
|
||||
if (ret) {
|
||||
@@ -448,14 +426,14 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
|
||||
|
||||
stop_fw:
|
||||
aie2_suspend_fw(ndev);
|
||||
xdna_mailbox_stop_channel(ndev->mgmt_chann);
|
||||
xdna_mailbox_stop_channel(ndev->aie.mgmt_chann);
|
||||
stop_psp:
|
||||
aie2_psp_stop(ndev->psp_hdl);
|
||||
aie_psp_stop(ndev->aie.psp_hdl);
|
||||
fini_smu:
|
||||
aie2_smu_fini(ndev);
|
||||
free_channel:
|
||||
xdna_mailbox_free_channel(ndev->mgmt_chann);
|
||||
ndev->mgmt_chann = NULL;
|
||||
xdna_mailbox_free_channel(ndev->aie.mgmt_chann);
|
||||
ndev->aie.mgmt_chann = NULL;
|
||||
disable_dev:
|
||||
pci_disable_device(pdev);
|
||||
|
||||
@@ -500,7 +478,8 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
||||
void __iomem *tbl[PCI_NUM_RESOURCES] = {0};
|
||||
struct init_config xrs_cfg = { 0 };
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
struct psp_config psp_conf;
|
||||
struct psp_config psp_conf = { 0 };
|
||||
struct smu_config smu_conf;
|
||||
const struct firmware *fw;
|
||||
unsigned long bars = 0;
|
||||
char *fw_full_path;
|
||||
@@ -521,7 +500,7 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
||||
return -ENOMEM;
|
||||
|
||||
ndev->priv = xdna->dev_info->dev_priv;
|
||||
ndev->xdna = xdna;
|
||||
ndev->aie.xdna = xdna;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(npu_fw); i++) {
|
||||
fw_full_path = kasprintf(GFP_KERNEL, "%s%s", ndev->priv->fw_path, npu_fw[i]);
|
||||
@@ -550,9 +529,10 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
||||
|
||||
for (i = 0; i < PSP_MAX_REGS; i++)
|
||||
set_bit(PSP_REG_BAR(ndev, i), &bars);
|
||||
for (i = 0; i < SMU_MAX_REGS; i++)
|
||||
set_bit(SMU_REG_BAR(ndev, i), &bars);
|
||||
|
||||
set_bit(xdna->dev_info->sram_bar, &bars);
|
||||
set_bit(xdna->dev_info->smu_bar, &bars);
|
||||
set_bit(xdna->dev_info->mbox_bar, &bars);
|
||||
|
||||
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
|
||||
@@ -567,7 +547,6 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
||||
}
|
||||
|
||||
ndev->sram_base = tbl[xdna->dev_info->sram_bar];
|
||||
ndev->smu_base = tbl[xdna->dev_info->smu_bar];
|
||||
ndev->mbox_base = tbl[xdna->dev_info->mbox_bar];
|
||||
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
|
||||
@@ -591,14 +570,25 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
||||
|
||||
psp_conf.fw_size = fw->size;
|
||||
psp_conf.fw_buf = fw->data;
|
||||
psp_conf.arg2_mask = GENMASK(23, 0);
|
||||
psp_conf.notify_val = 1;
|
||||
for (i = 0; i < PSP_MAX_REGS; i++)
|
||||
psp_conf.psp_regs[i] = tbl[PSP_REG_BAR(ndev, i)] + PSP_REG_OFF(ndev, i);
|
||||
ndev->psp_hdl = aie2m_psp_create(&xdna->ddev, &psp_conf);
|
||||
if (!ndev->psp_hdl) {
|
||||
ndev->aie.psp_hdl = aiem_psp_create(&xdna->ddev, &psp_conf);
|
||||
if (!ndev->aie.psp_hdl) {
|
||||
XDNA_ERR(xdna, "failed to create psp");
|
||||
ret = -ENOMEM;
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
for (i = 0; i < SMU_MAX_REGS; i++)
|
||||
smu_conf.smu_regs[i] = tbl[SMU_REG_BAR(ndev, i)] + SMU_REG_OFF(ndev, i);
|
||||
ndev->aie.smu_hdl = aiem_smu_create(&xdna->ddev, &smu_conf);
|
||||
if (!ndev->aie.smu_hdl) {
|
||||
XDNA_ERR(xdna, "failed to create smu");
|
||||
ret = -ENOMEM;
|
||||
goto release_fw;
|
||||
}
|
||||
xdna->dev_handle = ndev;
|
||||
|
||||
ret = aie2_hw_start(xdna);
|
||||
@@ -610,7 +600,7 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
||||
xrs_cfg.clk_list.num_levels = ndev->max_dpm_level + 1;
|
||||
for (i = 0; i < xrs_cfg.clk_list.num_levels; i++)
|
||||
xrs_cfg.clk_list.cu_clk_list[i] = ndev->priv->dpm_clk_tbl[i].hclk;
|
||||
xrs_cfg.sys_eff_factor = 1;
|
||||
xrs_cfg.sys_eff_factor = 2;
|
||||
xrs_cfg.ddev = &xdna->ddev;
|
||||
xrs_cfg.actions = &aie2_xrs_actions;
|
||||
xrs_cfg.total_col = ndev->total_col;
|
||||
@@ -624,6 +614,7 @@ static int aie2_init(struct amdxdna_dev *xdna)
|
||||
|
||||
release_firmware(fw);
|
||||
aie2_msg_init(ndev);
|
||||
amdxdna_vbnv_init(xdna);
|
||||
amdxdna_pm_init(xdna);
|
||||
return 0;
|
||||
|
||||
@@ -644,23 +635,19 @@ static void aie2_fini(struct amdxdna_dev *xdna)
|
||||
static int aie2_get_aie_status(struct amdxdna_client *client,
|
||||
struct amdxdna_drm_get_info *args)
|
||||
{
|
||||
struct amdxdna_drm_query_aie_status status;
|
||||
struct amdxdna_drm_query_aie_status status = {};
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
u32 buf_sz;
|
||||
int ret;
|
||||
|
||||
ndev = xdna->dev_handle;
|
||||
if (copy_from_user(&status, u64_to_user_ptr(args->buffer), sizeof(status))) {
|
||||
buf_sz = min(args->buffer_size, sizeof(status));
|
||||
if (copy_from_user(&status, u64_to_user_ptr(args->buffer), buf_sz)) {
|
||||
XDNA_ERR(xdna, "Failed to copy AIE request into kernel");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (ndev->metadata.cols * ndev->metadata.size < status.buffer_size) {
|
||||
XDNA_ERR(xdna, "Invalid buffer size. Given Size: %u. Need Size: %u.",
|
||||
status.buffer_size, ndev->metadata.cols * ndev->metadata.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = aie2_query_status(ndev, u64_to_user_ptr(status.buffer),
|
||||
status.buffer_size, &status.cols_filled);
|
||||
if (ret) {
|
||||
@@ -668,7 +655,7 @@ static int aie2_get_aie_status(struct amdxdna_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &status, sizeof(status))) {
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &status, buf_sz)) {
|
||||
XDNA_ERR(xdna, "Failed to copy AIE request info to user space");
|
||||
return -EFAULT;
|
||||
}
|
||||
@@ -676,63 +663,20 @@ static int aie2_get_aie_status(struct amdxdna_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aie2_get_aie_metadata(struct amdxdna_client *client,
|
||||
struct amdxdna_drm_get_info *args)
|
||||
{
|
||||
struct amdxdna_drm_query_aie_metadata *meta;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
int ret = 0;
|
||||
|
||||
ndev = xdna->dev_handle;
|
||||
meta = kzalloc_obj(*meta);
|
||||
if (!meta)
|
||||
return -ENOMEM;
|
||||
|
||||
meta->col_size = ndev->metadata.size;
|
||||
meta->cols = ndev->metadata.cols;
|
||||
meta->rows = ndev->metadata.rows;
|
||||
|
||||
meta->version.major = ndev->metadata.version.major;
|
||||
meta->version.minor = ndev->metadata.version.minor;
|
||||
|
||||
meta->core.row_count = ndev->metadata.core.row_count;
|
||||
meta->core.row_start = ndev->metadata.core.row_start;
|
||||
meta->core.dma_channel_count = ndev->metadata.core.dma_channel_count;
|
||||
meta->core.lock_count = ndev->metadata.core.lock_count;
|
||||
meta->core.event_reg_count = ndev->metadata.core.event_reg_count;
|
||||
|
||||
meta->mem.row_count = ndev->metadata.mem.row_count;
|
||||
meta->mem.row_start = ndev->metadata.mem.row_start;
|
||||
meta->mem.dma_channel_count = ndev->metadata.mem.dma_channel_count;
|
||||
meta->mem.lock_count = ndev->metadata.mem.lock_count;
|
||||
meta->mem.event_reg_count = ndev->metadata.mem.event_reg_count;
|
||||
|
||||
meta->shim.row_count = ndev->metadata.shim.row_count;
|
||||
meta->shim.row_start = ndev->metadata.shim.row_start;
|
||||
meta->shim.dma_channel_count = ndev->metadata.shim.dma_channel_count;
|
||||
meta->shim.lock_count = ndev->metadata.shim.lock_count;
|
||||
meta->shim.event_reg_count = ndev->metadata.shim.event_reg_count;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), meta, sizeof(*meta)))
|
||||
ret = -EFAULT;
|
||||
|
||||
kfree(meta);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie2_get_aie_version(struct amdxdna_client *client,
|
||||
struct amdxdna_drm_get_info *args)
|
||||
{
|
||||
struct amdxdna_drm_query_aie_version version;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
u32 buf_sz;
|
||||
|
||||
ndev = xdna->dev_handle;
|
||||
version.major = ndev->version.major;
|
||||
version.minor = ndev->version.minor;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &version, sizeof(version)))
|
||||
buf_sz = min(args->buffer_size, sizeof(version));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &version, buf_sz))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
@@ -743,13 +687,15 @@ static int aie2_get_firmware_version(struct amdxdna_client *client,
|
||||
{
|
||||
struct amdxdna_drm_query_firmware_version version;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
u32 buf_sz;
|
||||
|
||||
version.major = xdna->fw_ver.major;
|
||||
version.minor = xdna->fw_ver.minor;
|
||||
version.patch = xdna->fw_ver.sub;
|
||||
version.build = xdna->fw_ver.build;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &version, sizeof(version)))
|
||||
buf_sz = min(args->buffer_size, sizeof(version));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &version, buf_sz))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
@@ -761,11 +707,13 @@ static int aie2_get_power_mode(struct amdxdna_client *client,
|
||||
struct amdxdna_drm_get_power_mode mode = {};
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
u32 buf_sz;
|
||||
|
||||
ndev = xdna->dev_handle;
|
||||
mode.power_mode = ndev->pw_mode;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &mode, sizeof(mode)))
|
||||
buf_sz = min(args->buffer_size, sizeof(mode));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &mode, buf_sz))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
@@ -778,19 +726,22 @@ static int aie2_get_clock_metadata(struct amdxdna_client *client,
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
int ret = 0;
|
||||
u32 buf_sz;
|
||||
|
||||
ndev = xdna->dev_handle;
|
||||
clock = kzalloc_obj(*clock);
|
||||
if (!clock)
|
||||
return -ENOMEM;
|
||||
|
||||
aie2_update_counters(ndev);
|
||||
snprintf(clock->mp_npu_clock.name, sizeof(clock->mp_npu_clock.name),
|
||||
"MP-NPU Clock");
|
||||
clock->mp_npu_clock.freq_mhz = ndev->npuclk_freq;
|
||||
snprintf(clock->h_clock.name, sizeof(clock->h_clock.name), "H Clock");
|
||||
clock->h_clock.freq_mhz = ndev->hclk_freq;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), clock, sizeof(*clock)))
|
||||
buf_sz = min(args->buffer_size, sizeof(*clock));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), clock, buf_sz))
|
||||
ret = -EFAULT;
|
||||
|
||||
kfree(clock);
|
||||
@@ -816,12 +767,14 @@ static int aie2_get_sensors(struct amdxdna_client *client,
|
||||
scnprintf(sensor.label, sizeof(sensor.label), "Total Power");
|
||||
scnprintf(sensor.units, sizeof(sensor.units), "mW");
|
||||
|
||||
if (args->buffer_size < sizeof(sensor))
|
||||
goto out;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &sensor, sizeof(sensor)))
|
||||
return -EFAULT;
|
||||
|
||||
args->buffer_size -= sizeof(sensor);
|
||||
sensors_count++;
|
||||
if (args->buffer_size <= sensors_count * sizeof(sensor))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < min_t(u32, ndev->total_col, 8); i++) {
|
||||
memset(&sensor, 0, sizeof(sensor));
|
||||
@@ -831,13 +784,15 @@ static int aie2_get_sensors(struct amdxdna_client *client,
|
||||
scnprintf(sensor.label, sizeof(sensor.label), "Column %d Utilization", i);
|
||||
scnprintf(sensor.units, sizeof(sensor.units), "%%");
|
||||
|
||||
if (args->buffer_size < sizeof(sensor))
|
||||
goto out;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer) + sensors_count * sizeof(sensor),
|
||||
&sensor, sizeof(sensor)))
|
||||
return -EFAULT;
|
||||
|
||||
args->buffer_size -= sizeof(sensor);
|
||||
sensors_count++;
|
||||
if (args->buffer_size <= sensors_count * sizeof(sensor))
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -933,18 +888,21 @@ static int aie2_query_resource_info(struct amdxdna_client *client,
|
||||
const struct amdxdna_dev_priv *priv;
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
struct amdxdna_dev *xdna;
|
||||
u32 buf_sz;
|
||||
|
||||
xdna = client->xdna;
|
||||
ndev = xdna->dev_handle;
|
||||
priv = ndev->priv;
|
||||
|
||||
aie2_update_counters(ndev);
|
||||
res_info.npu_clk_max = priv->dpm_clk_tbl[ndev->max_dpm_level].hclk;
|
||||
res_info.npu_tops_max = ndev->max_tops;
|
||||
res_info.npu_task_max = priv->hwctx_limit;
|
||||
res_info.npu_tops_curr = ndev->curr_tops;
|
||||
res_info.npu_task_curr = ndev->hwctx_num;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &res_info, sizeof(res_info)))
|
||||
buf_sz = min(args->buffer_size, sizeof(res_info));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &res_info, buf_sz))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
@@ -980,12 +938,7 @@ static int aie2_get_telemetry(struct amdxdna_client *client,
|
||||
XDNA_ERR(xdna, "Invalid buffer size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
telemetry_data_sz = args->buffer_size - header_sz;
|
||||
if (telemetry_data_sz > SZ_4M) {
|
||||
XDNA_ERR(xdna, "Buffer size is too big, %d", telemetry_data_sz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
header = kzalloc(header_sz, GFP_KERNEL);
|
||||
if (!header)
|
||||
@@ -1026,6 +979,7 @@ static int aie2_get_preempt_state(struct amdxdna_client *client,
|
||||
struct amdxdna_drm_attribute_state state = {};
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
u32 buf_sz;
|
||||
|
||||
ndev = xdna->dev_handle;
|
||||
if (args->param == DRM_AMDXDNA_GET_FORCE_PREEMPT_STATE)
|
||||
@@ -1033,7 +987,8 @@ static int aie2_get_preempt_state(struct amdxdna_client *client,
|
||||
else if (args->param == DRM_AMDXDNA_GET_FRAME_BOUNDARY_PREEMPT_STATE)
|
||||
state.state = ndev->frame_boundary_preempt;
|
||||
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &state, sizeof(state)))
|
||||
buf_sz = min(args->buffer_size, sizeof(state));
|
||||
if (copy_to_user(u64_to_user_ptr(args->buffer), &state, buf_sz))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
@@ -1042,6 +997,7 @@ static int aie2_get_preempt_state(struct amdxdna_client *client,
|
||||
static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args)
|
||||
{
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
int ret, idx;
|
||||
|
||||
if (!drm_dev_enter(&xdna->ddev, &idx))
|
||||
@@ -1056,7 +1012,7 @@ static int aie2_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_i
|
||||
ret = aie2_get_aie_status(client, args);
|
||||
break;
|
||||
case DRM_AMDXDNA_QUERY_AIE_METADATA:
|
||||
ret = aie2_get_aie_metadata(client, args);
|
||||
ret = amdxdna_get_metadata(&ndev->aie, client, args);
|
||||
break;
|
||||
case DRM_AMDXDNA_QUERY_AIE_VERSION:
|
||||
ret = aie2_get_aie_version(client, args);
|
||||
@@ -1260,6 +1216,21 @@ static int aie2_set_state(struct amdxdna_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie2_get_dev_rev(struct amdxdna_dev *xdna, u32 *rev)
|
||||
{
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
enum aie2_dev_revision aie2_rev;
|
||||
int ret;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
ret = aie2_get_dev_revision(ndev, &aie2_rev);
|
||||
|
||||
if (!ret)
|
||||
*rev = (u32)aie2_rev;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct amdxdna_dev_ops aie2_ops = {
|
||||
.init = aie2_init,
|
||||
.fini = aie2_fini,
|
||||
@@ -1274,4 +1245,6 @@ const struct amdxdna_dev_ops aie2_ops = {
|
||||
.cmd_submit = aie2_cmd_submit,
|
||||
.hmm_invalidate = aie2_hmm_invalidate,
|
||||
.get_array = aie2_get_array,
|
||||
.get_dev_revision = aie2_get_dev_rev,
|
||||
.hwctx_heap_expand = aie2_hwctx_heap_expand,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2023-2024, Advanced Micro Devices, Inc.
|
||||
* Copyright (C) 2023-2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _AIE2_PCI_H_
|
||||
@@ -10,30 +10,22 @@
|
||||
#include <linux/limits.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "aie2_msg_priv.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
|
||||
#define AIE2_INTERVAL 20000 /* us */
|
||||
#define AIE2_TIMEOUT 1000000 /* us */
|
||||
|
||||
/* Firmware determines device memory base address and size */
|
||||
#define AIE2_DEVM_BASE 0x4000000
|
||||
#define AIE2_DEVM_SIZE SZ_64M
|
||||
#define AIE2_DEVM_BASE 0x4000000
|
||||
#define AIE2_DEVM_SIZE SZ_64M
|
||||
#define AIE2_DEVM_MAX_SIZE SZ_512M
|
||||
|
||||
#define NDEV2PDEV(ndev) (to_pci_dev((ndev)->xdna->ddev.dev))
|
||||
#define NDEV2PDEV(ndev) (to_pci_dev((ndev)->aie.xdna->ddev.dev))
|
||||
|
||||
#define AIE2_SRAM_OFF(ndev, addr) ((addr) - (ndev)->priv->sram_dev_addr)
|
||||
#define AIE2_MBOX_OFF(ndev, addr) ((addr) - (ndev)->priv->mbox_dev_addr)
|
||||
|
||||
#define PSP_REG_BAR(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].bar_idx)
|
||||
#define PSP_REG_OFF(ndev, idx) ((ndev)->priv->psp_regs_off[(idx)].offset)
|
||||
#define SRAM_REG_OFF(ndev, idx) ((ndev)->priv->sram_offs[(idx)].offset)
|
||||
|
||||
#define SMU_REG(ndev, idx) \
|
||||
({ \
|
||||
typeof(ndev) _ndev = ndev; \
|
||||
((_ndev)->smu_base + (_ndev)->priv->smu_regs_off[(idx)].offset); \
|
||||
})
|
||||
#define SRAM_GET_ADDR(ndev, idx) \
|
||||
({ \
|
||||
typeof(ndev) _ndev = ndev; \
|
||||
@@ -45,7 +37,7 @@
|
||||
({ \
|
||||
typeof(ndev) _ndev = (ndev); \
|
||||
((_ndev)->priv->mbox_size) ? (_ndev)->priv->mbox_size : \
|
||||
pci_resource_len(NDEV2PDEV(_ndev), (_ndev)->xdna->dev_info->mbox_bar); \
|
||||
pci_resource_len(NDEV2PDEV(_ndev), (_ndev)->aie.xdna->dev_info->mbox_bar); \
|
||||
})
|
||||
|
||||
#if IS_ENABLED(CONFIG_AMD_PMF)
|
||||
@@ -75,68 +67,17 @@
|
||||
})
|
||||
#endif
|
||||
|
||||
enum aie2_smu_reg_idx {
|
||||
SMU_CMD_REG = 0,
|
||||
SMU_ARG_REG,
|
||||
SMU_INTR_REG,
|
||||
SMU_RESP_REG,
|
||||
SMU_OUT_REG,
|
||||
SMU_MAX_REGS /* Keep this at the end */
|
||||
};
|
||||
|
||||
enum aie2_sram_reg_idx {
|
||||
MBOX_CHANN_OFF = 0,
|
||||
FW_ALIVE_OFF,
|
||||
SRAM_MAX_INDEX /* Keep this at the end */
|
||||
};
|
||||
|
||||
enum psp_reg_idx {
|
||||
PSP_CMD_REG = 0,
|
||||
PSP_ARG0_REG,
|
||||
PSP_ARG1_REG,
|
||||
PSP_ARG2_REG,
|
||||
PSP_NUM_IN_REGS, /* number of input registers */
|
||||
PSP_INTR_REG = PSP_NUM_IN_REGS,
|
||||
PSP_STATUS_REG,
|
||||
PSP_RESP_REG,
|
||||
PSP_PWAITMODE_REG,
|
||||
PSP_MAX_REGS /* Keep this at the end */
|
||||
};
|
||||
|
||||
struct amdxdna_client;
|
||||
struct amdxdna_fw_ver;
|
||||
struct amdxdna_hwctx;
|
||||
struct amdxdna_sched_job;
|
||||
|
||||
struct psp_config {
|
||||
const void *fw_buf;
|
||||
u32 fw_size;
|
||||
void __iomem *psp_regs[PSP_MAX_REGS];
|
||||
};
|
||||
|
||||
struct aie_version {
|
||||
u16 major;
|
||||
u16 minor;
|
||||
};
|
||||
|
||||
struct aie_tile_metadata {
|
||||
u16 row_count;
|
||||
u16 row_start;
|
||||
u16 dma_channel_count;
|
||||
u16 lock_count;
|
||||
u16 event_reg_count;
|
||||
};
|
||||
|
||||
struct aie_metadata {
|
||||
u32 size;
|
||||
u16 cols;
|
||||
u16 rows;
|
||||
struct aie_version version;
|
||||
struct aie_tile_metadata core;
|
||||
struct aie_tile_metadata mem;
|
||||
struct aie_tile_metadata shim;
|
||||
};
|
||||
|
||||
enum rt_config_category {
|
||||
AIE2_RT_CFG_INIT,
|
||||
AIE2_RT_CFG_CLK_GATING,
|
||||
@@ -202,24 +143,19 @@ struct aie2_exec_msg_ops {
|
||||
u32 (*get_chain_msg_op)(u32 cmd_op);
|
||||
};
|
||||
|
||||
enum aie2_tdr_status {
|
||||
AIE2_TDR_WAIT,
|
||||
AIE2_TDR_SIGNALED,
|
||||
};
|
||||
|
||||
struct amdxdna_dev_hdl {
|
||||
struct amdxdna_dev *xdna;
|
||||
struct aie_device aie;
|
||||
const struct amdxdna_dev_priv *priv;
|
||||
void __iomem *sram_base;
|
||||
void __iomem *smu_base;
|
||||
void __iomem *mbox_base;
|
||||
struct psp_device *psp_hdl;
|
||||
|
||||
struct xdna_mailbox_chann_res mgmt_x2i;
|
||||
struct xdna_mailbox_chann_res mgmt_i2x;
|
||||
u32 mgmt_chan_idx;
|
||||
u32 mgmt_prot_major;
|
||||
u32 mgmt_prot_minor;
|
||||
|
||||
u32 total_col;
|
||||
struct aie_version version;
|
||||
struct aie_metadata metadata;
|
||||
unsigned long feature_mask;
|
||||
struct amdxdna_drm_query_aie_version version;
|
||||
struct aie2_exec_msg_ops *exec_msg_ops;
|
||||
|
||||
/* power management and clock*/
|
||||
@@ -237,63 +173,58 @@ struct amdxdna_dev_hdl {
|
||||
|
||||
/* Mailbox and the management channel */
|
||||
struct mailbox *mbox;
|
||||
struct mailbox_channel *mgmt_chann;
|
||||
struct async_events *async_events;
|
||||
|
||||
enum aie2_dev_status dev_status;
|
||||
u32 hwctx_num;
|
||||
|
||||
struct amdxdna_async_error last_async_err;
|
||||
};
|
||||
|
||||
#define DEFINE_BAR_OFFSET(reg_name, bar, reg_addr) \
|
||||
[reg_name] = {bar##_BAR_INDEX, (reg_addr) - bar##_BAR_BASE}
|
||||
|
||||
struct aie2_bar_off_pair {
|
||||
int bar_idx;
|
||||
u32 offset;
|
||||
enum aie2_tdr_status tdr_status;
|
||||
};
|
||||
|
||||
struct aie2_hw_ops {
|
||||
int (*set_dpm)(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
|
||||
int (*update_counters)(struct amdxdna_dev_hdl *ndev);
|
||||
};
|
||||
|
||||
#define aie2_update_counters(ndev) \
|
||||
({ \
|
||||
typeof(ndev) _ndev = ndev; \
|
||||
if (_ndev->priv->hw_ops->update_counters) \
|
||||
_ndev->priv->hw_ops->update_counters(_ndev); \
|
||||
})
|
||||
|
||||
enum aie2_fw_feature {
|
||||
AIE2_NPU_COMMAND,
|
||||
AIE2_PREEMPT,
|
||||
AIE2_TEMPORAL_ONLY,
|
||||
AIE2_APP_HEALTH,
|
||||
AIE2_ADD_HOST_BUFFER,
|
||||
AIE2_UPDATE_PROPERTY,
|
||||
AIE2_GET_DEV_REVISION,
|
||||
AIE2_FEATURE_MAX
|
||||
};
|
||||
|
||||
struct aie2_fw_feature_tbl {
|
||||
u64 features;
|
||||
u32 major;
|
||||
u32 max_minor;
|
||||
u32 min_minor;
|
||||
};
|
||||
|
||||
#define AIE2_ALL_FEATURES GENMASK_ULL(AIE2_FEATURE_MAX - 1, AIE2_NPU_COMMAND)
|
||||
#define AIE2_FEATURE_ON(ndev, feature) test_bit(feature, &(ndev)->feature_mask)
|
||||
|
||||
struct amdxdna_dev_priv {
|
||||
const char *fw_path;
|
||||
const struct rt_config *rt_config;
|
||||
const struct dpm_clk_freq *dpm_clk_tbl;
|
||||
const struct aie2_fw_feature_tbl *fw_feature_tbl;
|
||||
|
||||
#define COL_ALIGN_NONE 0
|
||||
#define COL_ALIGN_NATURE 1
|
||||
u32 col_align;
|
||||
u32 col_opc;
|
||||
u32 mbox_dev_addr;
|
||||
/* If mbox_size is 0, use BAR size. See MBOX_SIZE macro */
|
||||
u32 mbox_size;
|
||||
u32 hwctx_limit;
|
||||
u32 sram_dev_addr;
|
||||
struct aie2_bar_off_pair sram_offs[SRAM_MAX_INDEX];
|
||||
struct aie2_bar_off_pair psp_regs_off[PSP_MAX_REGS];
|
||||
struct aie2_bar_off_pair smu_regs_off[SMU_MAX_REGS];
|
||||
struct aie2_hw_ops hw_ops;
|
||||
struct aie_bar_off_pair sram_offs[SRAM_MAX_INDEX];
|
||||
struct aie_bar_off_pair psp_regs_off[PSP_MAX_REGS];
|
||||
struct aie_bar_off_pair smu_regs_off[SMU_MAX_REGS];
|
||||
const struct aie2_hw_ops *hw_ops;
|
||||
};
|
||||
|
||||
extern const struct amdxdna_dev_ops aie2_ops;
|
||||
@@ -306,25 +237,15 @@ extern const struct dpm_clk_freq npu1_dpm_clk_table[];
|
||||
extern const struct dpm_clk_freq npu4_dpm_clk_table[];
|
||||
extern const struct rt_config npu1_default_rt_cfg[];
|
||||
extern const struct rt_config npu4_default_rt_cfg[];
|
||||
extern const struct aie2_fw_feature_tbl npu4_fw_feature_table[];
|
||||
|
||||
/* aie2_smu.c */
|
||||
int aie2_smu_init(struct amdxdna_dev_hdl *ndev);
|
||||
void aie2_smu_fini(struct amdxdna_dev_hdl *ndev);
|
||||
int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
|
||||
int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
|
||||
extern const struct amdxdna_fw_feature_tbl npu4_fw_feature_table[];
|
||||
extern const struct amdxdna_rev_vbnv npu4_rev_vbnv_tbl[];
|
||||
extern const struct aie2_hw_ops npu4_hw_ops;
|
||||
|
||||
/* aie2_pm.c */
|
||||
int aie2_pm_init(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target);
|
||||
int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level);
|
||||
|
||||
/* aie2_psp.c */
|
||||
struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf);
|
||||
int aie2_psp_start(struct psp_device *psp);
|
||||
void aie2_psp_stop(struct psp_device *psp);
|
||||
int aie2_psp_waitmode_poll(struct psp_device *psp);
|
||||
|
||||
/* aie2_error.c */
|
||||
int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev);
|
||||
void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev);
|
||||
@@ -340,15 +261,19 @@ int aie2_resume_fw(struct amdxdna_dev_hdl *ndev);
|
||||
int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value);
|
||||
int aie2_get_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 *value);
|
||||
int aie2_assign_mgmt_pasid(struct amdxdna_dev_hdl *ndev, u16 pasid);
|
||||
int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev, struct aie_version *version);
|
||||
int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev, struct aie_metadata *metadata);
|
||||
int aie2_query_aie_version(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_drm_query_aie_version *version);
|
||||
int aie2_query_aie_metadata(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_drm_query_aie_metadata *metadata);
|
||||
int aie2_query_firmware_version(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_fw_ver *fw_ver);
|
||||
int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id,
|
||||
struct app_health_report *report);
|
||||
int aie2_get_dev_revision(struct amdxdna_dev_hdl *ndev, enum aie2_dev_revision *rev);
|
||||
int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx);
|
||||
int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwctx);
|
||||
int aie2_map_host_buf(struct amdxdna_dev_hdl *ndev, u32 context_id, u64 addr, u64 size);
|
||||
int aie2_add_host_buf(struct amdxdna_dev_hdl *ndev, u32 context_id, u64 addr, u64 size);
|
||||
int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf, u32 size, u32 *cols_filled);
|
||||
int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev,
|
||||
char __user *buf, u32 size,
|
||||
@@ -369,10 +294,7 @@ int aie2_sync_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
|
||||
int (*notify_cb)(void *, void __iomem *, size_t));
|
||||
int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job,
|
||||
int (*notify_cb)(void *, void __iomem *, size_t));
|
||||
void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size,
|
||||
dma_addr_t *dma_addr);
|
||||
void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_addr);
|
||||
int aie2_update_prop_time_quota(struct amdxdna_dev_hdl *ndev, u32 us);
|
||||
|
||||
/* aie2_hwctx.c */
|
||||
int aie2_hwctx_init(struct amdxdna_hwctx *hwctx);
|
||||
@@ -383,5 +305,6 @@ void aie2_hwctx_suspend(struct amdxdna_client *client);
|
||||
int aie2_hwctx_resume(struct amdxdna_client *client);
|
||||
int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, u64 *seq);
|
||||
void aie2_hmm_invalidate(struct amdxdna_gem_obj *abo, unsigned long cur_seq);
|
||||
int aie2_hwctx_heap_expand(struct amdxdna_hwctx *hwctx, struct amdxdna_gem_obj *heap);
|
||||
|
||||
#endif /* _AIE2_PCI_H_ */
|
||||
|
||||
@@ -31,14 +31,14 @@ int aie2_pm_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = amdxdna_pm_resume_get_locked(ndev->xdna);
|
||||
ret = amdxdna_pm_resume_get_locked(ndev->aie.xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ndev->priv->hw_ops.set_dpm(ndev, dpm_level);
|
||||
ret = ndev->priv->hw_ops->set_dpm(ndev, dpm_level);
|
||||
if (!ret)
|
||||
ndev->dpm_level = dpm_level;
|
||||
amdxdna_pm_suspend_put(ndev->xdna);
|
||||
amdxdna_pm_suspend_put(ndev->aie.xdna);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev)
|
||||
|
||||
if (ndev->dev_status != AIE2_DEV_UNINIT) {
|
||||
/* Resume device */
|
||||
ret = ndev->priv->hw_ops.set_dpm(ndev, ndev->dpm_level);
|
||||
ret = ndev->priv->hw_ops->set_dpm(ndev, ndev->dpm_level);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -64,7 +64,7 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev)
|
||||
ndev->max_dpm_level++;
|
||||
ndev->max_dpm_level--;
|
||||
|
||||
ret = ndev->priv->hw_ops.set_dpm(ndev, ndev->max_dpm_level);
|
||||
ret = ndev->priv->hw_ops->set_dpm(ndev, ndev->max_dpm_level);
|
||||
if (ret)
|
||||
return ret;
|
||||
ndev->dpm_level = ndev->max_dpm_level;
|
||||
@@ -74,14 +74,14 @@ int aie2_pm_init(struct amdxdna_dev_hdl *ndev)
|
||||
return ret;
|
||||
|
||||
ndev->pw_mode = POWER_MODE_DEFAULT;
|
||||
ndev->dft_dpm_level = ndev->max_dpm_level;
|
||||
ndev->dft_dpm_level = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type target)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->xdna;
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
u32 clk_gating, dpm_level;
|
||||
int ret;
|
||||
|
||||
@@ -108,6 +108,14 @@ int aie2_pm_set_mode(struct amdxdna_dev_hdl *ndev, enum amdxdna_power_mode_type
|
||||
clk_gating = AIE2_CLK_GATING_ENABLE;
|
||||
dpm_level = ndev->dft_dpm_level;
|
||||
break;
|
||||
case POWER_MODE_LOW:
|
||||
clk_gating = AIE2_CLK_GATING_ENABLE;
|
||||
dpm_level = 0;
|
||||
break;
|
||||
case POWER_MODE_MEDIUM:
|
||||
clk_gating = AIE2_CLK_GATING_ENABLE;
|
||||
dpm_level = ndev->max_dpm_level / 2;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "aie2_pci.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
#define PSP_STATUS_READY BIT(31)
|
||||
|
||||
/* PSP commands */
|
||||
#define PSP_VALIDATE 1
|
||||
#define PSP_START 2
|
||||
#define PSP_RELEASE_TMR 3
|
||||
|
||||
/* PSP special arguments */
|
||||
#define PSP_START_COPY_FW 1
|
||||
|
||||
/* PSP response error code */
|
||||
#define PSP_ERROR_CANCEL 0xFFFF0002
|
||||
#define PSP_ERROR_BAD_STATE 0xFFFF0007
|
||||
|
||||
#define PSP_FW_ALIGN 0x10000
|
||||
#define PSP_POLL_INTERVAL 20000 /* us */
|
||||
#define PSP_POLL_TIMEOUT 1000000 /* us */
|
||||
|
||||
#define PSP_REG(p, reg) ((p)->psp_regs[reg])
|
||||
|
||||
struct psp_device {
|
||||
struct drm_device *ddev;
|
||||
struct psp_config conf;
|
||||
u32 fw_buf_sz;
|
||||
u64 fw_paddr;
|
||||
void *fw_buffer;
|
||||
void __iomem *psp_regs[PSP_MAX_REGS];
|
||||
};
|
||||
|
||||
static int psp_exec(struct psp_device *psp, u32 *reg_vals)
|
||||
{
|
||||
u32 resp_code;
|
||||
int ret, i;
|
||||
u32 ready;
|
||||
|
||||
/* Write command and argument registers */
|
||||
for (i = 0; i < PSP_NUM_IN_REGS; i++)
|
||||
writel(reg_vals[i], PSP_REG(psp, i));
|
||||
|
||||
/* clear and set PSP INTR register to kick off */
|
||||
writel(0, PSP_REG(psp, PSP_INTR_REG));
|
||||
writel(1, PSP_REG(psp, PSP_INTR_REG));
|
||||
|
||||
/* PSP should be busy. Wait for ready, so we know task is done. */
|
||||
ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready,
|
||||
FIELD_GET(PSP_STATUS_READY, ready),
|
||||
PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
|
||||
if (ret) {
|
||||
drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
resp_code = readl(PSP_REG(psp, PSP_RESP_REG));
|
||||
if (resp_code) {
|
||||
drm_err(psp->ddev, "fw return error 0x%x", resp_code);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie2_psp_waitmode_poll(struct psp_device *psp)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(psp->ddev);
|
||||
u32 mode_reg;
|
||||
int ret;
|
||||
|
||||
ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_PWAITMODE_REG), mode_reg,
|
||||
(mode_reg & 0x1) == 1,
|
||||
PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "fw waitmode reg error, ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void aie2_psp_stop(struct psp_device *psp)
|
||||
{
|
||||
u32 reg_vals[PSP_NUM_IN_REGS] = { PSP_RELEASE_TMR, };
|
||||
int ret;
|
||||
|
||||
ret = psp_exec(psp, reg_vals);
|
||||
if (ret)
|
||||
drm_err(psp->ddev, "release tmr failed, ret %d", ret);
|
||||
}
|
||||
|
||||
int aie2_psp_start(struct psp_device *psp)
|
||||
{
|
||||
u32 reg_vals[PSP_NUM_IN_REGS];
|
||||
int ret;
|
||||
|
||||
reg_vals[0] = PSP_VALIDATE;
|
||||
reg_vals[1] = lower_32_bits(psp->fw_paddr);
|
||||
reg_vals[2] = upper_32_bits(psp->fw_paddr);
|
||||
reg_vals[3] = psp->fw_buf_sz;
|
||||
|
||||
ret = psp_exec(psp, reg_vals);
|
||||
if (ret) {
|
||||
drm_err(psp->ddev, "failed to validate fw, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(reg_vals, 0, sizeof(reg_vals));
|
||||
reg_vals[0] = PSP_START;
|
||||
reg_vals[1] = PSP_START_COPY_FW;
|
||||
ret = psp_exec(psp, reg_vals);
|
||||
if (ret) {
|
||||
drm_err(psp->ddev, "failed to start fw, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct psp_device *aie2m_psp_create(struct drm_device *ddev, struct psp_config *conf)
|
||||
{
|
||||
struct psp_device *psp;
|
||||
u64 offset;
|
||||
|
||||
psp = drmm_kzalloc(ddev, sizeof(*psp), GFP_KERNEL);
|
||||
if (!psp)
|
||||
return NULL;
|
||||
|
||||
psp->ddev = ddev;
|
||||
memcpy(psp->psp_regs, conf->psp_regs, sizeof(psp->psp_regs));
|
||||
|
||||
psp->fw_buf_sz = ALIGN(conf->fw_size, PSP_FW_ALIGN);
|
||||
psp->fw_buffer = drmm_kmalloc(ddev, psp->fw_buf_sz + PSP_FW_ALIGN, GFP_KERNEL);
|
||||
if (!psp->fw_buffer) {
|
||||
drm_err(ddev, "no memory for fw buffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* AMD Platform Security Processor(PSP) requires host physical
|
||||
* address to load NPU firmware.
|
||||
*/
|
||||
psp->fw_paddr = virt_to_phys(psp->fw_buffer);
|
||||
offset = ALIGN(psp->fw_paddr, PSP_FW_ALIGN) - psp->fw_paddr;
|
||||
psp->fw_paddr += offset;
|
||||
memcpy(psp->fw_buffer + offset, conf->fw_buf, conf->fw_size);
|
||||
|
||||
return psp;
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2022-2024, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "aie2_pci.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
#define SMU_RESULT_OK 1
|
||||
|
||||
/* SMU commands */
|
||||
#define AIE2_SMU_POWER_ON 0x3
|
||||
#define AIE2_SMU_POWER_OFF 0x4
|
||||
#define AIE2_SMU_SET_MPNPUCLK_FREQ 0x5
|
||||
#define AIE2_SMU_SET_HCLK_FREQ 0x6
|
||||
#define AIE2_SMU_SET_SOFT_DPMLEVEL 0x7
|
||||
#define AIE2_SMU_SET_HARD_DPMLEVEL 0x8
|
||||
|
||||
#define NPU4_DPM_TOPS(ndev, dpm_level) \
|
||||
({ \
|
||||
typeof(ndev) _ndev = ndev; \
|
||||
(4096 * (_ndev)->total_col * \
|
||||
(_ndev)->priv->dpm_clk_tbl[dpm_level].hclk / 1000000); \
|
||||
})
|
||||
|
||||
static int aie2_smu_exec(struct amdxdna_dev_hdl *ndev, u32 reg_cmd,
|
||||
u32 reg_arg, u32 *out)
|
||||
{
|
||||
u32 resp;
|
||||
int ret;
|
||||
|
||||
writel(0, SMU_REG(ndev, SMU_RESP_REG));
|
||||
writel(reg_arg, SMU_REG(ndev, SMU_ARG_REG));
|
||||
writel(reg_cmd, SMU_REG(ndev, SMU_CMD_REG));
|
||||
|
||||
/* Clear and set SMU_INTR_REG to kick off */
|
||||
writel(0, SMU_REG(ndev, SMU_INTR_REG));
|
||||
writel(1, SMU_REG(ndev, SMU_INTR_REG));
|
||||
|
||||
ret = readx_poll_timeout(readl, SMU_REG(ndev, SMU_RESP_REG), resp,
|
||||
resp, AIE2_INTERVAL, AIE2_TIMEOUT);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "smu cmd %d timed out", reg_cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (out)
|
||||
*out = readl(SMU_REG(ndev, SMU_OUT_REG));
|
||||
|
||||
if (resp != SMU_RESULT_OK) {
|
||||
XDNA_ERR(ndev->xdna, "smu cmd %d failed, 0x%x", reg_cmd, resp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int npu1_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
|
||||
{
|
||||
u32 freq;
|
||||
int ret;
|
||||
|
||||
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_MPNPUCLK_FREQ,
|
||||
ndev->priv->dpm_clk_tbl[dpm_level].npuclk, &freq);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Set npu clock to %d failed, ret %d\n",
|
||||
ndev->priv->dpm_clk_tbl[dpm_level].npuclk, ret);
|
||||
return ret;
|
||||
}
|
||||
ndev->npuclk_freq = freq;
|
||||
|
||||
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HCLK_FREQ,
|
||||
ndev->priv->dpm_clk_tbl[dpm_level].hclk, &freq);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Set h clock to %d failed, ret %d\n",
|
||||
ndev->priv->dpm_clk_tbl[dpm_level].hclk, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ndev->hclk_freq = freq;
|
||||
ndev->max_tops = 2 * ndev->total_col;
|
||||
ndev->curr_tops = ndev->max_tops * freq / 1028;
|
||||
|
||||
XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
|
||||
ndev->npuclk_freq, ndev->hclk_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int npu4_set_dpm(struct amdxdna_dev_hdl *ndev, u32 dpm_level)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Set hard dpm level %d failed, ret %d ",
|
||||
dpm_level, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_smu_exec(ndev, AIE2_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Set soft dpm level %d failed, ret %d",
|
||||
dpm_level, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ndev->npuclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].npuclk;
|
||||
ndev->hclk_freq = ndev->priv->dpm_clk_tbl[dpm_level].hclk;
|
||||
ndev->max_tops = NPU4_DPM_TOPS(ndev, ndev->max_dpm_level);
|
||||
ndev->curr_tops = NPU4_DPM_TOPS(ndev, dpm_level);
|
||||
|
||||
XDNA_DBG(ndev->xdna, "MP-NPU clock %d, H clock %d\n",
|
||||
ndev->npuclk_freq, ndev->hclk_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie2_smu_init(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Failing to set power off indicates an unrecoverable hardware or
|
||||
* firmware error.
|
||||
*/
|
||||
ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Access power failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_ON, 0, NULL);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->xdna, "Power on failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void aie2_smu_fini(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ndev->priv->hw_ops.set_dpm(ndev, 0);
|
||||
ret = aie2_smu_exec(ndev, AIE2_SMU_POWER_OFF, 0, NULL);
|
||||
if (ret)
|
||||
XDNA_ERR(ndev->xdna, "Power off failed, ret %d", ret);
|
||||
}
|
||||
@@ -52,7 +52,7 @@ static u32 calculate_gops(struct aie_qos *rqos)
|
||||
u32 service_rate = 0;
|
||||
|
||||
if (rqos->latency)
|
||||
service_rate = (1000 / rqos->latency);
|
||||
service_rate = max_t(u32, 1000 / rqos->latency, 1);
|
||||
|
||||
if (rqos->fps > service_rate)
|
||||
return rqos->fps * rqos->gops;
|
||||
@@ -348,6 +348,7 @@ int xrs_release_resource(void *hdl, u64 rid)
|
||||
{
|
||||
struct solver_state *xrs = hdl;
|
||||
struct solver_node *node;
|
||||
u32 level = 0;
|
||||
|
||||
node = rg_search_node(&xrs->rgp, rid);
|
||||
if (!node) {
|
||||
@@ -358,6 +359,13 @@ int xrs_release_resource(void *hdl, u64 rid)
|
||||
xrs->cfg.actions->unload(node->cb_arg);
|
||||
remove_solver_node(&xrs->rgp, node);
|
||||
|
||||
/* set the dpm level which fits all the sessions */
|
||||
list_for_each_entry(node, &xrs->rgp.node_list, list) {
|
||||
if (node->dpm_level > level)
|
||||
level = node->dpm_level;
|
||||
}
|
||||
xrs->cfg.actions->set_dft_dpm_level(xrs->cfg.ddev, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
333
drivers/accel/amdxdna/aie4_ctx.c
Normal file
333
drivers/accel/amdxdna/aie4_ctx.c
Normal file
@@ -0,0 +1,333 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/amdxdna_accel.h>
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_gem.h>
|
||||
#include <drm/drm_gem_shmem_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "aie4_host_queue.h"
|
||||
#include "aie4_msg_priv.h"
|
||||
#include "aie4_pci.h"
|
||||
#include "amdxdna_ctx.h"
|
||||
#include "amdxdna_gem.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_mailbox_helper.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
static irqreturn_t cert_comp_isr(int irq, void *p)
|
||||
{
|
||||
struct cert_comp *cert_comp = p;
|
||||
|
||||
wake_up_all(&cert_comp->waitq);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct cert_comp *aie4_lookup_cert_comp(struct amdxdna_dev_hdl *ndev, u32 msix_idx)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
struct cert_comp *cert_comp;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&ndev->cert_comp_lock);
|
||||
|
||||
cert_comp = xa_load(&ndev->cert_comp_xa, msix_idx);
|
||||
if (cert_comp) {
|
||||
kref_get(&cert_comp->kref);
|
||||
return cert_comp;
|
||||
}
|
||||
|
||||
cert_comp = kzalloc_obj(*cert_comp);
|
||||
if (!cert_comp)
|
||||
return NULL;
|
||||
|
||||
cert_comp->ndev = ndev;
|
||||
cert_comp->msix_idx = msix_idx;
|
||||
init_waitqueue_head(&cert_comp->waitq);
|
||||
kref_init(&cert_comp->kref);
|
||||
|
||||
ret = pci_irq_vector(pdev, cert_comp->msix_idx);
|
||||
if (ret < 0) {
|
||||
XDNA_ERR(xdna, "MSI-X idx %u is invalid, ret:%d", msix_idx, ret);
|
||||
goto free_cert_comp;
|
||||
}
|
||||
cert_comp->irq = ret;
|
||||
|
||||
ret = request_irq(cert_comp->irq, cert_comp_isr, 0, "xdna_hsa", cert_comp);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "request irq %d failed %d", cert_comp->irq, ret);
|
||||
goto free_cert_comp;
|
||||
}
|
||||
|
||||
ret = xa_err(xa_store(&ndev->cert_comp_xa, msix_idx, cert_comp, GFP_KERNEL));
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "store cert_comp for msix idx %d failed %d", msix_idx, ret);
|
||||
goto free_irq;
|
||||
}
|
||||
|
||||
return cert_comp;
|
||||
|
||||
free_irq:
|
||||
free_irq(cert_comp->irq, cert_comp);
|
||||
free_cert_comp:
|
||||
kfree(cert_comp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cert_comp_release(struct kref *kref)
|
||||
{
|
||||
struct cert_comp *cert_comp = container_of(kref, struct cert_comp, kref);
|
||||
struct amdxdna_dev_hdl *ndev = cert_comp->ndev;
|
||||
|
||||
drm_WARN_ON(&ndev->aie.xdna->ddev, !mutex_is_locked(&ndev->cert_comp_lock));
|
||||
|
||||
xa_erase(&ndev->cert_comp_xa, cert_comp->msix_idx);
|
||||
free_irq(cert_comp->irq, cert_comp);
|
||||
kfree(cert_comp);
|
||||
}
|
||||
|
||||
static void aie4_put_cert_comp(struct cert_comp *cert_comp)
|
||||
{
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
|
||||
ndev = cert_comp->ndev;
|
||||
guard(mutex)(&ndev->cert_comp_lock);
|
||||
kref_put(&cert_comp->kref, cert_comp_release);
|
||||
}
|
||||
|
||||
static int aie4_msg_destroy_context(struct amdxdna_dev_hdl *ndev, u32 hw_context_id)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_destroy_hw_context, AIE4_MSG_OP_DESTROY_HW_CONTEXT);
|
||||
|
||||
req.hw_context_id = hw_context_id;
|
||||
return aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
}
|
||||
|
||||
static int aie4_hwctx_create(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_create_hw_context, AIE4_MSG_OP_CREATE_HW_CONTEXT);
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_hwctx_priv *priv = hwctx->priv;
|
||||
struct amdxdna_dev *xdna = hwctx->client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
int ret;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
if (!ndev->partition_id || !hwctx->num_tiles) {
|
||||
XDNA_ERR(xdna, "invalid request partition_id %d, num_tiles %d",
|
||||
ndev->partition_id, hwctx->num_tiles);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
req.partition_id = ndev->partition_id;
|
||||
req.request_num_tiles = hwctx->num_tiles;
|
||||
req.pasid = FIELD_PREP(AIE4_MSG_PASID, client->pasid) |
|
||||
FIELD_PREP(AIE4_MSG_PASID_VLD, 1);
|
||||
req.priority_band = hwctx->qos.priority;
|
||||
|
||||
req.hsa_addr_high = upper_32_bits(amdxdna_gem_dev_addr(priv->umq_bo));
|
||||
req.hsa_addr_low = lower_32_bits(amdxdna_gem_dev_addr(priv->umq_bo));
|
||||
|
||||
XDNA_DBG(xdna, "pasid 0x%x, num_tiles %d, hsa[0x%x 0x%x]",
|
||||
req.pasid, req.request_num_tiles, req.hsa_addr_high, req.hsa_addr_low);
|
||||
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "create ctx failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
XDNA_DBG(xdna, "resp msix: %d, ctx id: %d, doorbell: %d",
|
||||
resp.job_complete_msix_idx,
|
||||
resp.hw_context_id,
|
||||
resp.doorbell_offset);
|
||||
|
||||
/* setup interrupt completion per msix index */
|
||||
priv->cert_comp = aie4_lookup_cert_comp(ndev, resp.job_complete_msix_idx);
|
||||
if (!priv->cert_comp) {
|
||||
aie4_msg_destroy_context(ndev, resp.hw_context_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->hw_ctx_id = resp.hw_context_id;
|
||||
hwctx->doorbell_offset = resp.doorbell_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aie4_hwctx_destroy(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_hwctx_priv *priv = hwctx->priv;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
aie4_msg_destroy_context(ndev, priv->hw_ctx_id);
|
||||
aie4_put_cert_comp(priv->cert_comp);
|
||||
}
|
||||
|
||||
static void aie4_hwctx_umq_fini(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
if (hwctx->priv && hwctx->priv->umq_bo)
|
||||
amdxdna_gem_put_obj(hwctx->priv->umq_bo);
|
||||
}
|
||||
|
||||
static int aie4_hwctx_umq_init(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_hwctx_priv *priv = hwctx->priv;
|
||||
struct amdxdna_dev *xdna = hwctx->client->xdna;
|
||||
struct amdxdna_gem_obj *umq_bo;
|
||||
struct host_queue_header *qhdr;
|
||||
int ret;
|
||||
|
||||
umq_bo = amdxdna_gem_get_obj(hwctx->client, hwctx->umq_bo_hdl, AMDXDNA_BO_SHARE);
|
||||
if (!umq_bo) {
|
||||
XDNA_ERR(xdna, "cannot find umq_bo handle %d", hwctx->umq_bo_hdl);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (umq_bo->mem.size < sizeof(*qhdr)) {
|
||||
XDNA_ERR(xdna, "umq_bo size is too small");
|
||||
ret = -EINVAL;
|
||||
goto put_umq_bo;
|
||||
}
|
||||
|
||||
/* get kva address for host queue read index and write index */
|
||||
qhdr = amdxdna_gem_vmap(umq_bo);
|
||||
if (!qhdr) {
|
||||
ret = -ENOMEM;
|
||||
goto put_umq_bo;
|
||||
}
|
||||
|
||||
priv->umq_bo = umq_bo;
|
||||
priv->umq_read_index = &qhdr->read_index;
|
||||
priv->umq_write_index = &qhdr->write_index;
|
||||
|
||||
return 0;
|
||||
|
||||
put_umq_bo:
|
||||
amdxdna_gem_put_obj(umq_bo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aie4_hwctx_init(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_hwctx_priv *priv;
|
||||
int ret;
|
||||
|
||||
priv = kzalloc_obj(*priv);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
hwctx->priv = priv;
|
||||
|
||||
ret = aie4_hwctx_umq_init(hwctx);
|
||||
if (ret)
|
||||
goto free_priv;
|
||||
|
||||
ret = aie4_hwctx_create(hwctx);
|
||||
if (ret)
|
||||
goto umq_fini;
|
||||
|
||||
XDNA_DBG(xdna, "hwctx %s init completed", hwctx->name);
|
||||
return 0;
|
||||
|
||||
umq_fini:
|
||||
aie4_hwctx_umq_fini(hwctx);
|
||||
free_priv:
|
||||
kfree(priv);
|
||||
hwctx->priv = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
aie4_hwctx_destroy(hwctx);
|
||||
aie4_hwctx_umq_fini(hwctx);
|
||||
kfree(hwctx->priv);
|
||||
}
|
||||
|
||||
static inline bool valid_queue_index(u64 read, u64 write, u32 capacity)
|
||||
{
|
||||
return (write >= read) && ((write - read) <= capacity);
|
||||
}
|
||||
|
||||
static u64 get_read_index(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
u64 wi = READ_ONCE(*hwctx->priv->umq_write_index);
|
||||
u64 ri = READ_ONCE(*hwctx->priv->umq_read_index);
|
||||
struct amdxdna_dev *xdna = hwctx->client->xdna;
|
||||
|
||||
/*
|
||||
* CERT cannot update read index as uint64 atomically. Driver may read
|
||||
* half-updated read index when it has bits in high 32bit. In case read
|
||||
* index is not valid, wait for some time and retry once. It should
|
||||
* allow CERT to complete the read index update.
|
||||
*/
|
||||
if (!valid_queue_index(ri, wi, CTX_MAX_CMDS)) {
|
||||
XDNA_WARN(xdna, "Invalid index, ri %llu, wi %llu", ri, wi);
|
||||
usleep_range(100, 200);
|
||||
ri = READ_ONCE(*hwctx->priv->umq_read_index);
|
||||
if (!valid_queue_index(ri, wi, CTX_MAX_CMDS)) {
|
||||
XDNA_ERR(xdna, "Invalid index after retry, ri %llu, wi %llu", ri, wi);
|
||||
ri = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
static inline bool check_cmd_done(struct amdxdna_hwctx *hwctx, u64 seq)
|
||||
{
|
||||
u64 read_idx = get_read_index(hwctx);
|
||||
|
||||
return read_idx > seq;
|
||||
}
|
||||
|
||||
int aie4_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout)
|
||||
{
|
||||
unsigned long wait_jifs = MAX_SCHEDULE_TIMEOUT;
|
||||
struct amdxdna_hwctx_priv *priv = hwctx->priv;
|
||||
struct cert_comp *cert_comp = priv->cert_comp;
|
||||
long ret;
|
||||
|
||||
if (timeout)
|
||||
wait_jifs = msecs_to_jiffies(timeout);
|
||||
|
||||
ret = wait_event_interruptible_timeout(cert_comp->waitq,
|
||||
(check_cmd_done(hwctx, seq)),
|
||||
wait_jifs);
|
||||
|
||||
if (!ret)
|
||||
ret = -ETIME;
|
||||
|
||||
return ret <= 0 ? ret : 0;
|
||||
}
|
||||
|
||||
int aie4_hwctx_valid_doorbell(struct amdxdna_client *client, u32 vm_pgoff)
|
||||
{
|
||||
struct amdxdna_hwctx *hwctx;
|
||||
unsigned long hwctx_id;
|
||||
int idx;
|
||||
|
||||
idx = srcu_read_lock(&client->hwctx_srcu);
|
||||
amdxdna_for_each_hwctx(client, hwctx_id, hwctx) {
|
||||
if (vm_pgoff == (hwctx->doorbell_offset >> PAGE_SHIFT)) {
|
||||
srcu_read_unlock(&client->hwctx_srcu, idx);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
srcu_read_unlock(&client->hwctx_srcu, idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
24
drivers/accel/amdxdna/aie4_host_queue.h
Normal file
24
drivers/accel/amdxdna/aie4_host_queue.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _AIE4_HOST_QUEUE_H_
|
||||
#define _AIE4_HOST_QUEUE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define CTX_MAX_CMDS 32
|
||||
|
||||
struct host_queue_header {
|
||||
__u64 read_index;
|
||||
struct {
|
||||
__u16 major;
|
||||
__u16 minor;
|
||||
} version;
|
||||
__u32 capacity; /* Queue capacity, must be power of two. */
|
||||
__u64 write_index;
|
||||
__u64 data_address; /* The xdna dev addr for payload. */
|
||||
};
|
||||
|
||||
#endif /* _AIE4_HOST_QUEUE_H_ */
|
||||
83
drivers/accel/amdxdna/aie4_message.c
Normal file
83
drivers/accel/amdxdna/aie4_message.c
Normal file
@@ -0,0 +1,83 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/amdxdna_accel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "aie4_msg_priv.h"
|
||||
#include "aie4_pci.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_mailbox_helper.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_suspend, AIE4_MSG_OP_SUSPEND);
|
||||
int ret;
|
||||
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
XDNA_ERR(ndev->aie.xdna, "Failed to suspend fw, ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aie4_query_aie_metadata(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_drm_query_aie_metadata *metadata)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_aie4_tile_info, AIE4_MSG_OP_AIE_TILE_INFO);
|
||||
int ret;
|
||||
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
metadata->col_size = resp.info.size;
|
||||
metadata->cols = resp.info.cols;
|
||||
metadata->rows = resp.info.rows;
|
||||
|
||||
metadata->version.major = resp.info.major;
|
||||
metadata->version.minor = resp.info.minor;
|
||||
|
||||
metadata->core.row_count = resp.info.core_rows;
|
||||
metadata->core.row_start = resp.info.core_row_start;
|
||||
metadata->core.dma_channel_count = resp.info.core_dma_channels;
|
||||
metadata->core.lock_count = resp.info.core_locks;
|
||||
metadata->core.event_reg_count = resp.info.core_events;
|
||||
|
||||
metadata->mem.row_count = resp.info.mem_rows;
|
||||
metadata->mem.row_start = resp.info.mem_row_start;
|
||||
metadata->mem.dma_channel_count = resp.info.mem_dma_channels;
|
||||
metadata->mem.lock_count = resp.info.mem_locks;
|
||||
metadata->mem.event_reg_count = resp.info.mem_events;
|
||||
|
||||
metadata->shim.row_count = resp.info.shim_rows;
|
||||
metadata->shim.row_start = resp.info.shim_row_start;
|
||||
metadata->shim.dma_channel_count = resp.info.shim_dma_channels;
|
||||
metadata->shim.lock_count = resp.info.shim_locks;
|
||||
metadata->shim.event_reg_count = resp.info.shim_events;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie4_attach_work_buffer(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_attach_work_buffer, AIE4_MSG_OP_ATTACH_WORK_BUFFER);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
req.buff_addr = ndev->work_buf_addr;
|
||||
req.buff_size = AIE4_WORK_BUFFER_MIN_SIZE;
|
||||
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "Failed to attach work buffer, ret %d", ret);
|
||||
else
|
||||
XDNA_DBG(xdna, "Attached work buffer");
|
||||
|
||||
return ret;
|
||||
}
|
||||
147
drivers/accel/amdxdna/aie4_msg_priv.h
Normal file
147
drivers/accel/amdxdna/aie4_msg_priv.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _AIE4_MSG_PRIV_H_
|
||||
#define _AIE4_MSG_PRIV_H_
|
||||
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
enum aie4_msg_opcode {
|
||||
AIE4_MSG_OP_SUSPEND = 0x10003,
|
||||
AIE4_MSG_OP_ATTACH_WORK_BUFFER = 0x1000D,
|
||||
|
||||
AIE4_MSG_OP_CREATE_VFS = 0x20001,
|
||||
AIE4_MSG_OP_DESTROY_VFS = 0x20002,
|
||||
|
||||
AIE4_MSG_OP_CREATE_PARTITION = 0x30001,
|
||||
AIE4_MSG_OP_DESTROY_PARTITION = 0x30002,
|
||||
AIE4_MSG_OP_CREATE_HW_CONTEXT = 0x30003,
|
||||
AIE4_MSG_OP_DESTROY_HW_CONTEXT = 0x30004,
|
||||
AIE4_MSG_OP_AIE_TILE_INFO = 0x30006,
|
||||
};
|
||||
|
||||
enum aie4_msg_status {
|
||||
AIE4_MSG_STATUS_SUCCESS = 0x0,
|
||||
AIE4_MSG_STATUS_ERROR = 0x1,
|
||||
AIE4_MSG_STATUS_NOTSUPP = 0x2,
|
||||
MAX_AIE4_MSG_STATUS_CODE = 0x4,
|
||||
};
|
||||
|
||||
struct aie4_msg_suspend_req {
|
||||
__u32 rsvd;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_suspend_resp {
|
||||
enum aie4_msg_status status;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_create_vfs_req {
|
||||
__u32 vf_cnt;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_create_vfs_resp {
|
||||
enum aie4_msg_status status;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_destroy_vfs_req {
|
||||
__u32 rsvd;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_destroy_vfs_resp {
|
||||
enum aie4_msg_status status;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_create_partition_req {
|
||||
__u32 partition_col_start;
|
||||
__u32 partition_col_count;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_create_partition_resp {
|
||||
enum aie4_msg_status status;
|
||||
__u32 partition_id;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_destroy_partition_req {
|
||||
__u32 partition_id;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_destroy_partition_resp {
|
||||
enum aie4_msg_status status;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_create_hw_context_req {
|
||||
__u32 partition_id;
|
||||
__u32 request_num_tiles;
|
||||
__u32 hsa_addr_high;
|
||||
__u32 hsa_addr_low;
|
||||
#define AIE4_MSG_PASID GENMASK(19, 0)
|
||||
#define AIE4_MSG_PASID_VLD GENMASK(31, 31)
|
||||
__u32 pasid;
|
||||
__u32 priority_band;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_create_hw_context_resp {
|
||||
enum aie4_msg_status status;
|
||||
__u32 hw_context_id;
|
||||
__u32 doorbell_offset;
|
||||
__u32 job_complete_msix_idx;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_destroy_hw_context_req {
|
||||
__u32 hw_context_id;
|
||||
__u32 resvd1;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_destroy_hw_context_resp {
|
||||
enum aie4_msg_status status;
|
||||
} __packed;
|
||||
|
||||
struct aie4_tile_info {
|
||||
__u32 size;
|
||||
__u16 major;
|
||||
__u16 minor;
|
||||
__u16 cols;
|
||||
__u16 rows;
|
||||
__u16 core_rows;
|
||||
__u16 mem_rows;
|
||||
__u16 shim_rows;
|
||||
__u16 core_row_start;
|
||||
__u16 mem_row_start;
|
||||
__u16 shim_row_start;
|
||||
__u16 core_dma_channels;
|
||||
__u16 mem_dma_channels;
|
||||
__u16 shim_dma_channels;
|
||||
__u16 core_locks;
|
||||
__u16 mem_locks;
|
||||
__u16 shim_locks;
|
||||
__u16 core_events;
|
||||
__u16 mem_events;
|
||||
__u16 shim_events;
|
||||
__u16 resvd;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_aie4_tile_info_req {
|
||||
__u32 resvd;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_aie4_tile_info_resp {
|
||||
enum aie4_msg_status status;
|
||||
struct aie4_tile_info info;
|
||||
} __packed;
|
||||
|
||||
#define AIE4_WORK_BUFFER_MIN_SIZE SZ_4M
|
||||
|
||||
struct aie4_msg_attach_work_buffer_req {
|
||||
__u64 buff_addr;
|
||||
__u32 reserved;
|
||||
__u32 buff_size;
|
||||
} __packed;
|
||||
|
||||
struct aie4_msg_attach_work_buffer_resp {
|
||||
enum aie4_msg_status status;
|
||||
} __packed;
|
||||
|
||||
#endif /* _AIE4_MSG_PRIV_H_ */
|
||||
667
drivers/accel/amdxdna/aie4_pci.c
Normal file
667
drivers/accel/amdxdna/aie4_pci.c
Normal file
@@ -0,0 +1,667 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/amdxdna_accel.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "aie4_msg_priv.h"
|
||||
#include "aie4_pci.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_mailbox_helper.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
#define NO_IOHUB 0
|
||||
#define PSP_NOTIFY_INTR 0xD007BE11
|
||||
#define AIE4_TOTAL_COLUMN 3
|
||||
|
||||
/*
|
||||
* The management mailbox channel is allocated by firmware.
|
||||
* The related register and ring buffer information is on SRAM BAR.
|
||||
* This struct is the register layout.
|
||||
*/
|
||||
struct mailbox_info {
|
||||
__u32 valid;
|
||||
__u32 protocol_major;
|
||||
__u32 protocol_minor;
|
||||
__u32 x2i_tail_offset;
|
||||
__u32 x2i_head_offset;
|
||||
__u32 x2i_buffer_addr;
|
||||
__u32 x2i_buffer_size;
|
||||
__u32 i2x_tail_offset;
|
||||
__u32 i2x_head_offset;
|
||||
__u32 i2x_buffer_addr;
|
||||
__u32 i2x_buffer_size;
|
||||
__u32 i2x_msi_idx;
|
||||
__u32 reserved[4];
|
||||
};
|
||||
|
||||
static int aie4_fw_is_alive(struct amdxdna_dev *xdna)
|
||||
{
|
||||
const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
u32 __iomem *src;
|
||||
u32 fw_is_valid;
|
||||
int ret;
|
||||
|
||||
src = ndev->rbuf_base + npriv->mbox_info_off;
|
||||
|
||||
ret = readx_poll_timeout(readl, src + offsetof(struct mailbox_info, valid),
|
||||
fw_is_valid, (fw_is_valid == 0x1),
|
||||
AIE_INTERVAL, AIE_TIMEOUT);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "fw_is_valid=%d after %d ms",
|
||||
fw_is_valid, DIV_ROUND_CLOSEST(AIE_TIMEOUT, 1000000));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aie4_read_mbox_info(struct amdxdna_dev *xdna,
|
||||
struct mailbox_info *mbox_info)
|
||||
{
|
||||
const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
u32 *dst = (u32 *)mbox_info;
|
||||
u32 __iomem *src;
|
||||
int i;
|
||||
|
||||
src = ndev->rbuf_base + npriv->mbox_info_off;
|
||||
|
||||
for (i = 0; i < sizeof(*mbox_info) / sizeof(u32); i++)
|
||||
dst[i] = readl(&src[i]);
|
||||
}
|
||||
|
||||
static int aie4_mailbox_info(struct amdxdna_dev *xdna,
|
||||
struct mailbox_info *mbox_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie4_fw_is_alive(xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
aie4_read_mbox_info(xdna, mbox_info);
|
||||
|
||||
ret = aie_check_protocol(&xdna->dev_handle->aie,
|
||||
mbox_info->protocol_major,
|
||||
mbox_info->protocol_minor);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "mailbox major.minor %d.%d is not supported",
|
||||
mbox_info->protocol_major, mbox_info->protocol_minor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aie4_mailbox_fini(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
|
||||
aie_destroy_chann(&ndev->aie, &ndev->aie.mgmt_chann);
|
||||
drmm_kfree(&xdna->ddev, ndev->mbox);
|
||||
ndev->mbox = NULL;
|
||||
}
|
||||
|
||||
static int aie4_irq_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
int ret, nvec;
|
||||
|
||||
nvec = pci_msix_vec_count(pdev);
|
||||
XDNA_DBG(xdna, "irq vectors:%d", nvec);
|
||||
if (nvec <= 0) {
|
||||
XDNA_ERR(xdna, "does not get number of interrupt vector");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX);
|
||||
if (ret < 0) {
|
||||
XDNA_ERR(xdna, "failed to alloc irq vector, ret: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aie4_mailbox_start(struct amdxdna_dev *xdna,
|
||||
struct mailbox_info *mbi)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
|
||||
struct xdna_mailbox_chann_res *i2x;
|
||||
struct xdna_mailbox_chann_res *x2i;
|
||||
int mgmt_mb_irq;
|
||||
int ret;
|
||||
|
||||
struct xdna_mailbox_res mbox_res = {
|
||||
.ringbuf_base = ndev->rbuf_base,
|
||||
.ringbuf_size = pci_resource_len(pdev, npriv->mbox_rbuf_bar),
|
||||
.mbox_base = ndev->mbox_base,
|
||||
.mbox_size = pci_resource_len(pdev, npriv->mbox_bar),
|
||||
.name = "xdna_aie4_mailbox",
|
||||
};
|
||||
|
||||
i2x = &ndev->aie.mgmt_i2x;
|
||||
x2i = &ndev->aie.mgmt_x2i;
|
||||
|
||||
x2i->mb_head_ptr_reg = mbi->x2i_head_offset;
|
||||
x2i->mb_tail_ptr_reg = mbi->x2i_tail_offset;
|
||||
x2i->rb_start_addr = mbi->x2i_buffer_addr;
|
||||
x2i->rb_size = mbi->x2i_buffer_size;
|
||||
|
||||
i2x->rb_start_addr = mbi->i2x_buffer_addr;
|
||||
i2x->rb_size = mbi->i2x_buffer_size;
|
||||
i2x->mb_head_ptr_reg = mbi->i2x_head_offset;
|
||||
i2x->mb_tail_ptr_reg = mbi->i2x_tail_offset;
|
||||
|
||||
ndev->aie.mgmt_chan_idx = mbi->i2x_msi_idx;
|
||||
aie_dump_mgmt_chann_debug(&ndev->aie);
|
||||
|
||||
ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
|
||||
if (!ndev->mbox) {
|
||||
XDNA_ERR(xdna, "failed to create mailbox device");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ndev->aie.mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
|
||||
if (!ndev->aie.mgmt_chann) {
|
||||
XDNA_ERR(xdna, "failed to alloc mailbox channel");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mgmt_mb_irq = pci_irq_vector(pdev, ndev->aie.mgmt_chan_idx);
|
||||
if (mgmt_mb_irq < 0) {
|
||||
XDNA_ERR(xdna, "failed to alloc irq vector, return %d", mgmt_mb_irq);
|
||||
ret = mgmt_mb_irq;
|
||||
goto free_channel;
|
||||
}
|
||||
|
||||
ret = xdna_mailbox_start_channel(ndev->aie.mgmt_chann,
|
||||
&ndev->aie.mgmt_x2i,
|
||||
&ndev->aie.mgmt_i2x,
|
||||
NO_IOHUB,
|
||||
mgmt_mb_irq);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to start management mailbox channel");
|
||||
ret = -EINVAL;
|
||||
goto free_channel;
|
||||
}
|
||||
|
||||
XDNA_DBG(xdna, "Mailbox management channel created");
|
||||
return 0;
|
||||
|
||||
free_channel:
|
||||
xdna_mailbox_free_channel(ndev->aie.mgmt_chann);
|
||||
ndev->aie.mgmt_chann = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie4_mailbox_init(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct mailbox_info mbox_info;
|
||||
int ret;
|
||||
|
||||
ret = aie4_mailbox_info(xdna, &mbox_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return aie4_mailbox_start(xdna, &mbox_info);
|
||||
}
|
||||
|
||||
static void aie4_fw_stop(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
aie_psp_stop(ndev->aie.psp_hdl);
|
||||
aie_smu_fini(ndev->aie.smu_hdl);
|
||||
}
|
||||
|
||||
static int aie4_fw_start(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie_smu_init(ndev->aie.smu_hdl);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->aie.xdna, "failed to init smu, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie_psp_start(ndev->aie.psp_hdl);
|
||||
if (ret) {
|
||||
XDNA_ERR(ndev->aie.xdna, "failed to start psp, ret %d", ret);
|
||||
aie_smu_fini(ndev->aie.smu_hdl);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie4_partition_init(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_create_partition, AIE4_MSG_OP_CREATE_PARTITION);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
req.partition_col_start = 0;
|
||||
req.partition_col_count = AIE4_TOTAL_COLUMN;
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "partition init failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ndev->partition_id = resp.partition_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aie4_partition_fini(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_destroy_partition, AIE4_MSG_OP_DESTROY_PARTITION);
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
int ret;
|
||||
|
||||
req.partition_id = ndev->partition_id;
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "partition fini failed: %d", ret);
|
||||
}
|
||||
|
||||
static int aie4_query(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
return aie4_query_aie_metadata(ndev, &ndev->aie.metadata);
|
||||
}
|
||||
|
||||
static int aie4_pf_hw_start(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie4_fw_start(ndev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aie4_mailbox_init(ndev);
|
||||
if (ret)
|
||||
goto stop_fw;
|
||||
|
||||
ret = aie4_attach_work_buffer(ndev);
|
||||
if (ret)
|
||||
goto mbox_fini;
|
||||
|
||||
return 0;
|
||||
|
||||
mbox_fini:
|
||||
aie4_mailbox_fini(ndev);
|
||||
stop_fw:
|
||||
aie4_fw_stop(ndev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aie4_pf_hw_stop(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
aie4_suspend_fw(ndev);
|
||||
aie4_mailbox_fini(ndev);
|
||||
aie4_fw_stop(ndev);
|
||||
}
|
||||
|
||||
static int aie4_vf_hw_start(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie4_mailbox_init(ndev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aie4_query(ndev);
|
||||
if (ret)
|
||||
goto mailbox_fini;
|
||||
|
||||
ret = aie4_partition_init(ndev);
|
||||
if (ret)
|
||||
goto mailbox_fini;
|
||||
|
||||
return 0;
|
||||
|
||||
mailbox_fini:
|
||||
aie4_mailbox_fini(ndev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aie4_vf_hw_stop(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
aie4_partition_fini(ndev);
|
||||
aie4_mailbox_fini(ndev);
|
||||
}
|
||||
|
||||
static int aie4_request_firmware(struct amdxdna_dev_hdl *ndev,
|
||||
const struct firmware **npufw,
|
||||
const struct firmware **certfw)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
char fw_name[128];
|
||||
int ret;
|
||||
|
||||
ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s",
|
||||
pdev->device, pdev->revision, ndev->priv->npufw_path);
|
||||
if (ret >= sizeof(fw_name)) {
|
||||
XDNA_ERR(xdna, "npu firmware path is truncated");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = request_firmware(npufw, fw_name, &pdev->dev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snprintf(fw_name, sizeof(fw_name), "amdnpu/%04x_%02x/%s",
|
||||
pdev->device, pdev->revision, ndev->priv->certfw_path);
|
||||
if (ret >= sizeof(fw_name)) {
|
||||
XDNA_ERR(xdna, "cert firmware path is truncated");
|
||||
ret = -EINVAL;
|
||||
goto release_npufw;
|
||||
}
|
||||
|
||||
ret = request_firmware(certfw, fw_name, &pdev->dev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to request_firmware %s, ret %d", fw_name, ret);
|
||||
goto release_npufw;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
release_npufw:
|
||||
release_firmware(*npufw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void aie4_release_firmware(struct amdxdna_dev_hdl *ndev,
|
||||
const struct firmware *npufw,
|
||||
const struct firmware *certfw)
|
||||
{
|
||||
release_firmware(certfw);
|
||||
release_firmware(npufw);
|
||||
}
|
||||
|
||||
static int aie4_prepare_firmware(struct amdxdna_dev_hdl *ndev,
|
||||
const struct firmware *npufw,
|
||||
const struct firmware *certfw,
|
||||
void __iomem *tbl[PCI_NUM_RESOURCES])
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct psp_config psp_conf;
|
||||
struct smu_config smu_conf;
|
||||
int i;
|
||||
|
||||
psp_conf.fw_size = npufw->size;
|
||||
psp_conf.fw_buf = npufw->data;
|
||||
psp_conf.certfw_size = certfw->size;
|
||||
psp_conf.certfw_buf = certfw->data;
|
||||
psp_conf.arg2_mask = ~0;
|
||||
psp_conf.notify_val = PSP_NOTIFY_INTR;
|
||||
for (i = 0; i < PSP_MAX_REGS; i++)
|
||||
psp_conf.psp_regs[i] = tbl[PSP_REG_BAR(ndev, i)] + PSP_REG_OFF(ndev, i);
|
||||
ndev->aie.psp_hdl = aiem_psp_create(&xdna->ddev, &psp_conf);
|
||||
if (!ndev->aie.psp_hdl) {
|
||||
XDNA_ERR(xdna, "failed to create psp");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < SMU_MAX_REGS; i++)
|
||||
smu_conf.smu_regs[i] = tbl[SMU_REG_BAR(ndev, i)] + SMU_REG_OFF(ndev, i);
|
||||
ndev->aie.smu_hdl = aiem_smu_create(&xdna->ddev, &smu_conf);
|
||||
if (!ndev->aie.smu_hdl) {
|
||||
XDNA_ERR(xdna, "failed to create smu");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aie4_load_fw(struct amdxdna_dev_hdl *ndev,
|
||||
void __iomem *tbl[PCI_NUM_RESOURCES])
|
||||
{
|
||||
const struct firmware *npufw, *certfw;
|
||||
int ret;
|
||||
|
||||
if (!ndev->priv->npufw_path && !ndev->priv->certfw_path)
|
||||
return 0;
|
||||
|
||||
ret = aie4_request_firmware(ndev, &npufw, &certfw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aie4_prepare_firmware(ndev, npufw, certfw, tbl);
|
||||
aie4_release_firmware(ndev, npufw, certfw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie4m_pcidev_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
void __iomem *tbl[PCI_NUM_RESOURCES] = {0};
|
||||
unsigned long bars = 0;
|
||||
int ret, i;
|
||||
|
||||
ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL);
|
||||
if (!ndev)
|
||||
return -ENOMEM;
|
||||
|
||||
ndev->priv = xdna->dev_info->dev_priv;
|
||||
ndev->aie.xdna = xdna;
|
||||
xdna->dev_handle = ndev;
|
||||
|
||||
xa_init_flags(&ndev->cert_comp_xa, XA_FLAGS_ALLOC);
|
||||
mutex_init(&ndev->cert_comp_lock);
|
||||
|
||||
/* Enable managed PCI device */
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "pcim enable device failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "failed to set DMA mask to 64:%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < PSP_MAX_REGS; i++)
|
||||
set_bit(PSP_REG_BAR(ndev, i), &bars);
|
||||
for (i = 0; i < SMU_MAX_REGS; i++)
|
||||
set_bit(SMU_REG_BAR(ndev, i), &bars);
|
||||
set_bit(xdna->dev_info->mbox_bar, &bars);
|
||||
set_bit(xdna->dev_info->sram_bar, &bars);
|
||||
|
||||
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
|
||||
if (!test_bit(i, &bars))
|
||||
continue;
|
||||
tbl[i] = pcim_iomap(pdev, i, 0);
|
||||
if (!tbl[i]) {
|
||||
XDNA_ERR(xdna, "map bar %d failed", i);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ndev->mbox_base = tbl[xdna->dev_info->mbox_bar];
|
||||
ndev->rbuf_base = tbl[xdna->dev_info->sram_bar];
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = aie4_load_fw(ndev, tbl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aie4_irq_init(xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
amdxdna_vbnv_init(xdna);
|
||||
XDNA_DBG(xdna, "init finished");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aie4_doorbell_mmap(struct amdxdna_client *client, struct vm_area_struct *vma)
|
||||
{
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
const struct amdxdna_dev_priv *npriv = xdna->dev_info->dev_priv;
|
||||
phys_addr_t res_start;
|
||||
unsigned long pfn;
|
||||
int ret;
|
||||
|
||||
if (!aie4_hwctx_valid_doorbell(client, vma->vm_pgoff)) {
|
||||
XDNA_ERR(xdna, "Invalid doorbell page offset 0x%lx", vma->vm_pgoff);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vma_pages(vma) != 1) {
|
||||
XDNA_ERR(xdna, "can only map one page, got %ld", vma_pages(vma));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res_start = pci_resource_start(pdev, xdna->dev_info->doorbell_bar) + npriv->doorbell_off;
|
||||
pfn = PHYS_PFN(res_start) + vma->vm_pgoff;
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
|
||||
ret = io_remap_pfn_range(vma, vma->vm_start,
|
||||
pfn,
|
||||
PAGE_SIZE,
|
||||
vma->vm_page_prot);
|
||||
|
||||
XDNA_DBG(xdna, "doorbell ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie4_get_info(struct amdxdna_client *client, struct amdxdna_drm_get_info *args)
|
||||
{
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
int ret;
|
||||
|
||||
switch (args->param) {
|
||||
case DRM_AMDXDNA_QUERY_AIE_METADATA:
|
||||
ret = amdxdna_get_metadata(&ndev->aie, client, args);
|
||||
break;
|
||||
default:
|
||||
XDNA_ERR(xdna, "Not supported request parameter %u", args->param);
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
XDNA_DBG(xdna, "Got param %d", args->param);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie4_alloc_work_buffer(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
u32 buf_size = AIE4_WORK_BUFFER_MIN_SIZE;
|
||||
|
||||
ndev->work_buf = amdxdna_alloc_msg_buffer(xdna, &buf_size,
|
||||
&ndev->work_buf_addr);
|
||||
if (IS_ERR(ndev->work_buf)) {
|
||||
int ret = PTR_ERR(ndev->work_buf);
|
||||
|
||||
XDNA_ERR(xdna, "Failed to alloc work buffer, size 0x%x",
|
||||
AIE4_WORK_BUFFER_MIN_SIZE);
|
||||
ndev->work_buf = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ndev->work_buf_size = buf_size;
|
||||
XDNA_DBG(xdna, "Work buffer allocated: size 0x%x", buf_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aie4_free_work_buffer(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
|
||||
if (!ndev->work_buf)
|
||||
return;
|
||||
|
||||
amdxdna_free_msg_buffer(xdna, ndev->work_buf_size, ndev->work_buf,
|
||||
ndev->work_buf_addr);
|
||||
ndev->work_buf = NULL;
|
||||
}
|
||||
|
||||
static int aie4_pf_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie4m_pcidev_init(xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aie4_alloc_work_buffer(xdna->dev_handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aie4_pf_hw_start(xdna->dev_handle);
|
||||
if (ret)
|
||||
goto free_work_buf;
|
||||
|
||||
return 0;
|
||||
|
||||
free_work_buf:
|
||||
aie4_free_work_buffer(xdna->dev_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie4_vf_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie4m_pcidev_init(xdna);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return aie4_vf_hw_start(xdna->dev_handle);
|
||||
}
|
||||
|
||||
static void aie4_pf_fini(struct amdxdna_dev *xdna)
|
||||
{
|
||||
aie4_sriov_stop(xdna->dev_handle);
|
||||
aie4_pf_hw_stop(xdna->dev_handle);
|
||||
aie4_free_work_buffer(xdna->dev_handle);
|
||||
}
|
||||
|
||||
static void aie4_vf_fini(struct amdxdna_dev *xdna)
|
||||
{
|
||||
aie4_vf_hw_stop(xdna->dev_handle);
|
||||
}
|
||||
|
||||
const struct amdxdna_dev_ops aie4_pf_ops = {
|
||||
.init = aie4_pf_init,
|
||||
.fini = aie4_pf_fini,
|
||||
.sriov_configure = aie4_sriov_configure,
|
||||
};
|
||||
|
||||
const struct amdxdna_dev_ops aie4_vf_ops = {
|
||||
.init = aie4_vf_init,
|
||||
.fini = aie4_vf_fini,
|
||||
.hwctx_init = aie4_hwctx_init,
|
||||
.hwctx_fini = aie4_hwctx_fini,
|
||||
.mmap = aie4_doorbell_mmap,
|
||||
.cmd_wait = aie4_cmd_wait,
|
||||
.get_aie_info = aie4_get_info,
|
||||
};
|
||||
89
drivers/accel/amdxdna/aie4_pci.h
Normal file
89
drivers/accel/amdxdna/aie4_pci.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _AIE4_PCI_H_
|
||||
#define _AIE4_PCI_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
|
||||
struct cert_comp {
|
||||
struct amdxdna_dev_hdl *ndev;
|
||||
u32 msix_idx;
|
||||
int irq;
|
||||
struct kref kref;
|
||||
wait_queue_head_t waitq;
|
||||
};
|
||||
|
||||
struct amdxdna_hwctx_priv {
|
||||
struct amdxdna_gem_obj *umq_bo;
|
||||
u64 *umq_read_index;
|
||||
u64 *umq_write_index;
|
||||
|
||||
struct cert_comp *cert_comp;
|
||||
u32 hw_ctx_id;
|
||||
};
|
||||
|
||||
struct amdxdna_dev_priv {
|
||||
const char *npufw_path;
|
||||
const char *certfw_path;
|
||||
u32 mbox_bar;
|
||||
u32 mbox_rbuf_bar;
|
||||
u64 mbox_info_off;
|
||||
u32 doorbell_off;
|
||||
|
||||
struct aie_bar_off_pair psp_regs_off[PSP_MAX_REGS];
|
||||
struct aie_bar_off_pair smu_regs_off[SMU_MAX_REGS];
|
||||
};
|
||||
|
||||
struct amdxdna_dev_hdl {
|
||||
struct aie_device aie;
|
||||
const struct amdxdna_dev_priv *priv;
|
||||
void __iomem *mbox_base;
|
||||
void __iomem *rbuf_base;
|
||||
|
||||
struct mailbox *mbox;
|
||||
u32 partition_id;
|
||||
|
||||
struct xarray cert_comp_xa; /* device level indexed by msix id */
|
||||
struct mutex cert_comp_lock; /* protects cert_comp operations*/
|
||||
|
||||
void *work_buf;
|
||||
dma_addr_t work_buf_addr;
|
||||
u32 work_buf_size;
|
||||
};
|
||||
|
||||
/* aie4_message.c */
|
||||
int aie4_query_aie_metadata(struct amdxdna_dev_hdl *ndev,
|
||||
struct amdxdna_drm_query_aie_metadata *metadata);
|
||||
int aie4_suspend_fw(struct amdxdna_dev_hdl *ndev);
|
||||
int aie4_attach_work_buffer(struct amdxdna_dev_hdl *ndev);
|
||||
|
||||
/* aie4_ctx.c */
|
||||
int aie4_hwctx_init(struct amdxdna_hwctx *hwctx);
|
||||
void aie4_hwctx_fini(struct amdxdna_hwctx *hwctx);
|
||||
int aie4_cmd_wait(struct amdxdna_hwctx *hwctx, u64 seq, u32 timeout);
|
||||
int aie4_hwctx_valid_doorbell(struct amdxdna_client *client, u32 vm_pgoff);
|
||||
|
||||
/* aie4_sriov.c */
|
||||
#if IS_ENABLED(CONFIG_PCI_IOV)
|
||||
int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs);
|
||||
int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev);
|
||||
#else
|
||||
#define aie4_sriov_configure NULL
|
||||
static inline int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern const struct amdxdna_dev_ops aie4_pf_ops;
|
||||
extern const struct amdxdna_dev_ops aie4_vf_ops;
|
||||
|
||||
#endif /* _AIE4_PCI_H_ */
|
||||
88
drivers/accel/amdxdna/aie4_sriov.c
Normal file
88
drivers/accel/amdxdna/aie4_sriov.c
Normal file
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/amdxdna_accel.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "aie.h"
|
||||
#include "aie4_msg_priv.h"
|
||||
#include "aie4_pci.h"
|
||||
#include "amdxdna_mailbox.h"
|
||||
#include "amdxdna_mailbox_helper.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
static int aie4_destroy_vfs(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_destroy_vfs, AIE4_MSG_OP_DESTROY_VFS);
|
||||
int ret;
|
||||
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
XDNA_ERR(ndev->aie.xdna, "destroy vfs op failed: %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aie4_create_vfs(struct amdxdna_dev_hdl *ndev, int num_vfs)
|
||||
{
|
||||
DECLARE_AIE_MSG(aie4_msg_create_vfs, AIE4_MSG_OP_CREATE_VFS);
|
||||
int ret;
|
||||
|
||||
req.vf_cnt = num_vfs;
|
||||
ret = aie_send_mgmt_msg_wait(&ndev->aie, &msg);
|
||||
if (ret)
|
||||
XDNA_ERR(ndev->aie.xdna, "create vfs op failed: %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aie4_sriov_stop(struct amdxdna_dev_hdl *ndev)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
int ret;
|
||||
|
||||
if (!pci_num_vf(pdev))
|
||||
return 0;
|
||||
|
||||
ret = pci_vfs_assigned(pdev);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "VFs are still assigned to VMs");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
pci_disable_sriov(pdev);
|
||||
return aie4_destroy_vfs(ndev);
|
||||
}
|
||||
|
||||
static int aie4_sriov_start(struct amdxdna_dev_hdl *ndev, int num_vfs)
|
||||
{
|
||||
struct amdxdna_dev *xdna = ndev->aie.xdna;
|
||||
struct pci_dev *pdev = to_pci_dev(xdna->ddev.dev);
|
||||
int ret;
|
||||
|
||||
ret = aie4_create_vfs(ndev, num_vfs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_enable_sriov(pdev, num_vfs);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "configure VFs failed, ret: %d", ret);
|
||||
aie4_destroy_vfs(ndev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return num_vfs;
|
||||
}
|
||||
|
||||
int aie4_sriov_configure(struct amdxdna_dev *xdna, int num_vfs)
|
||||
{
|
||||
struct amdxdna_dev_hdl *ndev = xdna->dev_handle;
|
||||
|
||||
drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
|
||||
|
||||
return (num_vfs) ? aie4_sriov_start(ndev, num_vfs) : aie4_sriov_stop(ndev);
|
||||
}
|
||||
235
drivers/accel/amdxdna/aie_psp.c
Normal file
235
drivers/accel/amdxdna/aie_psp.c
Normal file
@@ -0,0 +1,235 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "aie.h"
|
||||
|
||||
#define PSP_STATUS_READY BIT(31)
|
||||
|
||||
/* PSP commands */
|
||||
#define PSP_VALIDATE 1
|
||||
#define PSP_START 2
|
||||
#define PSP_RELEASE_TMR 3
|
||||
#define PSP_VALIDATE_CERT 4
|
||||
|
||||
/* PSP special arguments */
|
||||
#define PSP_START_COPY_FW 1
|
||||
|
||||
/* PSP response error code */
|
||||
#define PSP_ERROR_CANCEL 0xFFFF0002
|
||||
#define PSP_ERROR_BAD_STATE 0xFFFF0007
|
||||
|
||||
#define PSP_FW_ALIGN 0x10000
|
||||
#define PSP_CFW_ALIGN 0x8000
|
||||
#define PSP_POLL_INTERVAL 20000 /* us */
|
||||
#define PSP_POLL_TIMEOUT 1000000 /* us */
|
||||
|
||||
#define PSP_REG(p, reg) ((p)->conf.psp_regs[reg])
|
||||
#define PSP_SET_CMD(psp, reg_vals, cmd, arg0, arg1, arg2) \
|
||||
({ \
|
||||
u32 *_regs = reg_vals; \
|
||||
u32 _cmd = cmd; \
|
||||
_regs[0] = _cmd; \
|
||||
_regs[1] = arg0; \
|
||||
_regs[2] = arg1; \
|
||||
_regs[3] = ((arg2) | ((_cmd) << 24)) & (psp)->conf.arg2_mask; \
|
||||
})
|
||||
|
||||
struct psp_device {
|
||||
struct drm_device *ddev;
|
||||
struct psp_config conf;
|
||||
u32 fw_buf_sz;
|
||||
u64 fw_paddr;
|
||||
void *fw_buffer;
|
||||
u32 certfw_buf_sz;
|
||||
u64 certfw_paddr;
|
||||
void *certfw_buffer;
|
||||
};
|
||||
|
||||
static int psp_exec(struct psp_device *psp, u32 *reg_vals)
|
||||
{
|
||||
u32 resp_code;
|
||||
int ret, i;
|
||||
u32 ready;
|
||||
|
||||
/* Check for PSP ready before any write */
|
||||
ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready,
|
||||
FIELD_GET(PSP_STATUS_READY, ready),
|
||||
PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
|
||||
if (ret) {
|
||||
drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Write command and argument registers */
|
||||
for (i = 0; i < PSP_NUM_IN_REGS; i++)
|
||||
writel(reg_vals[i], PSP_REG(psp, i));
|
||||
|
||||
/* clear and set PSP INTR register to kick off */
|
||||
writel(0, PSP_REG(psp, PSP_INTR_REG));
|
||||
writel(psp->conf.notify_val, PSP_REG(psp, PSP_INTR_REG));
|
||||
|
||||
/* PSP should be busy. Wait for ready, so we know task is done. */
|
||||
ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_STATUS_REG), ready,
|
||||
FIELD_GET(PSP_STATUS_READY, ready),
|
||||
PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
|
||||
if (ret) {
|
||||
drm_err(psp->ddev, "PSP is not ready, ret 0x%x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
resp_code = readl(PSP_REG(psp, PSP_RESP_REG));
|
||||
if (resp_code) {
|
||||
drm_err(psp->ddev, "fw return error 0x%x", resp_code);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie_psp_waitmode_poll(struct psp_device *psp)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(psp->ddev);
|
||||
u32 mode_reg;
|
||||
int ret;
|
||||
|
||||
ret = readx_poll_timeout(readl, PSP_REG(psp, PSP_PWAITMODE_REG), mode_reg,
|
||||
(mode_reg & 0x1) == 1,
|
||||
PSP_POLL_INTERVAL, PSP_POLL_TIMEOUT);
|
||||
if (ret)
|
||||
XDNA_ERR(xdna, "fw waitmode reg error, ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void aie_psp_stop(struct psp_device *psp)
|
||||
{
|
||||
u32 reg_vals[PSP_NUM_IN_REGS];
|
||||
int ret;
|
||||
|
||||
PSP_SET_CMD(psp, reg_vals, PSP_RELEASE_TMR, 0, 0, 0);
|
||||
|
||||
ret = psp_exec(psp, reg_vals);
|
||||
if (ret)
|
||||
drm_err(psp->ddev, "release tmr failed, ret %d", ret);
|
||||
}
|
||||
|
||||
static int psp_validate_fw(struct psp_device *psp, u8 cmd, u64 paddr, u32 buf_sz)
|
||||
{
|
||||
u32 reg_vals[PSP_NUM_IN_REGS];
|
||||
int ret;
|
||||
|
||||
PSP_SET_CMD(psp, reg_vals, cmd, lower_32_bits(paddr),
|
||||
upper_32_bits(paddr), buf_sz);
|
||||
|
||||
ret = psp_exec(psp, reg_vals);
|
||||
if (ret)
|
||||
drm_err(psp->ddev, "failed to validate fw, ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int psp_start(struct psp_device *psp)
|
||||
{
|
||||
u32 reg_vals[PSP_NUM_IN_REGS];
|
||||
int ret;
|
||||
|
||||
PSP_SET_CMD(psp, reg_vals, PSP_START, PSP_START_COPY_FW, 0, 0);
|
||||
|
||||
ret = psp_exec(psp, reg_vals);
|
||||
if (ret)
|
||||
drm_err(psp->ddev, "failed to start fw, ret %d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int aie_psp_start(struct psp_device *psp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = psp_validate_fw(psp, PSP_VALIDATE,
|
||||
psp->fw_paddr, psp->fw_buf_sz);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!psp->certfw_buf_sz)
|
||||
goto psp_start;
|
||||
|
||||
ret = psp_validate_fw(psp, PSP_VALIDATE_CERT,
|
||||
psp->certfw_paddr, psp->certfw_buf_sz);
|
||||
if (ret)
|
||||
return ret;
|
||||
psp_start:
|
||||
return psp_start(psp);
|
||||
}
|
||||
|
||||
/*
|
||||
* PSP requires host physical address to load firmware.
|
||||
* Allocate a buffer, obtain its physical address, align, and copy data in.
|
||||
*/
|
||||
static void *psp_alloc_fw_buf(struct psp_device *psp, const void *fw_data,
|
||||
u32 fw_size, u32 align, u32 *buf_sz,
|
||||
u64 *paddr)
|
||||
{
|
||||
u32 alloc_sz;
|
||||
void *buffer;
|
||||
u64 offset;
|
||||
|
||||
*buf_sz = ALIGN(fw_size, align);
|
||||
alloc_sz = *buf_sz + align;
|
||||
|
||||
buffer = drmm_kmalloc(psp->ddev, alloc_sz, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
*paddr = virt_to_phys(buffer);
|
||||
offset = ALIGN(*paddr, align) - *paddr;
|
||||
*paddr += offset;
|
||||
memcpy(buffer + offset, fw_data, fw_size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct psp_device *aiem_psp_create(struct drm_device *ddev, struct psp_config *conf)
|
||||
{
|
||||
struct psp_device *psp;
|
||||
|
||||
psp = drmm_kzalloc(ddev, sizeof(*psp), GFP_KERNEL);
|
||||
if (!psp)
|
||||
return NULL;
|
||||
|
||||
psp->ddev = ddev;
|
||||
psp->fw_buffer = psp_alloc_fw_buf(psp, conf->fw_buf, conf->fw_size,
|
||||
PSP_FW_ALIGN, &psp->fw_buf_sz,
|
||||
&psp->fw_paddr);
|
||||
if (!psp->fw_buffer)
|
||||
return NULL;
|
||||
|
||||
if (!conf->certfw_size) {
|
||||
drm_dbg(ddev, "no cert fw");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* CERT firmware */
|
||||
psp->certfw_buffer = psp_alloc_fw_buf(psp, conf->certfw_buf,
|
||||
conf->certfw_size, PSP_CFW_ALIGN,
|
||||
&psp->certfw_buf_sz,
|
||||
&psp->certfw_paddr);
|
||||
if (!psp->certfw_buffer) {
|
||||
drm_err(ddev, "no memory for cert fw buffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
done:
|
||||
memcpy(&psp->conf, conf, sizeof(psp->conf));
|
||||
|
||||
return psp;
|
||||
}
|
||||
153
drivers/accel/amdxdna/aie_smu.c
Normal file
153
drivers/accel/amdxdna/aie_smu.c
Normal file
@@ -0,0 +1,153 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include "drm/amdxdna_accel.h"
|
||||
#include <drm/drm_device.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/gpu_scheduler.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "aie.h"
|
||||
|
||||
#define SMU_RESULT_OK 1
|
||||
|
||||
/* SMU commands */
|
||||
#define AIE_SMU_POWER_ON 0x3
|
||||
#define AIE_SMU_POWER_OFF 0x4
|
||||
#define AIE_SMU_SET_MPNPUCLK_FREQ 0x5
|
||||
#define AIE_SMU_SET_HCLK_FREQ 0x6
|
||||
#define AIE_SMU_SET_SOFT_DPMLEVEL 0x7
|
||||
#define AIE_SMU_SET_HARD_DPMLEVEL 0x8
|
||||
|
||||
#define SMU_REG(s, reg) ((s)->smu_regs[reg])
|
||||
|
||||
struct smu_device {
|
||||
struct drm_device *ddev;
|
||||
struct smu_config conf;
|
||||
void __iomem *smu_regs[SMU_MAX_REGS];
|
||||
};
|
||||
|
||||
static int aie_smu_exec(struct smu_device *smu, u32 reg_cmd, u32 reg_arg, u32 *out)
|
||||
{
|
||||
u32 resp;
|
||||
int ret;
|
||||
|
||||
writel(0, SMU_REG(smu, SMU_RESP_REG));
|
||||
writel(reg_arg, SMU_REG(smu, SMU_ARG_REG));
|
||||
writel(reg_cmd, SMU_REG(smu, SMU_CMD_REG));
|
||||
|
||||
/* Clear and set SMU_INTR_REG to kick off */
|
||||
writel(0, SMU_REG(smu, SMU_INTR_REG));
|
||||
writel(1, SMU_REG(smu, SMU_INTR_REG));
|
||||
|
||||
ret = readx_poll_timeout(readl, SMU_REG(smu, SMU_RESP_REG), resp,
|
||||
resp, AIE_INTERVAL, AIE_TIMEOUT);
|
||||
if (ret) {
|
||||
drm_err(smu->ddev, "smu cmd %d timed out", reg_cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (out)
|
||||
*out = readl(SMU_REG(smu, SMU_OUT_REG));
|
||||
|
||||
if (resp != SMU_RESULT_OK) {
|
||||
drm_err(smu->ddev, "smu cmd %d failed, 0x%x", reg_cmd, resp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie_smu_init(struct smu_device *smu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Failing to set power off indicates an unrecoverable hardware or
|
||||
* firmware error.
|
||||
*/
|
||||
ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL);
|
||||
if (ret) {
|
||||
drm_err(smu->ddev, "Access power failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie_smu_exec(smu, AIE_SMU_POWER_ON, 0, NULL);
|
||||
if (ret) {
|
||||
drm_err(smu->ddev, "Power on failed, ret %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void aie_smu_fini(struct smu_device *smu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie_smu_exec(smu, AIE_SMU_POWER_OFF, 0, NULL);
|
||||
if (ret)
|
||||
drm_err(smu->ddev, "Power off failed, ret %d", ret);
|
||||
}
|
||||
|
||||
int aie_smu_set_clocks(struct smu_device *smu, u32 *npuclk, u32 *hclk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (npuclk) {
|
||||
ret = aie_smu_exec(smu, AIE_SMU_SET_MPNPUCLK_FREQ, *npuclk, npuclk);
|
||||
if (ret) {
|
||||
drm_err(smu->ddev, "Set mpnpu clock to %d failed, ret %d", *npuclk, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (hclk) {
|
||||
ret = aie_smu_exec(smu, AIE_SMU_SET_HCLK_FREQ, *hclk, hclk);
|
||||
if (ret) {
|
||||
drm_err(smu->ddev, "Set hclock to %d failed, ret %d",
|
||||
*hclk, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aie_smu_set_dpm(struct smu_device *smu, u32 dpm_level)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = aie_smu_exec(smu, AIE_SMU_SET_HARD_DPMLEVEL, dpm_level, NULL);
|
||||
if (ret) {
|
||||
drm_err(smu->ddev, "Set hard dpm level %d failed, ret %d",
|
||||
dpm_level, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = aie_smu_exec(smu, AIE_SMU_SET_SOFT_DPMLEVEL, dpm_level, NULL);
|
||||
if (ret) {
|
||||
drm_err(smu->ddev, "Set soft dpm level %d failed, ret %d",
|
||||
dpm_level, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smu_device *aiem_smu_create(struct drm_device *ddev, struct smu_config *conf)
|
||||
{
|
||||
struct smu_device *smu;
|
||||
|
||||
smu = drmm_kzalloc(ddev, sizeof(*smu), GFP_KERNEL);
|
||||
if (!smu)
|
||||
return NULL;
|
||||
|
||||
smu->ddev = ddev;
|
||||
memcpy(smu->smu_regs, conf->smu_regs, sizeof(smu->smu_regs));
|
||||
|
||||
return smu;
|
||||
}
|
||||
280
drivers/accel/amdxdna/amdxdna_cbuf.c
Normal file
280
drivers/accel/amdxdna/amdxdna_cbuf.c
Normal file
@@ -0,0 +1,280 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <drm/drm_mm.h>
|
||||
#include <drm/drm_prime.h>
|
||||
|
||||
#include "amdxdna_cbuf.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
/*
|
||||
* Carveout memory is a chunk of memory which is physically contiguous and
|
||||
* is reserved during early boot time. There is only one chunk of such memory
|
||||
* per device. Once available, all BOs accessible from device should be
|
||||
* allocated from this memory. This is a platform debug/bringup feature.
|
||||
*/
|
||||
struct amdxdna_carveout {
|
||||
u64 addr;
|
||||
u64 size;
|
||||
struct drm_mm mm;
|
||||
struct mutex lock; /* protect mm */
|
||||
};
|
||||
|
||||
bool amdxdna_use_carveout(struct amdxdna_dev *xdna)
|
||||
{
|
||||
return !!xdna->carveout;
|
||||
}
|
||||
|
||||
void amdxdna_get_carveout_conf(struct amdxdna_dev *xdna, u64 *addr, u64 *size)
|
||||
{
|
||||
if (amdxdna_use_carveout(xdna)) {
|
||||
*addr = xdna->carveout->addr;
|
||||
*size = xdna->carveout->size;
|
||||
} else {
|
||||
*addr = 0;
|
||||
*size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int amdxdna_carveout_init(struct amdxdna_dev *xdna, u64 carveout_addr, u64 carveout_size)
|
||||
{
|
||||
struct amdxdna_carveout *carveout;
|
||||
|
||||
/* Only allow carveout memory to be set up once. */
|
||||
if (amdxdna_use_carveout(xdna)) {
|
||||
XDNA_ERR(xdna, "Carveout memory has already been set up.");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
carveout = kzalloc_obj(*carveout);
|
||||
if (!carveout)
|
||||
return -ENOMEM;
|
||||
|
||||
carveout->addr = carveout_addr;
|
||||
carveout->size = carveout_size;
|
||||
mutex_init(&carveout->lock);
|
||||
drm_mm_init(&carveout->mm, carveout->addr, carveout->size);
|
||||
|
||||
xdna->carveout = carveout;
|
||||
XDNA_INFO(xdna, "Use carveout mem: 0x%llx@0x%llx\n", carveout->size, carveout->addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amdxdna_carveout_fini(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct amdxdna_carveout *carveout = xdna->carveout;
|
||||
|
||||
if (!amdxdna_use_carveout(xdna))
|
||||
return;
|
||||
|
||||
XDNA_INFO(xdna, "Cleanup carveout mem: 0x%llx@0x%llx\n", carveout->size, carveout->addr);
|
||||
drm_mm_takedown(&carveout->mm);
|
||||
mutex_destroy(&carveout->lock);
|
||||
kfree(carveout);
|
||||
xdna->carveout = NULL;
|
||||
}
|
||||
|
||||
struct amdxdna_cbuf_priv {
|
||||
struct amdxdna_dev *xdna;
|
||||
struct drm_mm_node node;
|
||||
};
|
||||
|
||||
static struct sg_table *amdxdna_cbuf_map(struct dma_buf_attachment *attach,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct amdxdna_cbuf_priv *cbuf = attach->dmabuf->priv;
|
||||
struct device *dev = attach->dev;
|
||||
struct scatterlist *sgl, *sg;
|
||||
int ret, n_entries, i;
|
||||
struct sg_table *sgt;
|
||||
dma_addr_t dma_addr;
|
||||
size_t dma_size;
|
||||
size_t max_seg;
|
||||
|
||||
sgt = kzalloc_obj(*sgt);
|
||||
if (!sgt)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
max_seg = min_t(size_t, UINT_MAX, dma_max_mapping_size(dev));
|
||||
n_entries = (cbuf->node.size + max_seg - 1) / max_seg;
|
||||
sgl = kzalloc_objs(*sg, n_entries);
|
||||
if (!sgl) {
|
||||
ret = -ENOMEM;
|
||||
goto free_sgt;
|
||||
}
|
||||
sg_init_table(sgl, n_entries);
|
||||
sgt->orig_nents = n_entries;
|
||||
sgt->nents = n_entries;
|
||||
sgt->sgl = sgl;
|
||||
|
||||
dma_size = cbuf->node.size;
|
||||
dma_addr = dma_map_resource(dev, cbuf->node.start, dma_size,
|
||||
direction, DMA_ATTR_SKIP_CPU_SYNC);
|
||||
ret = dma_mapping_error(dev, dma_addr);
|
||||
if (ret) {
|
||||
pr_err("Failed to dma_map_resource carveout dma buf, ret %d\n", ret);
|
||||
goto free_sgl;
|
||||
}
|
||||
|
||||
for_each_sgtable_dma_sg(sgt, sg, i) {
|
||||
size_t len = min_t(size_t, max_seg, dma_size);
|
||||
|
||||
sg_dma_address(sg) = dma_addr;
|
||||
sg_dma_len(sg) = len;
|
||||
dma_addr += len;
|
||||
dma_size -= len;
|
||||
}
|
||||
|
||||
return sgt;
|
||||
|
||||
free_sgl:
|
||||
kfree(sgl);
|
||||
free_sgt:
|
||||
kfree(sgt);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void amdxdna_cbuf_unmap(struct dma_buf_attachment *attach,
|
||||
struct sg_table *sgt,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
dma_unmap_resource(attach->dev, sg_dma_address(sgt->sgl),
|
||||
drm_prime_get_contiguous_size(sgt), direction,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
sg_free_table(sgt);
|
||||
kfree(sgt);
|
||||
}
|
||||
|
||||
static void amdxdna_cbuf_release(struct dma_buf *dbuf)
|
||||
{
|
||||
struct amdxdna_cbuf_priv *cbuf = dbuf->priv;
|
||||
struct amdxdna_carveout *carveout;
|
||||
|
||||
carveout = cbuf->xdna->carveout;
|
||||
mutex_lock(&carveout->lock);
|
||||
drm_mm_remove_node(&cbuf->node);
|
||||
mutex_unlock(&carveout->lock);
|
||||
|
||||
kfree(cbuf);
|
||||
}
|
||||
|
||||
static vm_fault_t amdxdna_cbuf_vm_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct vm_area_struct *vma = vmf->vma;
|
||||
struct amdxdna_cbuf_priv *cbuf;
|
||||
unsigned long pfn;
|
||||
pgoff_t pgoff;
|
||||
|
||||
cbuf = vma->vm_private_data;
|
||||
pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
|
||||
pfn = (cbuf->node.start >> PAGE_SHIFT) + pgoff;
|
||||
|
||||
return vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct amdxdna_cbuf_vm_ops = {
|
||||
.fault = amdxdna_cbuf_vm_fault,
|
||||
};
|
||||
|
||||
static int amdxdna_cbuf_mmap(struct dma_buf *dbuf, struct vm_area_struct *vma)
|
||||
{
|
||||
struct amdxdna_cbuf_priv *cbuf = dbuf->priv;
|
||||
|
||||
vma->vm_ops = &amdxdna_cbuf_vm_ops;
|
||||
vma->vm_private_data = cbuf;
|
||||
vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amdxdna_cbuf_vmap(struct dma_buf *dbuf, struct iosys_map *map)
|
||||
{
|
||||
struct amdxdna_cbuf_priv *cbuf = dbuf->priv;
|
||||
void *kva;
|
||||
|
||||
kva = memremap(cbuf->node.start, cbuf->node.size, MEMREMAP_WB);
|
||||
if (!kva) {
|
||||
pr_err("Failed to vmap carveout dma buf\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
iosys_map_set_vaddr(map, kva);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdxdna_cbuf_vunmap(struct dma_buf *dbuf, struct iosys_map *map)
|
||||
{
|
||||
memunmap(map->vaddr);
|
||||
}
|
||||
|
||||
static const struct dma_buf_ops amdxdna_cbuf_dmabuf_ops = {
|
||||
.map_dma_buf = amdxdna_cbuf_map,
|
||||
.unmap_dma_buf = amdxdna_cbuf_unmap,
|
||||
.release = amdxdna_cbuf_release,
|
||||
.mmap = amdxdna_cbuf_mmap,
|
||||
.vmap = amdxdna_cbuf_vmap,
|
||||
.vunmap = amdxdna_cbuf_vunmap,
|
||||
};
|
||||
|
||||
static int amdxdna_cbuf_clear(struct dma_buf *dbuf)
|
||||
{
|
||||
struct iosys_map vmap = IOSYS_MAP_INIT_VADDR(NULL);
|
||||
|
||||
dma_buf_vmap(dbuf, &vmap);
|
||||
if (!vmap.vaddr)
|
||||
return -EFAULT;
|
||||
|
||||
memset(vmap.vaddr, 0, dbuf->size);
|
||||
dma_buf_vunmap(dbuf, &vmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dma_buf *amdxdna_get_cbuf(struct drm_device *dev, size_t size, u64 alignment)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(dev);
|
||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||
struct amdxdna_carveout *carveout;
|
||||
struct amdxdna_cbuf_priv *cbuf;
|
||||
struct dma_buf *dbuf;
|
||||
int ret;
|
||||
|
||||
cbuf = kzalloc_obj(*cbuf);
|
||||
if (!cbuf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
cbuf->xdna = xdna;
|
||||
|
||||
carveout = xdna->carveout;
|
||||
mutex_lock(&carveout->lock);
|
||||
ret = drm_mm_insert_node_generic(&carveout->mm, &cbuf->node, size,
|
||||
alignment, 0, DRM_MM_INSERT_BEST);
|
||||
mutex_unlock(&carveout->lock);
|
||||
if (ret)
|
||||
goto free_cbuf;
|
||||
|
||||
exp_info.size = size;
|
||||
exp_info.ops = &amdxdna_cbuf_dmabuf_ops;
|
||||
exp_info.priv = cbuf;
|
||||
exp_info.flags = O_RDWR;
|
||||
dbuf = dma_buf_export(&exp_info);
|
||||
if (IS_ERR(dbuf)) {
|
||||
ret = PTR_ERR(dbuf);
|
||||
goto remove_node;
|
||||
}
|
||||
|
||||
ret = amdxdna_cbuf_clear(dbuf);
|
||||
if (ret) {
|
||||
dma_buf_put(dbuf);
|
||||
goto out;
|
||||
}
|
||||
return dbuf;
|
||||
|
||||
remove_node:
|
||||
drm_mm_remove_node(&cbuf->node);
|
||||
free_cbuf:
|
||||
kfree(cbuf);
|
||||
out:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
18
drivers/accel/amdxdna/amdxdna_cbuf.h
Normal file
18
drivers/accel/amdxdna/amdxdna_cbuf.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
#ifndef _AMDXDNA_CBUF_H_
|
||||
#define _AMDXDNA_CBUF_H_
|
||||
|
||||
#include "amdxdna_pci_drv.h"
|
||||
#include <drm/drm_device.h>
|
||||
#include <linux/dma-buf.h>
|
||||
|
||||
bool amdxdna_use_carveout(struct amdxdna_dev *xdna);
|
||||
int amdxdna_carveout_init(struct amdxdna_dev *xdna, u64 carveout_addr, u64 carveout_size);
|
||||
void amdxdna_carveout_fini(struct amdxdna_dev *xdna);
|
||||
void amdxdna_get_carveout_conf(struct amdxdna_dev *xdna, u64 *addr, u64 *size);
|
||||
struct dma_buf *amdxdna_get_cbuf(struct drm_device *dev, size_t size, u64 alignment);
|
||||
|
||||
#endif
|
||||
@@ -61,16 +61,35 @@ static struct dma_fence *amdxdna_fence_create(struct amdxdna_hwctx *hwctx)
|
||||
return &fence->base;
|
||||
}
|
||||
|
||||
static void amdxdna_hwctx_release_expanded_heap(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_gem_obj *heap;
|
||||
unsigned long heap_id;
|
||||
|
||||
mutex_lock(&client->mm_lock);
|
||||
if (hwctx->last_attached_heap) {
|
||||
xa_for_each_range(&client->dev_heap_xa, heap_id, heap, 1,
|
||||
hwctx->last_attached_heap) {
|
||||
amdxdna_gem_unpin(heap);
|
||||
drm_gem_object_put(to_gobj(heap));
|
||||
}
|
||||
}
|
||||
mutex_unlock(&client->mm_lock);
|
||||
}
|
||||
|
||||
static void amdxdna_hwctx_destroy_rcu(struct amdxdna_hwctx *hwctx,
|
||||
struct srcu_struct *ss)
|
||||
{
|
||||
struct amdxdna_dev *xdna = hwctx->client->xdna;
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
|
||||
synchronize_srcu(ss);
|
||||
|
||||
/* At this point, user is not able to submit new commands */
|
||||
xdna->dev_info->ops->hwctx_fini(hwctx);
|
||||
|
||||
amdxdna_hwctx_release_expanded_heap(hwctx);
|
||||
kfree(hwctx->name);
|
||||
kfree(hwctx);
|
||||
}
|
||||
@@ -207,6 +226,9 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
|
||||
if (args->ext || args->ext_flags)
|
||||
return -EINVAL;
|
||||
|
||||
if (!xdna->dev_info->ops->hwctx_init)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
hwctx = kzalloc_obj(*hwctx);
|
||||
if (!hwctx)
|
||||
return -ENOMEM;
|
||||
@@ -220,6 +242,8 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
|
||||
hwctx->client = client;
|
||||
hwctx->fw_ctx_id = -1;
|
||||
hwctx->num_tiles = args->num_tiles;
|
||||
hwctx->umq_bo_hdl = args->umq_bo;
|
||||
hwctx->doorbell_offset = AMDXDNA_INVALID_DOORBELL_OFFSET;
|
||||
hwctx->mem_size = args->mem_size;
|
||||
hwctx->max_opc = args->max_opc;
|
||||
|
||||
@@ -233,7 +257,7 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
|
||||
ret = xdna->dev_info->ops->hwctx_init(hwctx);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Init hwctx failed, ret %d", ret);
|
||||
goto dev_exit;
|
||||
goto release_expanded_heap;
|
||||
}
|
||||
|
||||
hwctx->name = kasprintf(GFP_KERNEL, "hwctx.%d.%d", client->pid, hwctx->fw_ctx_id);
|
||||
@@ -252,6 +276,7 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
|
||||
|
||||
args->handle = hwctx->id;
|
||||
args->syncobj_handle = hwctx->syncobj_hdl;
|
||||
args->umq_doorbell = hwctx->doorbell_offset;
|
||||
|
||||
atomic64_set(&hwctx->job_submit_cnt, 0);
|
||||
atomic64_set(&hwctx->job_free_cnt, 0);
|
||||
@@ -263,7 +288,8 @@ int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct dr
|
||||
kfree(hwctx->name);
|
||||
fini_hwctx:
|
||||
xdna->dev_info->ops->hwctx_fini(hwctx);
|
||||
dev_exit:
|
||||
release_expanded_heap:
|
||||
amdxdna_hwctx_release_expanded_heap(hwctx);
|
||||
drm_dev_exit(idx);
|
||||
free_hwctx:
|
||||
kfree(hwctx);
|
||||
@@ -401,6 +427,62 @@ int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdxdna_hwctx_expand_heap(struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
struct amdxdna_client *client = hwctx->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_gem_obj *heap;
|
||||
unsigned long heap_id, nid;
|
||||
int ret = 0;
|
||||
|
||||
nid = hwctx->last_attached_heap + 1;
|
||||
if (nid == client->dev_heap_nid)
|
||||
goto out;
|
||||
|
||||
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
|
||||
nid, client->dev_heap_nid) {
|
||||
drm_gem_object_get(to_gobj(heap));
|
||||
ret = amdxdna_gem_pin(heap);
|
||||
if (ret) {
|
||||
drm_gem_object_put(to_gobj(heap));
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&client->mm_lock);
|
||||
ret = xdna->dev_info->ops->hwctx_heap_expand(hwctx, heap);
|
||||
mutex_lock(&client->mm_lock);
|
||||
if (ret) {
|
||||
amdxdna_gem_unpin(heap);
|
||||
drm_gem_object_put(to_gobj(heap));
|
||||
break;
|
||||
}
|
||||
|
||||
hwctx->last_attached_heap = heap_id;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdxdna_update_heap(struct amdxdna_client *client, struct amdxdna_hwctx *hwctx)
|
||||
{
|
||||
unsigned long hwctx_id;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&client->mm_lock);
|
||||
|
||||
if (hwctx)
|
||||
return amdxdna_hwctx_expand_heap(hwctx);
|
||||
|
||||
amdxdna_for_each_hwctx(client, hwctx_id, hwctx) {
|
||||
ret = amdxdna_hwctx_expand_heap(hwctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
amdxdna_arg_bos_put(struct amdxdna_sched_job *job)
|
||||
{
|
||||
@@ -514,7 +596,6 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
goto unlock_srcu;
|
||||
}
|
||||
|
||||
|
||||
job->hwctx = hwctx;
|
||||
job->mm = current->mm;
|
||||
|
||||
@@ -612,6 +693,8 @@ int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_
|
||||
if (args->ext || args->ext_flags)
|
||||
return -EINVAL;
|
||||
|
||||
trace_amdxdna_debug_point(current->comm, args->type, "job received");
|
||||
|
||||
switch (args->type) {
|
||||
case AMDXDNA_CMD_SUBMIT_EXEC_BUF:
|
||||
return amdxdna_drm_submit_execbuf(client, args);
|
||||
@@ -620,3 +703,37 @@ int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_
|
||||
XDNA_ERR(client->xdna, "Invalid command type %d", args->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int amdxdna_drm_wait_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
{
|
||||
struct amdxdna_client *client = filp->driver_priv;
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(dev);
|
||||
struct amdxdna_drm_wait_cmd *args = data;
|
||||
struct amdxdna_hwctx *hwctx;
|
||||
int ret, idx;
|
||||
|
||||
XDNA_DBG(xdna, "PID %d ctx %d timeout set %d ms for cmd %llu",
|
||||
client->pid, args->hwctx, args->timeout, args->seq);
|
||||
|
||||
if (!xdna->dev_info->ops->cmd_wait)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
idx = srcu_read_lock(&client->hwctx_srcu);
|
||||
hwctx = xa_load(&client->hwctx_xa, args->hwctx);
|
||||
if (!hwctx) {
|
||||
XDNA_DBG(xdna, "PID %d failed to get ctx %d", client->pid, args->hwctx);
|
||||
ret = -EINVAL;
|
||||
goto unlock_ctx_srcu;
|
||||
}
|
||||
|
||||
ret = xdna->dev_info->ops->cmd_wait(hwctx, args->seq, args->timeout);
|
||||
|
||||
XDNA_DBG(xdna, "PID %d ctx %d cmd %lld wait finished, ret %d",
|
||||
client->pid, args->hwctx, args->seq, ret);
|
||||
|
||||
trace_amdxdna_debug_point(current->comm, args->seq, "job returned to user");
|
||||
|
||||
unlock_ctx_srcu:
|
||||
srcu_read_unlock(&client->hwctx_srcu, idx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ struct amdxdna_hwctx_priv;
|
||||
|
||||
enum ert_cmd_opcode {
|
||||
ERT_START_CU = 0,
|
||||
ERT_START_DPU = 18,
|
||||
ERT_CMD_CHAIN = 19,
|
||||
ERT_START_NPU = 20,
|
||||
ERT_START_NPU_PREEMPT = 21,
|
||||
@@ -105,7 +106,10 @@ struct amdxdna_hwctx {
|
||||
u32 *col_list;
|
||||
u32 start_col;
|
||||
u32 num_col;
|
||||
u32 umq_bo_hdl;
|
||||
u32 doorbell_offset;
|
||||
u32 num_unused_col;
|
||||
u32 last_attached_heap;
|
||||
|
||||
struct amdxdna_qos_info qos;
|
||||
struct amdxdna_hwctx_param_config_cu *cus;
|
||||
@@ -119,6 +123,7 @@ struct amdxdna_hwctx {
|
||||
container_of(j, struct amdxdna_sched_job, base)
|
||||
|
||||
enum amdxdna_job_opcode {
|
||||
DEFAULT_IO,
|
||||
SYNC_DEBUG_BO,
|
||||
ATTACH_DEBUG_BO,
|
||||
DETACH_DEBUG_BO,
|
||||
@@ -201,18 +206,17 @@ void amdxdna_hwctx_remove_all(struct amdxdna_client *client);
|
||||
int amdxdna_hwctx_walk(struct amdxdna_client *client, void *arg,
|
||||
int (*walk)(struct amdxdna_hwctx *hwctx, void *arg));
|
||||
int amdxdna_hwctx_sync_debug_bo(struct amdxdna_client *client, u32 debug_bo_hdl);
|
||||
int amdxdna_update_heap(struct amdxdna_client *client, struct amdxdna_hwctx *hwctx);
|
||||
|
||||
int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
struct amdxdna_drv_cmd *drv_cmd, u32 cmd_bo_hdls,
|
||||
u32 *arg_bo_hdls, u32 arg_bo_cnt,
|
||||
u32 hwctx_hdl, u64 *seq);
|
||||
|
||||
int amdxdna_cmd_wait(struct amdxdna_client *client, u32 hwctx_hdl,
|
||||
u64 seq, u32 timeout);
|
||||
|
||||
int amdxdna_drm_create_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
|
||||
int amdxdna_drm_config_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
|
||||
int amdxdna_drm_destroy_hwctx_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
|
||||
int amdxdna_drm_submit_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
|
||||
int amdxdna_drm_wait_cmd_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
|
||||
|
||||
#endif /* _AMDXDNA_CTX_H_ */
|
||||
|
||||
129
drivers/accel/amdxdna/amdxdna_debugfs.c
Normal file
129
drivers/accel/amdxdna/amdxdna_debugfs.c
Normal file
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include "amdxdna_cbuf.h"
|
||||
#include "amdxdna_debugfs.h"
|
||||
|
||||
#include <drm/drm_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define _DBGFS_FOPS(_open, _release, _write) \
|
||||
{ \
|
||||
.owner = THIS_MODULE, \
|
||||
.open = _open, \
|
||||
.read = seq_read, \
|
||||
.llseek = seq_lseek, \
|
||||
.release = _release, \
|
||||
.write = _write, \
|
||||
}
|
||||
|
||||
#define AMDXDNA_DBGFS_FOPS(_name, _show, _write) \
|
||||
static int amdxdna_dbgfs_##_name##_open(struct inode *inode, struct file *file) \
|
||||
{ \
|
||||
return single_open(file, _show, inode->i_private); \
|
||||
} \
|
||||
static int amdxdna_dbgfs_##_name##_release(struct inode *inode, struct file *file) \
|
||||
{ \
|
||||
return single_release(inode, file); \
|
||||
} \
|
||||
static const struct file_operations amdxdna_fops_##_name = \
|
||||
_DBGFS_FOPS(amdxdna_dbgfs_##_name##_open, amdxdna_dbgfs_##_name##_release, _write)
|
||||
|
||||
#define AMDXDNA_DBGFS_FILE(_name, _mode) { #_name, &amdxdna_fops_##_name, _mode }
|
||||
|
||||
#define file_to_xdna(file) (((struct seq_file *)(file)->private_data)->private)
|
||||
|
||||
static ssize_t amdxdna_carveout_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct amdxdna_dev *xdna = file_to_xdna(file);
|
||||
char kbuf[128];
|
||||
u64 size, addr;
|
||||
char *sep;
|
||||
int ret;
|
||||
|
||||
if (count == 0 || count >= sizeof(kbuf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(kbuf, buf, count))
|
||||
return -EFAULT;
|
||||
kbuf[count] = '\0';
|
||||
strim(kbuf);
|
||||
XDNA_DBG(xdna, "Trying to set carveout to %s", kbuf);
|
||||
|
||||
sep = strchr(kbuf, '@');
|
||||
if (!sep)
|
||||
return -EINVAL;
|
||||
*sep = '\0';
|
||||
sep++;
|
||||
|
||||
ret = kstrtou64(kbuf, 0, &size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kstrtou64(sep, 0, &addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Sanity check the addr and size. */
|
||||
if (!size)
|
||||
return -EINVAL;
|
||||
if (!IS_ALIGNED(addr, PAGE_SIZE) || !IS_ALIGNED(size, PAGE_SIZE))
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&xdna->dev_lock);
|
||||
|
||||
ret = amdxdna_carveout_init(xdna, addr, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int amdxdna_carveout_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct amdxdna_dev *xdna = m->private;
|
||||
u64 addr, size;
|
||||
|
||||
guard(mutex)(&xdna->dev_lock);
|
||||
amdxdna_get_carveout_conf(xdna, &addr, &size);
|
||||
seq_printf(m, "0x%llx@0x%llx\n", size, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input/output format: <carveout_size>@<carveout_address>
|
||||
*/
|
||||
AMDXDNA_DBGFS_FOPS(carveout, amdxdna_carveout_show, amdxdna_carveout_write);
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
const struct file_operations *fops;
|
||||
umode_t mode;
|
||||
} amdxdna_dbgfs_files[] = {
|
||||
AMDXDNA_DBGFS_FILE(carveout, 0600),
|
||||
};
|
||||
|
||||
void amdxdna_debugfs_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
struct drm_minor *minor = xdna->ddev.accel;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* It should be okay that debugfs fails to init.
|
||||
* We rely on DRM framework to finish debugfs.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(amdxdna_dbgfs_files); i++) {
|
||||
debugfs_create_file(amdxdna_dbgfs_files[i].name,
|
||||
amdxdna_dbgfs_files[i].mode,
|
||||
minor->debugfs_root,
|
||||
xdna,
|
||||
amdxdna_dbgfs_files[i].fops);
|
||||
}
|
||||
}
|
||||
18
drivers/accel/amdxdna/amdxdna_debugfs.h
Normal file
18
drivers/accel/amdxdna/amdxdna_debugfs.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2026, Advanced Micro Devices, Inc.
|
||||
*/
|
||||
#ifndef _AMDXDNA_DEBUGFS_H_
|
||||
#define _AMDXDNA_DEBUGFS_H_
|
||||
|
||||
#include "amdxdna_pci_drv.h"
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
void amdxdna_debugfs_init(struct amdxdna_dev *xdna);
|
||||
#else
|
||||
static inline void amdxdna_debugfs_init(struct amdxdna_dev *xdna)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "amdxdna_cbuf.h"
|
||||
#include "amdxdna_ctx.h"
|
||||
#include "amdxdna_gem.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
@@ -23,6 +24,77 @@
|
||||
|
||||
MODULE_IMPORT_NS("DMA_BUF");
|
||||
|
||||
/*
|
||||
* The dev BO could be across multiple heap BO chunks. The heap chunks should
|
||||
* be mapped to userspace and the userspace virtual address should be
|
||||
* contiguous.
|
||||
*/
|
||||
static int
|
||||
amdxdna_init_dev_bo(struct amdxdna_gem_obj *dev_bo)
|
||||
{
|
||||
struct amdxdna_client *client = dev_bo->client;
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_gem_obj *heap;
|
||||
u64 heap_addr, exp_heap_uva;
|
||||
u32 heap_id;
|
||||
|
||||
if (xa_empty(&client->dev_heap_xa)) {
|
||||
XDNA_DBG(xdna, "Empty heap xa");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
for (heap_id = 0; heap_id < client->dev_heap_nid; heap_id++) {
|
||||
heap = xa_load(&client->dev_heap_xa, heap_id);
|
||||
if (!heap) {
|
||||
XDNA_ERR(xdna, "Failed to load heap %d", heap_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
heap_addr = amdxdna_gem_dev_addr(heap);
|
||||
if (heap_addr > dev_bo->mm_node.start)
|
||||
break;
|
||||
}
|
||||
|
||||
heap_id--;
|
||||
heap = xa_load(&client->dev_heap_xa, heap_id);
|
||||
exp_heap_uva = amdxdna_gem_uva(heap);
|
||||
heap_addr = amdxdna_gem_dev_addr(heap);
|
||||
dev_bo->heap_start_id = heap_id;
|
||||
dev_bo->mem.uva = dev_bo->mm_node.start - heap_addr + exp_heap_uva;
|
||||
|
||||
for (; heap_id < client->dev_heap_nid; heap_id++) {
|
||||
heap = xa_load(&client->dev_heap_xa, heap_id);
|
||||
if (!heap) {
|
||||
XDNA_ERR(xdna, "Failed to load heap %d", heap_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
heap_addr = amdxdna_gem_uva(heap);
|
||||
if (heap_addr == AMDXDNA_INVALID_ADDR) {
|
||||
XDNA_ERR(xdna, "Heap %d is not mapped", heap_id);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (heap_addr != exp_heap_uva) {
|
||||
XDNA_ERR(xdna, "Heap %d uva is not contiguous", heap_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (heap->dev_addr + heap->mem.size >=
|
||||
dev_bo->mm_node.start + dev_bo->mem.size)
|
||||
break;
|
||||
|
||||
exp_heap_uva += heap->mem.size;
|
||||
}
|
||||
|
||||
if (heap_id == client->dev_heap_nid) {
|
||||
XDNA_DBG(xdna, "Can not find heap end");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
dev_bo->heap_end_id = heap_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
@@ -30,32 +102,22 @@ amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo)
|
||||
struct amdxdna_dev *xdna = client->xdna;
|
||||
struct amdxdna_mem *mem = &abo->mem;
|
||||
struct amdxdna_gem_obj *heap;
|
||||
unsigned long heap_id;
|
||||
u32 align;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&client->mm_lock);
|
||||
|
||||
heap = client->dev_heap;
|
||||
if (!heap) {
|
||||
ret = -EINVAL;
|
||||
goto unlock_out;
|
||||
}
|
||||
|
||||
if (amdxdna_gem_uva(heap) == AMDXDNA_INVALID_ADDR) {
|
||||
XDNA_ERR(xdna, "Invalid dev heap userptr");
|
||||
ret = -EINVAL;
|
||||
goto unlock_out;
|
||||
}
|
||||
|
||||
if (mem->size == 0 || mem->size > heap->mem.size) {
|
||||
XDNA_ERR(xdna, "Invalid dev bo size 0x%lx, limit 0x%lx",
|
||||
mem->size, heap->mem.size);
|
||||
if (!mem->size || mem->size > xdna->dev_info->dev_heap_max_size) {
|
||||
XDNA_ERR(xdna, "Invalid dev bo size 0x%lx, max heap 0x%lx",
|
||||
mem->size, xdna->dev_info->dev_heap_max_size);
|
||||
ret = -EINVAL;
|
||||
goto unlock_out;
|
||||
}
|
||||
|
||||
align = 1 << max(PAGE_SHIFT, xdna->dev_info->dev_mem_buf_shift);
|
||||
ret = drm_mm_insert_node_generic(&heap->mm, &abo->mm_node,
|
||||
ret = drm_mm_insert_node_generic(&client->dev_heap_mm,
|
||||
&abo->mm_node,
|
||||
mem->size, align,
|
||||
0, DRM_MM_INSERT_BEST);
|
||||
if (ret) {
|
||||
@@ -63,9 +125,16 @@ amdxdna_gem_heap_alloc(struct amdxdna_gem_obj *abo)
|
||||
goto unlock_out;
|
||||
}
|
||||
|
||||
client->heap_usage += mem->size;
|
||||
ret = amdxdna_init_dev_bo(abo);
|
||||
if (ret) {
|
||||
drm_mm_remove_node(&abo->mm_node);
|
||||
goto unlock_out;
|
||||
}
|
||||
|
||||
drm_gem_object_get(to_gobj(heap));
|
||||
client->heap_usage += mem->size;
|
||||
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
|
||||
abo->heap_start_id, abo->heap_end_id)
|
||||
drm_gem_object_get(to_gobj(heap));
|
||||
|
||||
unlock_out:
|
||||
mutex_unlock(&client->mm_lock);
|
||||
@@ -78,13 +147,16 @@ amdxdna_gem_heap_free(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
struct amdxdna_client *client = abo->client;
|
||||
struct amdxdna_gem_obj *heap;
|
||||
unsigned long heap_id;
|
||||
|
||||
mutex_lock(&client->mm_lock);
|
||||
|
||||
drm_mm_remove_node(&abo->mm_node);
|
||||
client->heap_usage -= abo->mem.size;
|
||||
heap = client->dev_heap;
|
||||
drm_gem_object_put(to_gobj(heap));
|
||||
|
||||
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
|
||||
abo->heap_start_id, abo->heap_end_id)
|
||||
drm_gem_object_put(to_gobj(heap));
|
||||
|
||||
mutex_unlock(&client->mm_lock);
|
||||
}
|
||||
@@ -160,31 +232,13 @@ static void amdxdna_gem_vunmap(struct amdxdna_gem_obj *abo)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain the user virtual address for accessing the BO.
|
||||
* It can be used for device to access the BO when PASID is enabled.
|
||||
*/
|
||||
u64 amdxdna_gem_uva(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
if (abo->type == AMDXDNA_BO_DEV) {
|
||||
struct amdxdna_gem_obj *heap = abo->client->dev_heap;
|
||||
u64 off = amdxdna_dev_bo_offset(abo);
|
||||
|
||||
if (amdxdna_gem_uva(heap) != AMDXDNA_INVALID_ADDR)
|
||||
return amdxdna_gem_uva(heap) + off;
|
||||
return AMDXDNA_INVALID_ADDR;
|
||||
}
|
||||
|
||||
return abo->mem.uva;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain the address for device to access the BO.
|
||||
*/
|
||||
u64 amdxdna_gem_dev_addr(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
if (abo->type == AMDXDNA_BO_DEV_HEAP)
|
||||
return abo->client->xdna->dev_info->dev_mem_base;
|
||||
return abo->dev_addr;
|
||||
if (abo->type == AMDXDNA_BO_DEV)
|
||||
return abo->mm_node.start;
|
||||
return amdxdna_obj_dma_addr(abo);
|
||||
@@ -211,7 +265,8 @@ static bool amdxdna_hmm_invalidate(struct mmu_interval_notifier *mni,
|
||||
mmu_interval_set_seq(&mapp->notifier, cur_seq);
|
||||
up_write(&xdna->notifier_lock);
|
||||
|
||||
xdna->dev_info->ops->hmm_invalidate(abo, cur_seq);
|
||||
if (xdna->dev_info->ops->hmm_invalidate)
|
||||
xdna->dev_info->ops->hmm_invalidate(abo, cur_seq);
|
||||
|
||||
if (range->event == MMU_NOTIFY_UNMAP) {
|
||||
down_write(&xdna->notifier_lock);
|
||||
@@ -294,8 +349,11 @@ static int amdxdna_hmm_register(struct amdxdna_gem_obj *abo,
|
||||
u32 nr_pages;
|
||||
int ret;
|
||||
|
||||
if (!xdna->dev_info->ops->hmm_invalidate)
|
||||
if (!amdxdna_pasid_on(abo->client)) {
|
||||
/* Need to set uva for heap uva validation */
|
||||
abo->mem.uva = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mapp = kzalloc_obj(*mapp);
|
||||
if (!mapp)
|
||||
@@ -519,10 +577,6 @@ static void amdxdna_imported_obj_free(struct amdxdna_gem_obj *abo)
|
||||
static inline bool
|
||||
amdxdna_gem_skip_bo_usage(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
/* Do not count imported BOs since the buffer is not allocated by us. */
|
||||
if (is_import_bo(abo))
|
||||
return true;
|
||||
|
||||
/* Already counted as part of HEAP BO */
|
||||
if (abo->type == AMDXDNA_BO_DEV)
|
||||
return true;
|
||||
@@ -571,12 +625,7 @@ static void amdxdna_gem_obj_free(struct drm_gem_object *gobj)
|
||||
if (abo->pinned)
|
||||
amdxdna_gem_unpin(abo);
|
||||
|
||||
if (abo->type == AMDXDNA_BO_DEV_HEAP)
|
||||
drm_mm_takedown(&abo->mm);
|
||||
|
||||
if (amdxdna_iova_on(xdna))
|
||||
amdxdna_iommu_unmap_bo(xdna, abo);
|
||||
|
||||
amdxdna_dma_unmap_bo(xdna, abo);
|
||||
amdxdna_gem_vunmap(abo);
|
||||
mutex_destroy(&abo->lock);
|
||||
|
||||
@@ -594,18 +643,20 @@ static int amdxdna_gem_obj_open(struct drm_gem_object *gobj, struct drm_file *fi
|
||||
|
||||
guard(mutex)(&abo->lock);
|
||||
abo->open_ref++;
|
||||
if (abo->open_ref > 1)
|
||||
return 0;
|
||||
|
||||
if (abo->open_ref == 1) {
|
||||
/* Attached to the client when first opened by it. */
|
||||
abo->client = filp->driver_priv;
|
||||
amdxdna_gem_add_bo_usage(abo);
|
||||
}
|
||||
if (amdxdna_iova_on(xdna)) {
|
||||
ret = amdxdna_iommu_map_bo(xdna, abo);
|
||||
/* Attached to the client when first opened by it. */
|
||||
abo->client = filp->driver_priv;
|
||||
|
||||
/* No need to set up dma addr mapping in PASID mode. */
|
||||
if (!amdxdna_pasid_on(abo->client)) {
|
||||
ret = amdxdna_dma_map_bo(xdna, abo);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
amdxdna_gem_add_bo_usage(abo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -623,14 +674,59 @@ static void amdxdna_gem_obj_close(struct drm_gem_object *gobj, struct drm_file *
|
||||
}
|
||||
}
|
||||
|
||||
static int amdxdna_gem_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map)
|
||||
{
|
||||
struct amdxdna_gem_obj *abo = to_xdna_obj(obj);
|
||||
int ret;
|
||||
|
||||
iosys_map_clear(map);
|
||||
|
||||
dma_resv_assert_held(obj->resv);
|
||||
|
||||
if (is_import_bo(abo))
|
||||
ret = dma_buf_vmap(abo->dma_buf, map);
|
||||
else
|
||||
ret = drm_gem_shmem_object_vmap(obj, map);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!map->vaddr)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdxdna_gem_obj_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
|
||||
{
|
||||
struct amdxdna_gem_obj *abo = to_xdna_obj(obj);
|
||||
|
||||
dma_resv_assert_held(obj->resv);
|
||||
|
||||
if (is_import_bo(abo))
|
||||
dma_buf_vunmap(abo->dma_buf, map);
|
||||
else
|
||||
drm_gem_shmem_object_vunmap(obj, map);
|
||||
}
|
||||
|
||||
static int amdxdna_gem_dev_obj_vmap(struct drm_gem_object *obj, struct iosys_map *map)
|
||||
{
|
||||
struct amdxdna_gem_obj *abo = to_xdna_obj(obj);
|
||||
void *base = amdxdna_gem_vmap(abo->client->dev_heap);
|
||||
u64 offset = amdxdna_dev_bo_offset(abo);
|
||||
struct amdxdna_gem_obj *heap;
|
||||
void *base;
|
||||
u64 offset;
|
||||
|
||||
/* vmap dev bo which is across more than 1 heap is not allowed */
|
||||
if (abo->heap_start_id != abo->heap_end_id)
|
||||
return -ENOMEM;
|
||||
|
||||
heap = xa_load(&abo->client->dev_heap_xa, abo->heap_start_id);
|
||||
if (!heap)
|
||||
return -ENOMEM;
|
||||
|
||||
base = amdxdna_gem_vmap(heap);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
offset = amdxdna_gem_dev_addr(abo) - amdxdna_gem_dev_addr(heap);
|
||||
iosys_map_set_vaddr(map, base + offset);
|
||||
return 0;
|
||||
}
|
||||
@@ -648,8 +744,8 @@ static const struct drm_gem_object_funcs amdxdna_gem_shmem_funcs = {
|
||||
.pin = drm_gem_shmem_object_pin,
|
||||
.unpin = drm_gem_shmem_object_unpin,
|
||||
.get_sg_table = drm_gem_shmem_object_get_sg_table,
|
||||
.vmap = drm_gem_shmem_object_vmap,
|
||||
.vunmap = drm_gem_shmem_object_vunmap,
|
||||
.vmap = amdxdna_gem_obj_vmap,
|
||||
.vunmap = amdxdna_gem_obj_vunmap,
|
||||
.mmap = amdxdna_gem_obj_mmap,
|
||||
.vm_ops = &drm_gem_shmem_vm_ops,
|
||||
.export = amdxdna_gem_prime_export,
|
||||
@@ -721,6 +817,36 @@ amdxdna_gem_create_ubuf_object(struct drm_device *dev, struct amdxdna_drm_create
|
||||
return abo;
|
||||
}
|
||||
|
||||
static struct amdxdna_gem_obj *
|
||||
amdxdna_gem_create_cbuf_object(struct drm_device *dev, struct amdxdna_drm_create_bo *args)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(dev);
|
||||
size_t size = PAGE_ALIGN(args->size);
|
||||
struct drm_gem_object *gobj;
|
||||
struct amdxdna_gem_obj *ret;
|
||||
struct dma_buf *dma_buf;
|
||||
u64 align;
|
||||
|
||||
if (!size) {
|
||||
XDNA_ERR(xdna, "Invalid BO size 0x%llx", args->size);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
align = (args->type == AMDXDNA_BO_DEV_HEAP) ? xdna->dev_info->dev_mem_size : 0;
|
||||
dma_buf = amdxdna_get_cbuf(dev, size, align);
|
||||
if (IS_ERR(dma_buf))
|
||||
return ERR_CAST(dma_buf);
|
||||
|
||||
gobj = amdxdna_gem_prime_import(dev, dma_buf);
|
||||
if (IS_ERR(gobj))
|
||||
ret = ERR_CAST(gobj);
|
||||
else
|
||||
ret = to_xdna_obj(gobj);
|
||||
|
||||
dma_buf_put(dma_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct drm_gem_object *
|
||||
amdxdna_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf)
|
||||
{
|
||||
@@ -776,6 +902,8 @@ amdxdna_drm_create_share_bo(struct drm_device *dev,
|
||||
|
||||
if (args->vaddr)
|
||||
abo = amdxdna_gem_create_ubuf_object(dev, args);
|
||||
else if (amdxdna_use_carveout(to_xdna_dev(dev)))
|
||||
abo = amdxdna_gem_create_cbuf_object(dev, args);
|
||||
else
|
||||
abo = amdxdna_gem_create_shmem_object(dev, args);
|
||||
if (IS_ERR(abo))
|
||||
@@ -817,15 +945,32 @@ amdxdna_drm_create_dev_heap_bo(struct drm_device *dev,
|
||||
/* Set up heap for this client. */
|
||||
mutex_lock(&client->mm_lock);
|
||||
|
||||
if (client->dev_heap) {
|
||||
XDNA_DBG(client->xdna, "dev heap is already created");
|
||||
ret = -EBUSY;
|
||||
if (!xdna->dev_info->ops->hwctx_heap_expand &&
|
||||
client->dev_heap_nid > 0) {
|
||||
XDNA_ERR(xdna, "Heap expansion is not supported");
|
||||
ret = -EOPNOTSUPP;
|
||||
goto mm_unlock;
|
||||
}
|
||||
client->dev_heap = abo;
|
||||
drm_gem_object_get(to_gobj(abo));
|
||||
|
||||
drm_mm_init(&abo->mm, xdna->dev_info->dev_mem_base, abo->mem.size);
|
||||
if (client->total_heap_size + abo->mem.size >
|
||||
xdna->dev_info->dev_heap_max_size) {
|
||||
XDNA_ERR(xdna, "Heap size 0x%lx + 0x%lx exceeds max 0x%lx",
|
||||
client->total_heap_size, abo->mem.size,
|
||||
xdna->dev_info->dev_heap_max_size);
|
||||
ret = -ENOSPC;
|
||||
goto mm_unlock;
|
||||
}
|
||||
|
||||
ret = xa_insert(&client->dev_heap_xa, client->dev_heap_nid, abo, GFP_KERNEL);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Add heap failed %d", ret);
|
||||
goto mm_unlock;
|
||||
}
|
||||
|
||||
abo->dev_addr = xdna->dev_info->dev_mem_base + client->total_heap_size;
|
||||
client->total_heap_size += abo->mem.size;
|
||||
client->dev_heap_nid++;
|
||||
drm_gem_object_get(to_gobj(abo));
|
||||
|
||||
mutex_unlock(&client->mm_lock);
|
||||
|
||||
@@ -868,10 +1013,10 @@ amdxdna_drm_create_dev_bo(struct drm_device *dev,
|
||||
|
||||
ret = amdxdna_gem_heap_alloc(abo);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed to alloc dev bo memory, ret %d", ret);
|
||||
amdxdna_gem_destroy_obj(abo);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
drm_gem_private_object_init(dev, gobj, aligned_sz);
|
||||
|
||||
return abo;
|
||||
@@ -879,6 +1024,7 @@ amdxdna_drm_create_dev_bo(struct drm_device *dev,
|
||||
|
||||
int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
|
||||
{
|
||||
struct amdxdna_client *client = filp->driver_priv;
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(dev);
|
||||
struct amdxdna_drm_create_bo *args = data;
|
||||
struct amdxdna_gem_obj *abo;
|
||||
@@ -891,7 +1037,6 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f
|
||||
args->type, args->vaddr, args->size, args->flags);
|
||||
switch (args->type) {
|
||||
case AMDXDNA_BO_CMD:
|
||||
fallthrough;
|
||||
case AMDXDNA_BO_SHARE:
|
||||
abo = amdxdna_drm_create_share_bo(dev, args, filp);
|
||||
break;
|
||||
@@ -900,6 +1045,13 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f
|
||||
break;
|
||||
case AMDXDNA_BO_DEV:
|
||||
abo = amdxdna_drm_create_dev_bo(dev, args, filp);
|
||||
if (!IS_ERR(abo)) {
|
||||
mutex_lock(&xdna->dev_lock);
|
||||
ret = amdxdna_update_heap(client, NULL);
|
||||
mutex_unlock(&xdna->dev_lock);
|
||||
if (ret)
|
||||
goto put_obj;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -923,14 +1075,11 @@ int amdxdna_drm_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_f
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo)
|
||||
static int amdxdna_bo_pin(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
|
||||
int ret;
|
||||
|
||||
if (abo->type == AMDXDNA_BO_DEV)
|
||||
abo = abo->client->dev_heap;
|
||||
|
||||
if (is_import_bo(abo))
|
||||
return 0;
|
||||
|
||||
@@ -940,6 +1089,45 @@ int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void amdxdna_bo_unpin(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(to_gobj(abo)->dev);
|
||||
|
||||
if (is_import_bo(abo))
|
||||
return;
|
||||
|
||||
drm_gem_shmem_unpin(&abo->base);
|
||||
|
||||
XDNA_DBG(xdna, "BO type %d", abo->type);
|
||||
}
|
||||
|
||||
int amdxdna_gem_pin_nolock(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
struct amdxdna_client *client = abo->client;
|
||||
struct amdxdna_gem_obj *heap;
|
||||
unsigned long heap_id, last = ULONG_MAX;
|
||||
int ret = 0;
|
||||
|
||||
if (abo->type != AMDXDNA_BO_DEV)
|
||||
return amdxdna_bo_pin(abo);
|
||||
|
||||
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
|
||||
abo->heap_start_id, abo->heap_end_id) {
|
||||
ret = amdxdna_bo_pin(heap);
|
||||
if (ret)
|
||||
break;
|
||||
last = heap_id;
|
||||
}
|
||||
|
||||
if (ret && last <= abo->heap_end_id) {
|
||||
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
|
||||
abo->heap_start_id, last)
|
||||
amdxdna_bo_unpin(heap);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int amdxdna_gem_pin(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
int ret;
|
||||
@@ -953,14 +1141,18 @@ int amdxdna_gem_pin(struct amdxdna_gem_obj *abo)
|
||||
|
||||
void amdxdna_gem_unpin(struct amdxdna_gem_obj *abo)
|
||||
{
|
||||
if (abo->type == AMDXDNA_BO_DEV)
|
||||
abo = abo->client->dev_heap;
|
||||
|
||||
if (is_import_bo(abo))
|
||||
return;
|
||||
|
||||
mutex_lock(&abo->lock);
|
||||
drm_gem_shmem_unpin(&abo->base);
|
||||
if (abo->type == AMDXDNA_BO_DEV) {
|
||||
struct amdxdna_gem_obj *heap;
|
||||
unsigned long heap_id;
|
||||
|
||||
xa_for_each_range(&abo->client->dev_heap_xa, heap_id, heap,
|
||||
abo->heap_start_id, abo->heap_end_id)
|
||||
amdxdna_bo_unpin(heap);
|
||||
} else {
|
||||
amdxdna_bo_unpin(abo);
|
||||
}
|
||||
|
||||
mutex_unlock(&abo->lock);
|
||||
}
|
||||
|
||||
@@ -1017,6 +1209,29 @@ int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amdxdna_flush_bo(struct amdxdna_gem_obj *abo, u64 offset, u64 size)
|
||||
{
|
||||
u64 end;
|
||||
|
||||
if (offset >= abo->mem.size)
|
||||
return -EINVAL;
|
||||
|
||||
if (check_add_overflow(offset, size, &end))
|
||||
return -EINVAL;
|
||||
|
||||
size = min(abo->mem.size, end) - offset;
|
||||
if (is_import_bo(abo))
|
||||
drm_clflush_sg(abo->base.sgt);
|
||||
else if (amdxdna_gem_vmap(abo))
|
||||
drm_clflush_virt_range(amdxdna_gem_vmap(abo) + offset, size);
|
||||
else if (abo->base.pages)
|
||||
drm_clflush_pages(abo->base.pages, abo->mem.size >> PAGE_SHIFT);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The sync bo ioctl is to make sure the CPU cache is in sync with memory.
|
||||
* This is required because NPU is not cache coherent device. CPU cache
|
||||
@@ -1027,11 +1242,12 @@ int amdxdna_drm_get_bo_info_ioctl(struct drm_device *dev, void *data, struct drm
|
||||
int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *filp)
|
||||
{
|
||||
struct amdxdna_client *client = filp->driver_priv;
|
||||
struct amdxdna_dev *xdna = to_xdna_dev(dev);
|
||||
struct amdxdna_drm_sync_bo *args = data;
|
||||
struct amdxdna_gem_obj *abo;
|
||||
struct drm_gem_object *gobj;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
gobj = drm_gem_object_lookup(filp, args->handle);
|
||||
if (!gobj) {
|
||||
@@ -1040,23 +1256,46 @@ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
|
||||
}
|
||||
abo = to_xdna_obj(gobj);
|
||||
|
||||
ret = amdxdna_gem_pin(abo);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Pin BO %d failed, ret %d", args->handle, ret);
|
||||
goto put_obj;
|
||||
if (abo->type == AMDXDNA_BO_DEV) {
|
||||
struct amdxdna_gem_obj *heap;
|
||||
unsigned long heap_id;
|
||||
u64 bo_start = amdxdna_gem_dev_addr(abo);
|
||||
u64 flush_start = bo_start + args->offset;
|
||||
u64 flush_end = flush_start + args->size;
|
||||
|
||||
xa_for_each_range(&client->dev_heap_xa, heap_id, heap,
|
||||
abo->heap_start_id, abo->heap_end_id) {
|
||||
u64 heap_start = amdxdna_gem_dev_addr(heap);
|
||||
u64 heap_end = heap_start + heap->mem.size;
|
||||
u64 start = max(flush_start, heap_start);
|
||||
u64 end = min(flush_end, heap_end);
|
||||
|
||||
if (start >= end)
|
||||
continue;
|
||||
|
||||
ret = amdxdna_flush_bo(heap, start - heap_start, end - start);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Failed to flush heap %ld ret %d",
|
||||
heap_id, ret);
|
||||
goto put_obj;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = amdxdna_gem_pin(abo);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Pin BO %d failed, ret %d", args->handle, ret);
|
||||
goto put_obj;
|
||||
}
|
||||
|
||||
ret = amdxdna_flush_bo(abo, args->offset, args->size);
|
||||
amdxdna_gem_unpin(abo);
|
||||
|
||||
if (ret) {
|
||||
drm_WARN(&xdna->ddev, 1, "Can not get flush memory");
|
||||
goto put_obj;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_import_bo(abo))
|
||||
drm_clflush_sg(abo->base.sgt);
|
||||
else if (amdxdna_gem_vmap(abo))
|
||||
drm_clflush_virt_range(amdxdna_gem_vmap(abo) + args->offset, args->size);
|
||||
else if (abo->base.pages)
|
||||
drm_clflush_pages(abo->base.pages, gobj->size >> PAGE_SHIFT);
|
||||
else
|
||||
drm_WARN(&xdna->ddev, 1, "Can not get flush memory");
|
||||
|
||||
amdxdna_gem_unpin(abo);
|
||||
|
||||
XDNA_DBG(xdna, "Sync bo %d offset 0x%llx, size 0x%llx\n",
|
||||
args->handle, args->offset, args->size);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user