Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'drm-misc-next-2024-03-28' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

Two misc-next in one.

drm-misc-next for v6.10-rc1:

The deal of a lifetime! You get ALL of the previous
drm-misc-next-2024-03-21-1 tag!!

But WAIT, there's MORE!

Cross-subsystem Changes:
- Assorted DT binding updates.

Core Changes:
- Clarify how optional wait_hpd_asserted is.
- Shuffle Kconfig names around.

Driver Changes:
- Assorted build fixes for panthor, imagination,
- Add AUO B120XAN01.0 panels.
- Assorted small fixes to panthor, panfrost.

drm-misc-next for v6.10:
UAPI Changes:
- Move some nouveau magic constants to uapi.

Cross-subsystem Changes:
- Move drm-misc to gitlab and freedesktop hosting.
- Add entries for panfrost.

Core Changes:
- Improve placement for TTM bo's in idle/busy handling.
- Improve drm/bridge init ordering.
- Add CONFIG_DRM_WERROR, and use W=1 for drm.
- Assorted documentation updates.
- Make more (drm and driver) headers self-contained and add header
guards.
- Grab reservation lock in pin/unpin callbacks.
- Fix reservation lock handling for vmap.
- Add edp and edid panel matching, use it to fix a nearly identical
panel.

Driver Changes:
- Add drm/panthor driver and assorted fixes.
- Assorted small fixes to xlnx, panel-edp, tidss, ci, nouveau,
panel and bridge drivers.
- Add Samsung s6e3fa7, BOE NT116WHM-N44, CMN N116BCA-EA1,
CrystalClear CMT430B19N00, Startek KD050HDFIA020-C020A,
powertip PH128800T006-ZHC01 panels.
- Fix console for omapdrm.

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/bea310a6-6ff6-477e-9363-f9f053cfd12a@linux.intel.com

+15901 -824
+10
Documentation/ABI/testing/sysfs-driver-panfrost-profiling
··· 1 + What: /sys/bus/platform/drivers/panfrost/.../profiling 2 + Date: February 2024 3 + KernelVersion: 6.8.0 4 + Contact: Adrian Larumbe <adrian.larumbe@collabora.com> 5 + Description: 6 + Get/set drm fdinfo's engine and cycles profiling status. 7 + Valid values are: 8 + 0: Don't enable fdinfo job profiling sources. 9 + 1: Enable fdinfo job profiling sources, this enables both the GPU's 10 + timestamp and cycle counter registers.
+1
Documentation/devicetree/bindings/display/bridge/lvds-codec.yaml
··· 41 41 - enum: 42 42 - ti,ds90cf364a # For the DS90CF364A FPD-Link LVDS Receiver 43 43 - ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver 44 + - ti,sn65lvds94 # For the SN65DS94 LVDS serdes 44 45 - const: lvds-decoder # Generic LVDS decoders compatible fallback 45 46 - enum: 46 47 - thine,thc63lvdm83d # For the THC63LVDM83D LVDS serializer
+1
Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml
··· 19 19 - ampire,am8001280g 20 20 - bananapi,lhr050h41 21 21 - feixin,k101-im2byl02 22 + - startek,kd050hdfia020 22 23 - tdo,tl050hdv35 23 24 - wanchanglong,w552946aba 24 25 - const: ilitek,ili9881c
+2 -1
Documentation/devicetree/bindings/display/panel/novatek,nt35950.yaml
··· 19 19 either bilinear interpolation or pixel duplication. 20 20 21 21 allOf: 22 - - $ref: panel-common.yaml# 22 + - $ref: panel-common-dual.yaml# 23 23 24 24 properties: 25 25 compatible: ··· 59 59 - avee-supply 60 60 - dvdd-supply 61 61 - vddio-supply 62 + - ports 62 63 63 64 additionalProperties: false 64 65
+20 -5
Documentation/devicetree/bindings/display/panel/novatek,nt36523.yaml
··· 14 14 panels. Support video mode panels from China Star Optoelectronics 15 15 Technology (CSOT) and BOE Technology. 16 16 17 - allOf: 18 - - $ref: panel-common.yaml# 19 - 20 17 properties: 21 18 compatible: 22 19 oneOf: ··· 35 38 description: regulator that supplies the I/O voltage 36 39 37 40 reg: true 38 - ports: true 39 41 rotation: true 40 42 backlight: true 41 43 ··· 43 47 - reg 44 48 - vddio-supply 45 49 - reset-gpios 46 - - ports 50 + 51 + allOf: 52 + - $ref: panel-common-dual.yaml# 53 + - if: 54 + properties: 55 + compatible: 56 + contains: 57 + enum: 58 + - novatek,nt36523w 59 + then: 60 + properties: 61 + ports: 62 + properties: 63 + port@1: false 64 + else: 65 + properties: 66 + port: false 67 + ports: 68 + required: 69 + - port@1 47 70 48 71 unevaluatedProperties: false 49 72
+47
Documentation/devicetree/bindings/display/panel/panel-common-dual.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/display/panel/panel-common-dual.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Common Properties for Dual-Link Display Panels 8 + 9 + maintainers: 10 + - Thierry Reding <thierry.reding@gmail.com> 11 + - Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> 12 + 13 + description: 14 + Properties common for Panel IC supporting dual link panels. Devices might 15 + support also single link. 16 + 17 + allOf: 18 + - $ref: panel-common.yaml# 19 + 20 + properties: 21 + ports: 22 + $ref: /schemas/graph.yaml#/properties/ports 23 + additionalProperties: false 24 + 25 + properties: 26 + port@0: 27 + $ref: /schemas/graph.yaml#/properties/port 28 + description: First link 29 + 30 + port@1: 31 + $ref: /schemas/graph.yaml#/properties/port 32 + description: Second link 33 + 34 + "#address-cells": true 35 + "#size-cells": true 36 + 37 + required: 38 + - port@0 39 + 40 + # Single-panel setups are still allowed. 41 + oneOf: 42 + - required: 43 + - ports 44 + - required: 45 + - port 46 + 47 + additionalProperties: true
+2
Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml
··· 50 50 - panasonic,vvx10f004b00 51 51 # Panasonic 10" WUXGA TFT LCD panel 52 52 - panasonic,vvx10f034n00 53 + # Samsung s6e3fa7 1080x2220 based AMS559NK06 AMOLED panel 54 + - samsung,s6e3fa7-ams559nk06 53 55 # Samsung s6e3fc2x01 1080x2340 AMOLED panel 54 56 - samsung,s6e3fc2x01 55 57 # Samsung sofef00 1080x2280 AMOLED panel
+4
Documentation/devicetree/bindings/display/panel/panel-simple.yaml
··· 91 91 - boe,nv133fhm-n62 92 92 # BOE NV140FHM-N49 14.0" FHD a-Si FT panel 93 93 - boe,nv140fhmn49 94 + # Crystal Clear Technology CMT430B19N00 4.3" 480x272 TFT-LCD panel 95 + - cct,cmt430b19n00 94 96 # CDTech(H.K.) Electronics Limited 4.3" 480x272 color TFT-LCD panel 95 97 - cdtech,s043wq26h-ct7 96 98 # CDTech(H.K.) Electronics Limited 7" WSVGA (1024x600) TFT LCD Panel ··· 274 272 - osddisplays,osd070t1718-19ts 275 273 # One Stop Displays OSD101T2045-53TS 10.1" 1920x1200 panel 276 274 - osddisplays,osd101t2045-53ts 275 + # POWERTIP PH128800T006-ZHC01 10.1" WXGA TFT LCD panel 276 + - powertip,ph128800t006-zhc01 277 277 # POWERTIP PH800480T013-IDF2 7.0" WVGA TFT LCD panel 278 278 - powertip,ph800480t013-idf02 279 279 # QiaoDian XianShi Corporation 4"3 TFT LCD panel
+2
Documentation/devicetree/bindings/display/panel/sony,td4353-jdi.yaml
··· 23 23 reg: true 24 24 25 25 backlight: true 26 + width-mm: true 27 + height-mm: true 26 28 27 29 vddio-supply: 28 30 description: VDDIO 1.8V supply
+147
Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/gpu/arm,mali-valhall-csf.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ARM Mali Valhall GPU 8 + 9 + maintainers: 10 + - Liviu Dudau <liviu.dudau@arm.com> 11 + - Boris Brezillon <boris.brezillon@collabora.com> 12 + 13 + properties: 14 + $nodename: 15 + pattern: '^gpu@[a-f0-9]+$' 16 + 17 + compatible: 18 + oneOf: 19 + - items: 20 + - enum: 21 + - rockchip,rk3588-mali 22 + - const: arm,mali-valhall-csf # Mali Valhall GPU model/revision is fully discoverable 23 + 24 + reg: 25 + maxItems: 1 26 + 27 + interrupts: 28 + items: 29 + - description: Job interrupt 30 + - description: MMU interrupt 31 + - description: GPU interrupt 32 + 33 + interrupt-names: 34 + items: 35 + - const: job 36 + - const: mmu 37 + - const: gpu 38 + 39 + clocks: 40 + minItems: 1 41 + maxItems: 3 42 + 43 + clock-names: 44 + minItems: 1 45 + items: 46 + - const: core 47 + - const: coregroup 48 + - const: stacks 49 + 50 + mali-supply: true 51 + 52 + operating-points-v2: true 53 + opp-table: 54 + type: object 55 + 56 + power-domains: 57 + minItems: 1 58 + maxItems: 5 59 + 60 + power-domain-names: 61 + minItems: 1 62 + maxItems: 5 63 + 64 + sram-supply: true 65 + 66 + "#cooling-cells": 67 + const: 2 68 + 69 + dynamic-power-coefficient: 70 + $ref: /schemas/types.yaml#/definitions/uint32 71 + description: 72 + A u32 value that represents the running time dynamic 73 + power coefficient in units of uW/MHz/V^2. The 74 + coefficient can either be calculated from power 75 + measurements or derived by analysis. 76 + 77 + The dynamic power consumption of the GPU is 78 + proportional to the square of the Voltage (V) and 79 + the clock frequency (f). The coefficient is used to 80 + calculate the dynamic power as below - 81 + 82 + Pdyn = dynamic-power-coefficient * V^2 * f 83 + 84 + where voltage is in V, frequency is in MHz. 85 + 86 + dma-coherent: true 87 + 88 + required: 89 + - compatible 90 + - reg 91 + - interrupts 92 + - interrupt-names 93 + - clocks 94 + - mali-supply 95 + 96 + additionalProperties: false 97 + 98 + allOf: 99 + - if: 100 + properties: 101 + compatible: 102 + contains: 103 + const: rockchip,rk3588-mali 104 + then: 105 + properties: 106 + clocks: 107 + minItems: 3 108 + power-domains: 109 + maxItems: 1 110 + power-domain-names: false 111 + 112 + examples: 113 + - | 114 + #include <dt-bindings/clock/rockchip,rk3588-cru.h> 115 + #include <dt-bindings/interrupt-controller/irq.h> 116 + #include <dt-bindings/interrupt-controller/arm-gic.h> 117 + #include <dt-bindings/power/rk3588-power.h> 118 + 119 + gpu: gpu@fb000000 { 120 + compatible = "rockchip,rk3588-mali", "arm,mali-valhall-csf"; 121 + reg = <0xfb000000 0x200000>; 122 + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH 0>, 123 + <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH 0>, 124 + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH 0>; 125 + interrupt-names = "job", "mmu", "gpu"; 126 + clock-names = "core", "coregroup", "stacks"; 127 + clocks = <&cru CLK_GPU>, <&cru CLK_GPU_COREGROUP>, 128 + <&cru CLK_GPU_STACKS>; 129 + power-domains = <&power RK3588_PD_GPU>; 130 + operating-points-v2 = <&gpu_opp_table>; 131 + mali-supply = <&vdd_gpu_s0>; 132 + sram-supply = <&vdd_gpu_mem_s0>; 133 + 134 + gpu_opp_table: opp-table { 135 + compatible = "operating-points-v2"; 136 + opp-300000000 { 137 + opp-hz = /bits/ 64 <300000000>; 138 + opp-microvolt = <675000 675000 850000>; 139 + }; 140 + opp-400000000 { 141 + opp-hz = /bits/ 64 <400000000>; 142 + opp-microvolt = <675000 675000 850000>; 143 + }; 144 + }; 145 + }; 146 + 147 + ...
+2
Documentation/devicetree/bindings/vendor-prefixes.yaml
··· 256 256 description: Catalyst Semiconductor, Inc. 257 257 "^cavium,.*": 258 258 description: Cavium, Inc. 259 + "^cct,.*": 260 + description: Crystal Clear Technology Sdn. Bhd. 259 261 "^cdns,.*": 260 262 description: Cadence Design Systems Inc. 261 263 "^cdtech,.*":
+5
Documentation/gpu/driver-uapi.rst
··· 18 18 19 19 .. kernel-doc:: include/uapi/drm/nouveau_drm.h 20 20 21 + drm/panthor uAPI 22 + ================ 23 + 24 + .. kernel-doc:: include/uapi/drm/panthor_drm.h 25 + 21 26 drm/xe uAPI 22 27 =========== 23 28
+9
Documentation/gpu/panfrost.rst
··· 38 38 39 39 Possible `drm-engine-` key names are: `fragment`, and `vertex-tiler`. 40 40 `drm-curfreq-` values convey the current operating frequency for that engine. 41 + 42 + Users must bear in mind that engine and cycle sampling are disabled by default, 43 + because of power saving concerns. `fdinfo` users and benchmark applications which 44 + query the fdinfo file must make sure to toggle the job profiling status of the 45 + driver by writing into the appropriate sysfs node:: 46 + 47 + echo <N> > /sys/bus/platform/drivers/panfrost/[a-f0-9]*.gpu/profiling 48 + 49 + Where `N` is either `0` or `1`, depending on the desired enablement status.
+97 -86
MAINTAINERS
··· 1671 1671 ARM KOMEDA DRM-KMS DRIVER 1672 1672 M: Liviu Dudau <liviu.dudau@arm.com> 1673 1673 S: Supported 1674 - T: git git://anongit.freedesktop.org/drm/drm-misc 1674 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 1675 1675 F: Documentation/devicetree/bindings/display/arm,komeda.yaml 1676 1676 F: Documentation/gpu/komeda-kms.rst 1677 1677 F: drivers/gpu/drm/arm/display/include/ ··· 1683 1683 R: Steven Price <steven.price@arm.com> 1684 1684 L: dri-devel@lists.freedesktop.org 1685 1685 S: Supported 1686 - T: git git://anongit.freedesktop.org/drm/drm-misc 1686 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 1687 1687 F: Documentation/gpu/panfrost.rst 1688 1688 F: drivers/gpu/drm/panfrost/ 1689 1689 F: include/uapi/drm/panfrost_drm.h 1690 1690 1691 + ARM MALI PANTHOR DRM DRIVER 1692 + M: Boris Brezillon <boris.brezillon@collabora.com> 1693 + M: Steven Price <steven.price@arm.com> 1694 + M: Liviu Dudau <liviu.dudau@arm.com> 1695 + L: dri-devel@lists.freedesktop.org 1696 + S: Supported 1697 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 1698 + F: Documentation/devicetree/bindings/gpu/arm,mali-valhall-csf.yaml 1699 + F: drivers/gpu/drm/panthor/ 1700 + F: include/uapi/drm/panthor_drm.h 1701 + 1691 1702 ARM MALI-DP DRM DRIVER 1692 1703 M: Liviu Dudau <liviu.dudau@arm.com> 1693 1704 S: Supported 1694 - T: git git://anongit.freedesktop.org/drm/drm-misc 1705 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 1695 1706 F: Documentation/devicetree/bindings/display/arm,malidp.yaml 1696 1707 F: Documentation/gpu/afbc.rst 1697 1708 F: drivers/gpu/drm/arm/ ··· 6323 6312 L: dri-devel@lists.freedesktop.org 6324 6313 L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) 6325 6314 S: Maintained 6326 - T: git git://anongit.freedesktop.org/drm/drm-misc 6315 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6327 6316 F: Documentation/driver-api/dma-buf.rst 6328 6317 F: Documentation/userspace-api/dma-buf-alloc-exchange.rst 6329 6318 F: drivers/dma-buf/ ··· 6377 6366 L: dri-devel@lists.freedesktop.org 6378 6367 L: linaro-mm-sig@lists.linaro.org (moderated for non-subscribers) 6379 6368 S: Maintained 6380 - T: git git://anongit.freedesktop.org/drm/drm-misc 6369 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6381 6370 F: drivers/dma-buf/dma-heap.c 6382 6371 F: drivers/dma-buf/heaps/* 6383 6372 F: include/linux/dma-heap.h ··· 6586 6575 M: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com> 6587 6576 L: dri-devel@lists.freedesktop.org 6588 6577 S: Supported 6589 - T: git git://anongit.freedesktop.org/drm/drm-misc 6578 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6590 6579 F: drivers/accel/ivpu/ 6591 6580 F: include/uapi/drm/ivpu_accel.h 6592 6581 ··· 6606 6595 R: Jernej Skrabec <jernej.skrabec@gmail.com> 6607 6596 L: dri-devel@lists.freedesktop.org 6608 6597 S: Supported 6609 - T: git git://anongit.freedesktop.org/drm/drm-misc 6598 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6610 6599 F: drivers/gpu/drm/sun4i/sun8i* 6611 6600 6612 6601 DRM DRIVER FOR ARM PL111 CLCD 6613 6602 S: Orphan 6614 - T: git git://anongit.freedesktop.org/drm/drm-misc 6603 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6615 6604 F: drivers/gpu/drm/pl111/ 6616 6605 6617 6606 DRM DRIVER FOR ARM VERSATILE TFT PANELS 6618 6607 M: Linus Walleij <linus.walleij@linaro.org> 6619 6608 S: Maintained 6620 - T: git git://anongit.freedesktop.org/drm/drm-misc 6609 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6621 6610 F: Documentation/devicetree/bindings/display/panel/arm,versatile-tft-panel.yaml 6622 6611 F: drivers/gpu/drm/panel/panel-arm-versatile.c 6623 6612 ··· 6625 6614 M: Joel Stanley <joel@jms.id.au> 6626 6615 L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) 6627 6616 S: Supported 6628 - T: git git://anongit.freedesktop.org/drm/drm-misc 6617 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6629 6618 F: Documentation/devicetree/bindings/gpu/aspeed-gfx.txt 6630 6619 F: drivers/gpu/drm/aspeed/ 6631 6620 ··· 6635 6624 R: Jocelyn Falempe <jfalempe@redhat.com> 6636 6625 L: dri-devel@lists.freedesktop.org 6637 6626 S: Supported 6638 - T: git git://anongit.freedesktop.org/drm/drm-misc 6627 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6639 6628 F: drivers/gpu/drm/ast/ 6640 6629 6641 6630 DRM DRIVER FOR BOCHS VIRTUAL GPU 6642 6631 M: Gerd Hoffmann <kraxel@redhat.com> 6643 6632 L: virtualization@lists.linux.dev 6644 6633 S: Maintained 6645 - T: git git://anongit.freedesktop.org/drm/drm-misc 6634 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6646 6635 F: drivers/gpu/drm/tiny/bochs.c 6647 6636 6648 6637 DRM DRIVER FOR BOE HIMAX8279D PANELS ··· 6660 6649 DRM DRIVER FOR EBBG FT8719 PANEL 6661 6650 M: Joel Selvaraj <jo@jsfamily.in> 6662 6651 S: Maintained 6663 - T: git git://anongit.freedesktop.org/drm/drm-misc 6652 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6664 6653 F: Documentation/devicetree/bindings/display/panel/ebbg,ft8719.yaml 6665 6654 F: drivers/gpu/drm/panel/panel-ebbg-ft8719.c 6666 6655 6667 6656 DRM DRIVER FOR FARADAY TVE200 TV ENCODER 6668 6657 M: Linus Walleij <linus.walleij@linaro.org> 6669 6658 S: Maintained 6670 - T: git git://anongit.freedesktop.org/drm/drm-misc 6659 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6671 6660 F: drivers/gpu/drm/tve200/ 6672 6661 6673 6662 DRM DRIVER FOR FEIXIN K101 IM2BA02 MIPI-DSI LCD PANELS ··· 6687 6676 M: Javier Martinez Canillas <javierm@redhat.com> 6688 6677 L: dri-devel@lists.freedesktop.org 6689 6678 S: Maintained 6690 - T: git git://anongit.freedesktop.org/drm/drm-misc 6679 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6691 6680 F: drivers/gpu/drm/drm_aperture.c 6692 6681 F: drivers/gpu/drm/tiny/ofdrm.c 6693 6682 F: drivers/gpu/drm/tiny/simpledrm.c ··· 6706 6695 M: Noralf Trønnes <noralf@tronnes.org> 6707 6696 S: Maintained 6708 6697 W: https://github.com/notro/gud/wiki 6709 - T: git git://anongit.freedesktop.org/drm/drm-misc 6698 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6710 6699 F: drivers/gpu/drm/gud/ 6711 6700 F: include/drm/gud.h 6712 6701 6713 6702 DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS 6714 6703 M: Hans de Goede <hdegoede@redhat.com> 6715 6704 S: Maintained 6716 - T: git git://anongit.freedesktop.org/drm/drm-misc 6705 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6717 6706 F: drivers/gpu/drm/tiny/gm12u320.c 6718 6707 6719 6708 DRM DRIVER FOR HIMAX HX8394 MIPI-DSI LCD panels 6720 6709 M: Ondrej Jirman <megi@xff.cz> 6721 6710 M: Javier Martinez Canillas <javierm@redhat.com> 6722 6711 S: Maintained 6723 - T: git git://anongit.freedesktop.org/drm/drm-misc 6712 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6724 6713 F: Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml 6725 6714 F: drivers/gpu/drm/panel/panel-himax-hx8394.c 6726 6715 6727 6716 DRM DRIVER FOR HX8357D PANELS 6728 6717 S: Orphan 6729 - T: git git://anongit.freedesktop.org/drm/drm-misc 6718 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6730 6719 F: Documentation/devicetree/bindings/display/himax,hx8357d.txt 6731 6720 F: drivers/gpu/drm/tiny/hx8357d.c 6732 6721 ··· 6735 6724 L: linux-hyperv@vger.kernel.org 6736 6725 L: dri-devel@lists.freedesktop.org 6737 6726 S: Maintained 6738 - T: git git://anongit.freedesktop.org/drm/drm-misc 6727 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6739 6728 F: drivers/gpu/drm/hyperv 6740 6729 6741 6730 DRM DRIVER FOR ILITEK ILI9225 PANELS 6742 6731 M: David Lechner <david@lechnology.com> 6743 6732 S: Maintained 6744 - T: git git://anongit.freedesktop.org/drm/drm-misc 6733 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6745 6734 F: Documentation/devicetree/bindings/display/ilitek,ili9225.txt 6746 6735 F: drivers/gpu/drm/tiny/ili9225.c 6747 6736 6748 6737 DRM DRIVER FOR ILITEK ILI9486 PANELS 6749 6738 M: Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com> 6750 6739 S: Maintained 6751 - T: git git://anongit.freedesktop.org/drm/drm-misc 6740 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6752 6741 F: Documentation/devicetree/bindings/display/ilitek,ili9486.yaml 6753 6742 F: drivers/gpu/drm/tiny/ili9486.c 6754 6743 ··· 6767 6756 DRM DRIVER FOR LOGICVC DISPLAY CONTROLLER 6768 6757 M: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 6769 6758 S: Supported 6770 - T: git git://anongit.freedesktop.org/drm/drm-misc 6759 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6771 6760 F: drivers/gpu/drm/logicvc/ 6772 6761 6773 6762 DRM DRIVER FOR LVDS PANELS 6774 6763 M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 6775 6764 L: dri-devel@lists.freedesktop.org 6776 6765 S: Maintained 6777 - T: git git://anongit.freedesktop.org/drm/drm-misc 6766 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6778 6767 F: Documentation/devicetree/bindings/display/lvds.yaml 6779 6768 F: Documentation/devicetree/bindings/display/panel/panel-lvds.yaml 6780 6769 F: drivers/gpu/drm/panel/panel-lvds.c ··· 6792 6781 R: Jocelyn Falempe <jfalempe@redhat.com> 6793 6782 L: dri-devel@lists.freedesktop.org 6794 6783 S: Supported 6795 - T: git git://anongit.freedesktop.org/drm/drm-misc 6784 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6796 6785 F: drivers/gpu/drm/mgag200/ 6797 6786 6798 6787 DRM DRIVER FOR MI0283QT 6799 6788 M: Noralf Trønnes <noralf@tronnes.org> 6800 6789 S: Maintained 6801 - T: git git://anongit.freedesktop.org/drm/drm-misc 6790 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6802 6791 F: Documentation/devicetree/bindings/display/multi-inno,mi0283qt.txt 6803 6792 F: drivers/gpu/drm/tiny/mi0283qt.c 6804 6793 ··· 6806 6795 M: Noralf Trønnes <noralf@tronnes.org> 6807 6796 S: Maintained 6808 6797 W: https://github.com/notro/panel-mipi-dbi/wiki 6809 - T: git git://anongit.freedesktop.org/drm/drm-misc 6798 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6810 6799 F: Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml 6811 6800 F: drivers/gpu/drm/tiny/panel-mipi-dbi.c 6812 6801 ··· 6830 6819 DRM DRIVER FOR NOVATEK NT35510 PANELS 6831 6820 M: Linus Walleij <linus.walleij@linaro.org> 6832 6821 S: Maintained 6833 - T: git git://anongit.freedesktop.org/drm/drm-misc 6822 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6834 6823 F: Documentation/devicetree/bindings/display/panel/novatek,nt35510.yaml 6835 6824 F: drivers/gpu/drm/panel/panel-novatek-nt35510.c 6836 6825 6837 6826 DRM DRIVER FOR NOVATEK NT35560 PANELS 6838 6827 M: Linus Walleij <linus.walleij@linaro.org> 6839 6828 S: Maintained 6840 - T: git git://anongit.freedesktop.org/drm/drm-misc 6829 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6841 6830 F: Documentation/devicetree/bindings/display/panel/sony,acx424akp.yaml 6842 6831 F: drivers/gpu/drm/panel/panel-novatek-nt35560.c 6843 6832 6844 6833 DRM DRIVER FOR NOVATEK NT36523 PANELS 6845 6834 M: Jianhua Lu <lujianhua000@gmail.com> 6846 6835 S: Maintained 6847 - T: git git://anongit.freedesktop.org/drm/drm-misc 6836 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6848 6837 F: Documentation/devicetree/bindings/display/panel/novatek,nt36523.yaml 6849 6838 F: drivers/gpu/drm/panel/panel-novatek-nt36523.c 6850 6839 6851 6840 DRM DRIVER FOR NOVATEK NT36672A PANELS 6852 6841 M: Sumit Semwal <sumit.semwal@linaro.org> 6853 6842 S: Maintained 6854 - T: git git://anongit.freedesktop.org/drm/drm-misc 6843 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6855 6844 F: Documentation/devicetree/bindings/display/panel/novatek,nt36672a.yaml 6856 6845 F: drivers/gpu/drm/panel/panel-novatek-nt36672a.c 6857 6846 ··· 6885 6874 DRM DRIVER FOR PERVASIVE DISPLAYS REPAPER PANELS 6886 6875 M: Noralf Trønnes <noralf@tronnes.org> 6887 6876 S: Maintained 6888 - T: git git://anongit.freedesktop.org/drm/drm-misc 6877 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6889 6878 F: Documentation/devicetree/bindings/display/repaper.txt 6890 6879 F: drivers/gpu/drm/tiny/repaper.c 6891 6880 ··· 6895 6884 L: virtualization@lists.linux.dev 6896 6885 S: Obsolete 6897 6886 W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/ 6898 - T: git git://anongit.freedesktop.org/drm/drm-misc 6887 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6899 6888 F: drivers/gpu/drm/tiny/cirrus.c 6900 6889 6901 6890 DRM DRIVER FOR QXL VIRTUAL GPU ··· 6904 6893 L: virtualization@lists.linux.dev 6905 6894 L: spice-devel@lists.freedesktop.org 6906 6895 S: Maintained 6907 - T: git git://anongit.freedesktop.org/drm/drm-misc 6896 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6908 6897 F: drivers/gpu/drm/qxl/ 6909 6898 F: include/uapi/drm/qxl_drm.h 6910 6899 ··· 6917 6906 DRM DRIVER FOR SAMSUNG DB7430 PANELS 6918 6907 M: Linus Walleij <linus.walleij@linaro.org> 6919 6908 S: Maintained 6920 - T: git git://anongit.freedesktop.org/drm/drm-misc 6909 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6921 6910 F: Documentation/devicetree/bindings/display/panel/samsung,lms397kf04.yaml 6922 6911 F: drivers/gpu/drm/panel/panel-samsung-db7430.c 6923 6912 ··· 6926 6915 M: Jagan Teki <jagan@amarulasolutions.com> 6927 6916 M: Marek Szyprowski <m.szyprowski@samsung.com> 6928 6917 S: Maintained 6929 - T: git git://anongit.freedesktop.org/drm/drm-misc 6918 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6930 6919 F: Documentation/devicetree/bindings/display/bridge/samsung,mipi-dsim.yaml 6931 6920 F: drivers/gpu/drm/bridge/samsung-dsim.c 6932 6921 F: include/drm/bridge/samsung-dsim.h ··· 6946 6935 DRM DRIVER FOR SITRONIX ST7586 PANELS 6947 6936 M: David Lechner <david@lechnology.com> 6948 6937 S: Maintained 6949 - T: git git://anongit.freedesktop.org/drm/drm-misc 6938 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6950 6939 F: Documentation/devicetree/bindings/display/sitronix,st7586.txt 6951 6940 F: drivers/gpu/drm/tiny/st7586.c 6952 6941 ··· 6967 6956 DRM DRIVER FOR SITRONIX ST7735R PANELS 6968 6957 M: David Lechner <david@lechnology.com> 6969 6958 S: Maintained 6970 - T: git git://anongit.freedesktop.org/drm/drm-misc 6959 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6971 6960 F: Documentation/devicetree/bindings/display/sitronix,st7735r.yaml 6972 6961 F: drivers/gpu/drm/tiny/st7735r.c 6973 6962 6974 6963 DRM DRIVER FOR SOLOMON SSD130X OLED DISPLAYS 6975 6964 M: Javier Martinez Canillas <javierm@redhat.com> 6976 6965 S: Maintained 6977 - T: git git://anongit.freedesktop.org/drm/drm-misc 6966 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6978 6967 F: Documentation/devicetree/bindings/display/solomon,ssd-common.yaml 6979 6968 F: Documentation/devicetree/bindings/display/solomon,ssd13*.yaml 6980 6969 F: drivers/gpu/drm/solomon/ssd130x* ··· 6982 6971 DRM DRIVER FOR ST-ERICSSON MCDE 6983 6972 M: Linus Walleij <linus.walleij@linaro.org> 6984 6973 S: Maintained 6985 - T: git git://anongit.freedesktop.org/drm/drm-misc 6974 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 6986 6975 F: Documentation/devicetree/bindings/display/ste,mcde.yaml 6987 6976 F: drivers/gpu/drm/mcde/ 6988 6977 ··· 7006 6995 DRM DRIVER FOR TPO TPG110 PANELS 7007 6996 M: Linus Walleij <linus.walleij@linaro.org> 7008 6997 S: Maintained 7009 - T: git git://anongit.freedesktop.org/drm/drm-misc 6998 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7010 6999 F: Documentation/devicetree/bindings/display/panel/tpo,tpg110.yaml 7011 7000 F: drivers/gpu/drm/panel/panel-tpo-tpg110.c 7012 7001 ··· 7016 7005 R: Thomas Zimmermann <tzimmermann@suse.de> 7017 7006 L: dri-devel@lists.freedesktop.org 7018 7007 S: Supported 7019 - T: git git://anongit.freedesktop.org/drm/drm-misc 7008 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7020 7009 F: drivers/gpu/drm/udl/ 7021 7010 7022 7011 DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS) ··· 7027 7016 R: Daniel Vetter <daniel@ffwll.ch> 7028 7017 L: dri-devel@lists.freedesktop.org 7029 7018 S: Maintained 7030 - T: git git://anongit.freedesktop.org/drm/drm-misc 7019 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7031 7020 F: Documentation/gpu/vkms.rst 7032 7021 F: drivers/gpu/drm/vkms/ 7033 7022 ··· 7035 7024 M: Hans de Goede <hdegoede@redhat.com> 7036 7025 L: dri-devel@lists.freedesktop.org 7037 7026 S: Maintained 7038 - T: git git://anongit.freedesktop.org/drm/drm-misc 7027 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7039 7028 F: drivers/gpu/drm/vboxvideo/ 7040 7029 7041 7030 DRM DRIVER FOR VMWARE VIRTUAL GPU ··· 7043 7032 R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com> 7044 7033 L: dri-devel@lists.freedesktop.org 7045 7034 S: Supported 7046 - T: git git://anongit.freedesktop.org/drm/drm-misc 7035 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7047 7036 F: drivers/gpu/drm/vmwgfx/ 7048 7037 F: include/uapi/drm/vmwgfx_drm.h 7049 7038 7050 7039 DRM DRIVER FOR WIDECHIPS WS2401 PANELS 7051 7040 M: Linus Walleij <linus.walleij@linaro.org> 7052 7041 S: Maintained 7053 - T: git git://anongit.freedesktop.org/drm/drm-misc 7042 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7054 7043 F: Documentation/devicetree/bindings/display/panel/samsung,lms380kf01.yaml 7055 7044 F: drivers/gpu/drm/panel/panel-widechips-ws2401.c 7056 7045 ··· 7075 7064 M: Maxime Ripard <mripard@kernel.org> 7076 7065 M: Thomas Zimmermann <tzimmermann@suse.de> 7077 7066 S: Maintained 7078 - W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html 7079 - T: git git://anongit.freedesktop.org/drm/drm-misc 7067 + W: https://drm.pages.freedesktop.org/maintainer-tools/drm-misc.html 7068 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7080 7069 F: Documentation/devicetree/bindings/display/ 7081 7070 F: Documentation/devicetree/bindings/gpu/ 7082 7071 F: Documentation/gpu/ ··· 7103 7092 M: Chen-Yu Tsai <wens@csie.org> 7104 7093 L: dri-devel@lists.freedesktop.org 7105 7094 S: Supported 7106 - T: git git://anongit.freedesktop.org/drm/drm-misc 7095 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7107 7096 F: Documentation/devicetree/bindings/display/allwinner* 7108 7097 F: drivers/gpu/drm/sun4i/ 7109 7098 ··· 7113 7102 L: linux-amlogic@lists.infradead.org 7114 7103 S: Supported 7115 7104 W: http://linux-meson.com/ 7116 - T: git git://anongit.freedesktop.org/drm/drm-misc 7105 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7117 7106 F: Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.yaml 7118 7107 F: Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml 7119 7108 F: Documentation/gpu/meson.rst ··· 7125 7114 M: Boris Brezillon <bbrezillon@kernel.org> 7126 7115 L: dri-devel@lists.freedesktop.org 7127 7116 S: Supported 7128 - T: git git://anongit.freedesktop.org/drm/drm-misc 7117 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7129 7118 F: Documentation/devicetree/bindings/display/atmel/ 7130 7119 F: drivers/gpu/drm/atmel-hlcdc/ 7131 7120 ··· 7137 7126 R: Jonas Karlman <jonas@kwiboo.se> 7138 7127 R: Jernej Skrabec <jernej.skrabec@gmail.com> 7139 7128 S: Maintained 7140 - T: git git://anongit.freedesktop.org/drm/drm-misc 7129 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7141 7130 F: Documentation/devicetree/bindings/display/bridge/ 7142 7131 F: drivers/gpu/drm/bridge/ 7143 7132 F: drivers/gpu/drm/drm_bridge.c ··· 7162 7151 M: Alison Wang <alison.wang@nxp.com> 7163 7152 L: dri-devel@lists.freedesktop.org 7164 7153 S: Supported 7165 - T: git git://anongit.freedesktop.org/drm/drm-misc 7154 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7166 7155 F: Documentation/devicetree/bindings/display/fsl,dcu.txt 7167 7156 F: Documentation/devicetree/bindings/display/fsl,tcon.txt 7168 7157 F: drivers/gpu/drm/fsl-dcu/ ··· 7171 7160 M: Philipp Zabel <p.zabel@pengutronix.de> 7172 7161 L: dri-devel@lists.freedesktop.org 7173 7162 S: Maintained 7174 - T: git git://anongit.freedesktop.org/drm/drm-misc 7163 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7175 7164 T: git git://git.pengutronix.de/git/pza/linux 7176 7165 F: Documentation/devicetree/bindings/display/imx/ 7177 7166 F: drivers/gpu/drm/imx/ipuv3/ ··· 7191 7180 M: Patrik Jakobsson <patrik.r.jakobsson@gmail.com> 7192 7181 L: dri-devel@lists.freedesktop.org 7193 7182 S: Maintained 7194 - T: git git://anongit.freedesktop.org/drm/drm-misc 7183 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7195 7184 F: drivers/gpu/drm/gma500/ 7196 7185 7197 7186 DRM DRIVERS FOR HISILICON ··· 7203 7192 R: John Stultz <jstultz@google.com> 7204 7193 L: dri-devel@lists.freedesktop.org 7205 7194 S: Maintained 7206 - T: git git://anongit.freedesktop.org/drm/drm-misc 7195 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7207 7196 F: Documentation/devicetree/bindings/display/hisilicon/ 7208 7197 F: drivers/gpu/drm/hisilicon/ 7209 7198 ··· 7212 7201 L: dri-devel@lists.freedesktop.org 7213 7202 L: lima@lists.freedesktop.org (moderated for non-subscribers) 7214 7203 S: Maintained 7215 - T: git git://anongit.freedesktop.org/drm/drm-misc 7204 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7216 7205 F: drivers/gpu/drm/lima/ 7217 7206 F: include/uapi/drm/lima_drm.h 7218 7207 ··· 7220 7209 M: Sui Jingfeng <suijingfeng@loongson.cn> 7221 7210 L: dri-devel@lists.freedesktop.org 7222 7211 S: Supported 7223 - T: git git://anongit.freedesktop.org/drm/drm-misc 7212 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7224 7213 F: drivers/gpu/drm/loongson/ 7225 7214 7226 7215 DRM DRIVERS FOR MEDIATEK ··· 7268 7257 L: dri-devel@lists.freedesktop.org 7269 7258 L: linux-renesas-soc@vger.kernel.org 7270 7259 S: Maintained 7271 - T: git git://anongit.freedesktop.org/drm/drm-misc 7260 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7272 7261 F: Documentation/devicetree/bindings/display/renesas,rzg2l-du.yaml 7273 7262 F: drivers/gpu/drm/renesas/rz-du/ 7274 7263 ··· 7278 7267 L: dri-devel@lists.freedesktop.org 7279 7268 L: linux-renesas-soc@vger.kernel.org 7280 7269 S: Supported 7281 - T: git git://anongit.freedesktop.org/drm/drm-misc 7270 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7282 7271 F: Documentation/devicetree/bindings/display/renesas,shmobile-lcdc.yaml 7283 7272 F: drivers/gpu/drm/renesas/shmobile/ 7284 7273 F: include/linux/platform_data/shmob_drm.h ··· 7289 7278 M: Andy Yan <andy.yan@rock-chips.com> 7290 7279 L: dri-devel@lists.freedesktop.org 7291 7280 S: Maintained 7292 - T: git git://anongit.freedesktop.org/drm/drm-misc 7281 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7293 7282 F: Documentation/devicetree/bindings/display/rockchip/ 7294 7283 F: drivers/gpu/drm/ci/xfails/rockchip* 7295 7284 F: drivers/gpu/drm/rockchip/ ··· 7298 7287 M: Alain Volmat <alain.volmat@foss.st.com> 7299 7288 L: dri-devel@lists.freedesktop.org 7300 7289 S: Maintained 7301 - T: git git://anongit.freedesktop.org/drm/drm-misc 7290 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7302 7291 F: Documentation/devicetree/bindings/display/st,stih4xx.txt 7303 7292 F: drivers/gpu/drm/sti 7304 7293 ··· 7308 7297 M: Philippe Cornu <philippe.cornu@foss.st.com> 7309 7298 L: dri-devel@lists.freedesktop.org 7310 7299 S: Maintained 7311 - T: git git://anongit.freedesktop.org/drm/drm-misc 7300 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7312 7301 F: Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml 7313 7302 F: drivers/gpu/drm/stm 7314 7303 ··· 7317 7306 M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 7318 7307 L: dri-devel@lists.freedesktop.org 7319 7308 S: Maintained 7320 - T: git git://anongit.freedesktop.org/drm/drm-misc 7309 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7321 7310 F: Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml 7322 7311 F: Documentation/devicetree/bindings/display/ti/ti,j721e-dss.yaml 7323 7312 F: Documentation/devicetree/bindings/display/ti/ti,k2g-dss.yaml ··· 7328 7317 M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 7329 7318 L: dri-devel@lists.freedesktop.org 7330 7319 S: Maintained 7331 - T: git git://anongit.freedesktop.org/drm/drm-misc 7320 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7332 7321 F: Documentation/devicetree/bindings/display/tilcdc/ 7333 7322 F: drivers/gpu/drm/tilcdc/ 7334 7323 ··· 7336 7325 M: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 7337 7326 L: dri-devel@lists.freedesktop.org 7338 7327 S: Maintained 7339 - T: git git://anongit.freedesktop.org/drm/drm-misc 7328 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7340 7329 F: Documentation/devicetree/bindings/display/ti/ 7341 7330 F: drivers/gpu/drm/omapdrm/ 7342 7331 ··· 7344 7333 M: Melissa Wen <mwen@igalia.com> 7345 7334 M: Maíra Canal <mcanal@igalia.com> 7346 7335 S: Supported 7347 - T: git git://anongit.freedesktop.org/drm/drm-misc 7336 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7348 7337 F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml 7349 7338 F: drivers/gpu/drm/v3d/ 7350 7339 F: include/uapi/drm/v3d_drm.h ··· 7353 7342 M: Maxime Ripard <mripard@kernel.org> 7354 7343 S: Supported 7355 7344 T: git git://github.com/anholt/linux 7356 - T: git git://anongit.freedesktop.org/drm/drm-misc 7345 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7357 7346 F: Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml 7358 7347 F: drivers/gpu/drm/vc4/ 7359 7348 F: include/uapi/drm/vc4_drm.h ··· 7374 7363 L: dri-devel@lists.freedesktop.org 7375 7364 L: xen-devel@lists.xenproject.org (moderated for non-subscribers) 7376 7365 S: Supported 7377 - T: git git://anongit.freedesktop.org/drm/drm-misc 7366 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7378 7367 F: Documentation/gpu/xen-front.rst 7379 7368 F: drivers/gpu/drm/xen/ 7380 7369 ··· 7382 7371 M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 7383 7372 L: dri-devel@lists.freedesktop.org 7384 7373 S: Maintained 7385 - T: git git://anongit.freedesktop.org/drm/drm-misc 7374 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7386 7375 F: Documentation/devicetree/bindings/display/xlnx/ 7387 7376 F: drivers/gpu/drm/xlnx/ 7388 7377 ··· 7391 7380 M: Matthew Brost <matthew.brost@intel.com> 7392 7381 L: dri-devel@lists.freedesktop.org 7393 7382 S: Maintained 7394 - T: git git://anongit.freedesktop.org/drm/drm-misc 7383 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7395 7384 F: drivers/gpu/drm/scheduler/ 7396 7385 F: include/drm/gpu_scheduler.h 7397 7386 ··· 7401 7390 R: Sam Ravnborg <sam@ravnborg.org> 7402 7391 L: dri-devel@lists.freedesktop.org 7403 7392 S: Maintained 7404 - T: git git://anongit.freedesktop.org/drm/drm-misc 7393 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7405 7394 F: Documentation/devicetree/bindings/display/panel/ 7406 7395 F: drivers/gpu/drm/drm_panel.c 7407 7396 F: drivers/gpu/drm/panel/ ··· 7411 7400 M: Hans de Goede <hdegoede@redhat.com> 7412 7401 L: dri-devel@lists.freedesktop.org 7413 7402 S: Maintained 7414 - T: git git://anongit.freedesktop.org/drm/drm-misc 7403 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7415 7404 F: drivers/gpu/drm/drm_privacy_screen* 7416 7405 F: include/drm/drm_privacy_screen* 7417 7406 ··· 7420 7409 M: Huang Rui <ray.huang@amd.com> 7421 7410 L: dri-devel@lists.freedesktop.org 7422 7411 S: Maintained 7423 - T: git git://anongit.freedesktop.org/drm/drm-misc 7412 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7424 7413 F: drivers/gpu/drm/ttm/ 7425 7414 F: include/drm/ttm/ 7426 7415 ··· 7428 7417 M: Helen Koike <helen.koike@collabora.com> 7429 7418 L: dri-devel@lists.freedesktop.org 7430 7419 S: Maintained 7431 - T: git git://anongit.freedesktop.org/drm/drm-misc 7420 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 7432 7421 F: Documentation/gpu/automated_testing.rst 7433 7422 F: drivers/gpu/drm/ci/ 7434 7423 ··· 8494 8483 FRAMEBUFFER CORE 8495 8484 M: Daniel Vetter <daniel@ffwll.ch> 8496 8485 S: Odd Fixes 8497 - T: git git://anongit.freedesktop.org/drm/drm-misc 8486 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 8498 8487 F: drivers/video/fbdev/core/ 8499 8488 8500 8489 FRAMEBUFFER LAYER ··· 10601 10590 M: Frank Binns <frank.binns@imgtec.com> 10602 10591 M: Matt Coster <matt.coster@imgtec.com> 10603 10592 S: Supported 10604 - T: git git://anongit.freedesktop.org/drm/drm-misc 10593 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 10605 10594 F: Documentation/devicetree/bindings/gpu/img,powervr-rogue.yaml 10606 10595 F: Documentation/devicetree/bindings/gpu/img,powervr-sgx.yaml 10607 10596 F: Documentation/gpu/imagination/ ··· 11382 11371 M: Thomas Zimmermann <tzimmermann@suse.de> 11383 11372 L: dri-devel@lists.freedesktop.org 11384 11373 S: Maintained 11385 - T: git git://anongit.freedesktop.org/drm/drm-misc 11374 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 11386 11375 F: include/linux/iosys-map.h 11387 11376 11388 11377 IO_URING ··· 11575 11564 M: Phong LE <ple@baylibre.com> 11576 11565 M: Neil Armstrong <neil.armstrong@linaro.org> 11577 11566 S: Maintained 11578 - T: git git://anongit.freedesktop.org/drm/drm-misc 11567 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 11579 11568 F: Documentation/devicetree/bindings/display/bridge/ite,it66121.yaml 11580 11569 F: drivers/gpu/drm/bridge/ite-it66121.c 11581 11570 ··· 15165 15154 M: Stefan Agner <stefan@agner.ch> 15166 15155 L: dri-devel@lists.freedesktop.org 15167 15156 S: Supported 15168 - T: git git://anongit.freedesktop.org/drm/drm-misc 15157 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 15169 15158 F: Documentation/devicetree/bindings/display/fsl,lcdif.yaml 15170 15159 F: drivers/gpu/drm/mxsfb/ 15171 15160 ··· 15886 15875 R: Lucas Stach <l.stach@pengutronix.de> 15887 15876 L: dri-devel@lists.freedesktop.org 15888 15877 S: Maintained 15889 - T: git git://anongit.freedesktop.org/drm/drm-misc 15878 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 15890 15879 F: Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml 15891 15880 F: drivers/gpu/drm/imx/dcss/ 15892 15881 ··· 18190 18179 L: linux-arm-msm@vger.kernel.org 18191 18180 L: dri-devel@lists.freedesktop.org 18192 18181 S: Supported 18193 - T: git git://anongit.freedesktop.org/drm/drm-misc 18182 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 18194 18183 F: Documentation/accel/qaic/ 18195 18184 F: drivers/accel/qaic/ 18196 18185 F: include/uapi/drm/qaic_accel.h ··· 21342 21331 L: linux-media@vger.kernel.org 21343 21332 L: dri-devel@lists.freedesktop.org 21344 21333 S: Maintained 21345 - T: git git://anongit.freedesktop.org/drm/drm-misc 21334 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 21346 21335 F: Documentation/driver-api/sync_file.rst 21347 21336 F: drivers/dma-buf/dma-fence* 21348 21337 F: drivers/dma-buf/sw_sync.c ··· 23124 23113 M: Gerd Hoffmann <kraxel@redhat.com> 23125 23114 L: dri-devel@lists.freedesktop.org 23126 23115 S: Maintained 23127 - T: git git://anongit.freedesktop.org/drm/drm-misc 23116 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 23128 23117 F: drivers/dma-buf/udmabuf.c 23129 23118 F: include/uapi/linux/udmabuf.h 23130 23119 ··· 23306 23295 VGA_SWITCHEROO 23307 23296 R: Lukas Wunner <lukas@wunner.de> 23308 23297 S: Maintained 23309 - T: git git://anongit.freedesktop.org/drm/drm-misc 23298 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 23310 23299 F: Documentation/gpu/vga-switcheroo.rst 23311 23300 F: drivers/gpu/vga/vga_switcheroo.c 23312 23301 F: include/linux/vga_switcheroo.h ··· 23499 23488 L: dri-devel@lists.freedesktop.org 23500 23489 L: virtualization@lists.linux.dev 23501 23490 S: Maintained 23502 - T: git git://anongit.freedesktop.org/drm/drm-misc 23491 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 23503 23492 F: drivers/gpu/drm/ci/xfails/virtio* 23504 23493 F: drivers/gpu/drm/virtio/ 23505 23494 F: include/uapi/linux/virtio_gpu.h
+2
arch/m68k/include/asm/pgtable.h
··· 2 2 #ifndef __M68K_PGTABLE_H 3 3 #define __M68K_PGTABLE_H 4 4 5 + #include <asm/page.h> 6 + 5 7 #ifdef __uClinux__ 6 8 #include <asm/pgtable_no.h> 7 9 #else
+1 -1
arch/parisc/configs/generic-32bit_defconfig
··· 131 131 CONFIG_I2C=y 132 132 CONFIG_HWMON=m 133 133 CONFIG_DRM=m 134 - CONFIG_DRM_DP_CEC=y 134 + CONFIG_DRM_DISPLAY_DP_AUX_CEC=y 135 135 # CONFIG_DRM_I2C_CH7006 is not set 136 136 # CONFIG_DRM_I2C_SIL164 is not set 137 137 CONFIG_DRM_RADEON=m
+20 -3
drivers/gpu/drm/Kconfig
··· 74 74 75 75 config DRM_KUNIT_TEST 76 76 tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS 77 - depends on DRM && KUNIT && MMU 77 + depends on DRM 78 + depends on DRM_DISPLAY_DP_HELPER 79 + depends on DRM_DISPLAY_HELPER 80 + depends on KUNIT 81 + depends on MMU 78 82 select DRM_BUDDY 79 - select DRM_DISPLAY_DP_HELPER 80 - select DRM_DISPLAY_HELPER 81 83 select DRM_EXEC 82 84 select DRM_EXPORT_FOR_TESTS if m 83 85 select DRM_GEM_SHMEM_HELPER ··· 373 371 374 372 source "drivers/gpu/drm/panfrost/Kconfig" 375 373 374 + source "drivers/gpu/drm/panthor/Kconfig" 375 + 376 376 source "drivers/gpu/drm/aspeed/Kconfig" 377 377 378 378 source "drivers/gpu/drm/mcde/Kconfig" ··· 418 414 config DRM_PRIVACY_SCREEN 419 415 bool 420 416 default n 417 + 418 + config DRM_WERROR 419 + bool "Compile the drm subsystem with warnings as errors" 420 + depends on DRM && EXPERT 421 + default n 422 + help 423 + A kernel build should not cause any compiler warnings, and this 424 + enables the '-Werror' flag to enforce that rule in the drm subsystem. 425 + 426 + The drm subsystem enables more warnings than the kernel default, so 427 + this config option is disabled by default. 428 + 429 + If in doubt, say N.
+29
drivers/gpu/drm/Makefile
··· 5 5 6 6 CFLAGS-$(CONFIG_DRM_USE_DYNAMIC_DEBUG) += -DDYNAMIC_DEBUG_MODULE 7 7 8 + # Unconditionally enable W=1 warnings locally 9 + # --- begin copy-paste W=1 warnings from scripts/Makefile.extrawarn 10 + subdir-ccflags-y += -Wextra -Wunused -Wno-unused-parameter 11 + subdir-ccflags-y += $(call cc-option, -Wrestrict) 12 + subdir-ccflags-y += -Wmissing-format-attribute 13 + subdir-ccflags-y += -Wold-style-definition 14 + subdir-ccflags-y += -Wmissing-include-dirs 15 + subdir-ccflags-y += $(call cc-option, -Wunused-but-set-variable) 16 + subdir-ccflags-y += $(call cc-option, -Wunused-const-variable) 17 + subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned) 18 + subdir-ccflags-y += $(call cc-option, -Wformat-overflow) 19 + # FIXME: fix -Wformat-truncation warnings and uncomment 20 + #subdir-ccflags-y += $(call cc-option, -Wformat-truncation) 21 + subdir-ccflags-y += $(call cc-option, -Wstringop-truncation) 22 + # The following turn off the warnings enabled by -Wextra 23 + ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) 24 + subdir-ccflags-y += -Wno-missing-field-initializers 25 + subdir-ccflags-y += -Wno-type-limits 26 + subdir-ccflags-y += -Wno-shift-negative-value 27 + endif 28 + ifeq ($(findstring 3, $(KBUILD_EXTRA_WARN)),) 29 + subdir-ccflags-y += -Wno-sign-compare 30 + endif 31 + # --- end copy-paste 32 + 33 + # Enable -Werror in CI and development 34 + subdir-ccflags-$(CONFIG_DRM_WERROR) += -Werror 35 + 8 36 drm-y := \ 9 37 drm_aperture.o \ 10 38 drm_atomic.o \ ··· 207 179 obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/ 208 180 obj-$(CONFIG_DRM_LIMA) += lima/ 209 181 obj-$(CONFIG_DRM_PANFROST) += panfrost/ 182 + obj-$(CONFIG_DRM_PANTHOR) += panthor/ 210 183 obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ 211 184 obj-$(CONFIG_DRM_MCDE) += mcde/ 212 185 obj-$(CONFIG_DRM_TIDSS) += tidss/
+7 -5
drivers/gpu/drm/amd/amdgpu/Kconfig
··· 2 2 3 3 config DRM_AMDGPU 4 4 tristate "AMD GPU" 5 - depends on DRM && PCI && MMU 5 + depends on DRM 6 + depends on DRM_DISPLAY_DP_HELPER 7 + depends on DRM_DISPLAY_HDCP_HELPER 8 + depends on DRM_DISPLAY_HDMI_HELPER 9 + depends on DRM_DISPLAY_HELPER 10 + depends on MMU 11 + depends on PCI 6 12 depends on !UML 7 13 select FW_LOADER 8 - select DRM_DISPLAY_DP_HELPER 9 - select DRM_DISPLAY_HDMI_HELPER 10 - select DRM_DISPLAY_HDCP_HELPER 11 - select DRM_DISPLAY_HELPER 12 14 select DRM_KMS_HELPER 13 15 select DRM_SCHED 14 16 select DRM_TTM
+6
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
··· 173 173 abo->flags & AMDGPU_GEM_CREATE_PREEMPTIBLE ? 174 174 AMDGPU_PL_PREEMPT : TTM_PL_TT; 175 175 places[c].flags = 0; 176 + /* 177 + * When GTT is just an alternative to VRAM make sure that we 178 + * only use it as fallback and still try to fill up VRAM first. 179 + */ 180 + if (domain & abo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) 181 + places[c].flags |= TTM_PL_FLAG_FALLBACK; 176 182 c++; 177 183 } 178 184
+14 -15
drivers/gpu/drm/bridge/Kconfig
··· 92 92 93 93 config DRM_ITE_IT6505 94 94 tristate "ITE IT6505 DisplayPort bridge" 95 + depends on DRM_DISPLAY_DP_AUX_BUS 96 + depends on DRM_DISPLAY_DP_HELPER 97 + depends on DRM_DISPLAY_HDCP_HELPER 98 + depends on DRM_DISPLAY_HELPER 95 99 depends on OF 96 - select DRM_DISPLAY_DP_HELPER 97 - select DRM_DISPLAY_HDCP_HELPER 98 - select DRM_DISPLAY_HELPER 99 - select DRM_DP_AUX_BUS 100 100 select DRM_KMS_HELPER 101 - select DRM_DP_HELPER 102 101 select EXTCON 103 102 select CRYPTO 104 103 select CRYPTO_HASH ··· 225 226 226 227 config DRM_PARADE_PS8640 227 228 tristate "Parade PS8640 MIPI DSI to eDP Converter" 229 + depends on DRM_DISPLAY_DP_AUX_BUS 230 + depends on DRM_DISPLAY_DP_HELPER 231 + depends on DRM_DISPLAY_HELPER 228 232 depends on OF 229 - select DRM_DISPLAY_DP_HELPER 230 - select DRM_DISPLAY_HELPER 231 - select DRM_DP_AUX_BUS 232 233 select DRM_KMS_HELPER 233 234 select DRM_MIPI_DSI 234 235 select DRM_PANEL ··· 312 313 313 314 config DRM_TOSHIBA_TC358767 314 315 tristate "Toshiba TC358767 eDP bridge" 316 + depends on DRM_DISPLAY_DP_HELPER 317 + depends on DRM_DISPLAY_HELPER 315 318 depends on OF 316 - select DRM_DISPLAY_DP_HELPER 317 - select DRM_DISPLAY_HELPER 318 319 select DRM_KMS_HELPER 319 320 select REGMAP_I2C 320 321 select DRM_MIPI_DSI ··· 335 336 336 337 config DRM_TOSHIBA_TC358775 337 338 tristate "Toshiba TC358775 DSI/LVDS bridge" 339 + depends on DRM_DISPLAY_DP_HELPER 340 + depends on DRM_DISPLAY_HELPER 338 341 depends on OF 339 - select DRM_DISPLAY_DP_HELPER 340 - select DRM_DISPLAY_HELPER 341 342 select DRM_KMS_HELPER 342 343 select REGMAP_I2C 343 344 select DRM_PANEL ··· 380 381 381 382 config DRM_TI_SN65DSI86 382 383 tristate "TI SN65DSI86 DSI to eDP bridge" 384 + depends on DRM_DISPLAY_DP_AUX_BUS 385 + depends on DRM_DISPLAY_DP_HELPER 386 + depends on DRM_DISPLAY_HELPER 383 387 depends on OF 384 - select DRM_DISPLAY_DP_HELPER 385 - select DRM_DISPLAY_HELPER 386 388 select DRM_KMS_HELPER 387 389 select REGMAP_I2C 388 390 select DRM_PANEL 389 391 select DRM_MIPI_DSI 390 392 select AUXILIARY_BUS 391 - select DRM_DP_AUX_BUS 392 393 help 393 394 Texas Instruments SN65DSI86 DSI to eDP Bridge driver 394 395
+8 -8
drivers/gpu/drm/bridge/analogix/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config DRM_ANALOGIX_ANX6345 3 3 tristate "Analogix ANX6345 bridge" 4 + depends on DRM_DISPLAY_DP_HELPER 5 + depends on DRM_DISPLAY_HELPER 4 6 depends on OF 5 7 select DRM_ANALOGIX_DP 6 - select DRM_DISPLAY_DP_HELPER 7 - select DRM_DISPLAY_HELPER 8 8 select DRM_KMS_HELPER 9 9 select REGMAP_I2C 10 10 help ··· 15 15 16 16 config DRM_ANALOGIX_ANX78XX 17 17 tristate "Analogix ANX78XX bridge" 18 + depends on DRM_DISPLAY_DP_HELPER 19 + depends on DRM_DISPLAY_HELPER 18 20 select DRM_ANALOGIX_DP 19 - select DRM_DISPLAY_DP_HELPER 20 - select DRM_DISPLAY_HELPER 21 21 select DRM_KMS_HELPER 22 22 select REGMAP_I2C 23 23 help ··· 33 33 config DRM_ANALOGIX_ANX7625 34 34 tristate "Analogix Anx7625 MIPI to DP interface support" 35 35 depends on DRM 36 + depends on DRM_DISPLAY_DP_AUX_BUS 37 + depends on DRM_DISPLAY_DP_HELPER 38 + depends on DRM_DISPLAY_HDCP_HELPER 39 + depends on DRM_DISPLAY_HELPER 36 40 depends on OF 37 - select DRM_DISPLAY_DP_HELPER 38 - select DRM_DISPLAY_HDCP_HELPER 39 - select DRM_DISPLAY_HELPER 40 - select DRM_DP_AUX_BUS 41 41 select DRM_MIPI_DSI 42 42 help 43 43 ANX7625 is an ultra-low power 4K mobile HD transmitter
+4 -4
drivers/gpu/drm/bridge/cadence/Kconfig
··· 23 23 24 24 config DRM_CDNS_MHDP8546 25 25 tristate "Cadence DPI/DP bridge" 26 - select DRM_DISPLAY_DP_HELPER 27 - select DRM_DISPLAY_HDCP_HELPER 28 - select DRM_DISPLAY_HELPER 26 + depends on DRM_DISPLAY_DP_HELPER 27 + depends on DRM_DISPLAY_HDCP_HELPER 28 + depends on DRM_DISPLAY_HELPER 29 + depends on OF 29 30 select DRM_KMS_HELPER 30 31 select DRM_PANEL_BRIDGE 31 - depends on OF 32 32 help 33 33 Support Cadence DPI to DP bridge. This is an internal 34 34 bridge and is meant to be directly embedded in a SoC.
+2 -2
drivers/gpu/drm/bridge/imx/Kconfig
··· 5 5 6 6 config DRM_IMX8MP_DW_HDMI_BRIDGE 7 7 tristate "Freescale i.MX8MP HDMI-TX bridge support" 8 - depends on OF 9 8 depends on COMMON_CLK 10 - select DRM_DW_HDMI 9 + depends on DRM_DW_HDMI 10 + depends on OF 11 11 select DRM_IMX8MP_HDMI_PVI 12 12 select PHY_FSL_SAMSUNG_HDMI_PHY 13 13 help
+11 -12
drivers/gpu/drm/bridge/ite-it66121.c
··· 1540 1540 return -EINVAL; 1541 1541 } 1542 1542 1543 - if (!of_device_is_available(ep)) { 1544 - of_node_put(ep); 1545 - dev_err(ctx->dev, "The remote device is disabled\n"); 1546 - return -ENODEV; 1547 - } 1548 - 1549 1543 ctx->next_bridge = of_drm_find_bridge(ep); 1550 1544 of_node_put(ep); 1551 1545 if (!ctx->next_bridge) { ··· 1580 1586 ctx->bridge.funcs = &it66121_bridge_funcs; 1581 1587 ctx->bridge.of_node = dev->of_node; 1582 1588 ctx->bridge.type = DRM_MODE_CONNECTOR_HDMIA; 1583 - ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD; 1589 + ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; 1590 + if (client->irq > 0) { 1591 + ctx->bridge.ops |= DRM_BRIDGE_OP_HPD; 1584 1592 1585 - ret = devm_request_threaded_irq(dev, client->irq, NULL, it66121_irq_threaded_handler, 1586 - IRQF_ONESHOT, dev_name(dev), ctx); 1587 - if (ret < 0) { 1588 - dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret); 1589 - return ret; 1593 + ret = devm_request_threaded_irq(dev, client->irq, NULL, 1594 + it66121_irq_threaded_handler, 1595 + IRQF_ONESHOT, dev_name(dev), 1596 + ctx); 1597 + if (ret < 0) { 1598 + dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret); 1599 + return ret; 1600 + } 1590 1601 } 1591 1602 1592 1603 it66121_audio_codec_init(ctx, dev);
+2 -2
drivers/gpu/drm/bridge/synopsys/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config DRM_DW_HDMI 3 3 tristate 4 - select DRM_DISPLAY_HDMI_HELPER 5 - select DRM_DISPLAY_HELPER 4 + depends on DRM_DISPLAY_HDMI_HELPER 5 + depends on DRM_DISPLAY_HELPER 6 6 select DRM_KMS_HELPER 7 7 select REGMAP_MMIO 8 8 select CEC_CORE if CEC_NOTIFIER
+4 -27
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
··· 3291 3291 3292 3292 static int dw_hdmi_parse_dt(struct dw_hdmi *hdmi) 3293 3293 { 3294 - struct device_node *endpoint; 3295 3294 struct device_node *remote; 3296 3295 3297 3296 if (!hdmi->plat_data->output_port) 3298 3297 return 0; 3299 3298 3300 - endpoint = of_graph_get_endpoint_by_regs(hdmi->dev->of_node, 3301 - hdmi->plat_data->output_port, 3302 - -1); 3303 - if (!endpoint) { 3304 - /* 3305 - * On platforms whose bindings don't make the output port 3306 - * mandatory (such as Rockchip) the plat_data->output_port 3307 - * field isn't set, so it's safe to make this a fatal error. 3308 - */ 3309 - dev_err(hdmi->dev, "Missing endpoint in port@%u\n", 3310 - hdmi->plat_data->output_port); 3311 - return -ENODEV; 3312 - } 3313 3299 3314 - remote = of_graph_get_remote_port_parent(endpoint); 3315 - of_node_put(endpoint); 3316 - if (!remote) { 3317 - dev_err(hdmi->dev, "Endpoint in port@%u unconnected\n", 3318 - hdmi->plat_data->output_port); 3300 + remote = of_graph_get_remote_node(hdmi->dev->of_node, 3301 + hdmi->plat_data->output_port, 3302 + -1); 3303 + if (!remote) 3319 3304 return -ENODEV; 3320 - } 3321 - 3322 - if (!of_device_is_available(remote)) { 3323 - dev_err(hdmi->dev, "port@%u remote device is disabled\n", 3324 - hdmi->plat_data->output_port); 3325 - of_node_put(remote); 3326 - return -ENODEV; 3327 - } 3328 3305 3329 3306 hdmi->next_bridge = of_drm_find_bridge(remote); 3330 3307 of_node_put(remote);
+3 -18
drivers/gpu/drm/bridge/thc63lvd1024.c
··· 123 123 struct device_node *endpoint; 124 124 struct device_node *remote; 125 125 126 - endpoint = of_graph_get_endpoint_by_regs(thc63->dev->of_node, 127 - THC63_RGB_OUT0, -1); 128 - if (!endpoint) { 129 - dev_err(thc63->dev, "Missing endpoint in port@%u\n", 130 - THC63_RGB_OUT0); 131 - return -ENODEV; 132 - } 133 - 134 - remote = of_graph_get_remote_port_parent(endpoint); 135 - of_node_put(endpoint); 126 + remote = of_graph_get_remote_node(thc63->dev->of_node, 127 + THC63_RGB_OUT0, -1); 136 128 if (!remote) { 137 - dev_err(thc63->dev, "Endpoint in port@%u unconnected\n", 129 + dev_err(thc63->dev, "No remote endpoint for port@%u\n", 138 130 THC63_RGB_OUT0); 139 - return -ENODEV; 140 - } 141 - 142 - if (!of_device_is_available(remote)) { 143 - dev_err(thc63->dev, "port@%u remote endpoint is disabled\n", 144 - THC63_RGB_OUT0); 145 - of_node_put(remote); 146 131 return -ENODEV; 147 132 } 148 133
+3 -3
drivers/gpu/drm/ci/test.yml
··· 252 252 i915:tgl: 253 253 extends: 254 254 - .i915 255 - parallel: 8 255 + parallel: 5 256 256 variables: 257 - DEVICE_TYPE: asus-cx9400-volteer 257 + DEVICE_TYPE: acer-cp514-2h-1130g7-volteer 258 258 GPU_VERSION: tgl 259 - RUNNER_TAG: mesa-ci-x86-64-lava-asus-cx9400-volteer 259 + RUNNER_TAG: mesa-ci-x86-64-lava-acer-cp514-2h-1130g7-volteer 260 260 261 261 .amdgpu: 262 262 extends:
+41 -34
drivers/gpu/drm/display/Kconfig
··· 1 1 # SPDX-License-Identifier: MIT 2 2 3 - config DRM_DP_AUX_BUS 4 - tristate 5 - depends on DRM 6 - depends on OF || COMPILE_TEST 7 - 8 3 config DRM_DISPLAY_HELPER 9 - tristate 4 + tristate "DRM Display Helpers" 10 5 depends on DRM 6 + default y 11 7 help 12 8 DRM helpers for display adapters. 13 9 14 - config DRM_DISPLAY_DP_HELPER 15 - bool 10 + config DRM_DISPLAY_DP_AUX_BUS 11 + tristate "DRM DisplayPort AUX bus support" 12 + depends on DRM 13 + depends on OF || COMPILE_TEST 14 + default y 15 + 16 + config DRM_DISPLAY_DP_AUX_CEC 17 + bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" 18 + depends on DRM 16 19 depends on DRM_DISPLAY_HELPER 20 + depends on DRM_DISPLAY_DP_HELPER 21 + select CEC_CORE 22 + help 23 + Choose this option if you want to enable HDMI CEC support for 24 + DisplayPort/USB-C to HDMI adapters. 25 + 26 + Note: not all adapters support this feature, and even for those 27 + that do support this they often do not hook up the CEC pin. 28 + 29 + config DRM_DISPLAY_DP_AUX_CHARDEV 30 + bool "DRM DisplayPort AUX Interface" 31 + depends on DRM 32 + depends on DRM_DISPLAY_HELPER 33 + depends on DRM_DISPLAY_DP_HELPER 34 + help 35 + Choose this option to enable a /dev/drm_dp_auxN node that allows to 36 + read and write values to arbitrary DPCD registers on the DP aux 37 + channel. 38 + 39 + config DRM_DISPLAY_DP_HELPER 40 + bool "DRM DisplayPort Helpers" 41 + depends on DRM_DISPLAY_HELPER 42 + default y 17 43 help 18 44 DRM display helpers for DisplayPort. 19 45 20 46 config DRM_DISPLAY_DP_TUNNEL 21 - bool 22 - select DRM_DISPLAY_DP_HELPER 47 + bool "DRM DisplayPort tunnels support" 48 + depends on DRM_DISPLAY_DP_HELPER 23 49 help 24 50 Enable support for DisplayPort tunnels. This allows drivers to use 25 51 DP tunnel features like the Bandwidth Allocation mode to maximize the 26 52 BW utilization for display streams on Thunderbolt links. 27 53 28 - config DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE 54 + config DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG 29 55 bool "Enable debugging the DP tunnel state" 30 56 depends on REF_TRACKER 31 57 depends on DRM_DISPLAY_DP_TUNNEL ··· 65 39 If in doubt, say "N". 66 40 67 41 config DRM_DISPLAY_HDCP_HELPER 68 - bool 42 + bool "DRM HDCD Helpers" 69 43 depends on DRM_DISPLAY_HELPER 44 + default y 70 45 help 71 46 DRM display helpers for HDCP. 72 47 73 48 config DRM_DISPLAY_HDMI_HELPER 74 - bool 49 + bool "DRM HDMI Helpers" 75 50 depends on DRM_DISPLAY_HELPER 51 + default y 76 52 help 77 53 DRM display helpers for HDMI. 78 - 79 - config DRM_DP_AUX_CHARDEV 80 - bool "DRM DP AUX Interface" 81 - depends on DRM && DRM_DISPLAY_HELPER 82 - select DRM_DISPLAY_DP_HELPER 83 - help 84 - Choose this option to enable a /dev/drm_dp_auxN node that allows to 85 - read and write values to arbitrary DPCD registers on the DP aux 86 - channel. 87 - 88 - config DRM_DP_CEC 89 - bool "Enable DisplayPort CEC-Tunneling-over-AUX HDMI support" 90 - depends on DRM && DRM_DISPLAY_HELPER 91 - select DRM_DISPLAY_DP_HELPER 92 - select CEC_CORE 93 - help 94 - Choose this option if you want to enable HDMI CEC support for 95 - DisplayPort/USB-C to HDMI adapters. 96 - 97 - Note: not all adapters support this feature, and even for those 98 - that do support this they often do not hook up the CEC pin.
+3 -3
drivers/gpu/drm/display/Makefile
··· 1 1 # SPDX-License-Identifier: MIT 2 2 3 - obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o 3 + obj-$(CONFIG_DRM_DISPLAY_DP_AUX_BUS) += drm_dp_aux_bus.o 4 4 5 5 drm_display_helper-y := drm_display_helper_mod.o 6 6 drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_HELPER) += \ ··· 14 14 drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \ 15 15 drm_hdmi_helper.o \ 16 16 drm_scdc_helper.o 17 - drm_display_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o 18 - drm_display_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o 17 + drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV) += drm_dp_aux_dev.o 18 + drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_AUX_CEC) += drm_dp_cec.o 19 19 20 20 obj-$(CONFIG_DRM_DISPLAY_HELPER) += drm_display_helper.o
+1 -1
drivers/gpu/drm/display/drm_dp_helper.c
··· 2113 2113 * drm_dp_aux_register() in &drm_connector_funcs.late_register, and likewise to 2114 2114 * call drm_dp_aux_unregister() in &drm_connector_funcs.early_unregister. 2115 2115 * Functions which don't follow this will likely Oops when 2116 - * %CONFIG_DRM_DP_AUX_CHARDEV is enabled. 2116 + * %CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV is enabled. 2117 2117 * 2118 2118 * For devices where the AUX channel is a device that exists independently of 2119 2119 * the &drm_device that uses it, such as SoCs and bridge devices, it is
+1 -1
drivers/gpu/drm/display/drm_dp_helper_internal.h
··· 5 5 6 6 struct drm_dp_aux; 7 7 8 - #ifdef CONFIG_DRM_DP_AUX_CHARDEV 8 + #ifdef CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV 9 9 int drm_dp_aux_dev_init(void); 10 10 void drm_dp_aux_dev_exit(void); 11 11 int drm_dp_aux_register_devnode(struct drm_dp_aux *aux);
+3 -1
drivers/gpu/drm/display/drm_dp_mst_topology_internal.h
··· 10 10 #ifndef _DRM_DP_MST_HELPER_INTERNAL_H_ 11 11 #define _DRM_DP_MST_HELPER_INTERNAL_H_ 12 12 13 - #include <drm/display/drm_dp_mst_helper.h> 13 + struct drm_dp_sideband_msg_req_body; 14 + struct drm_dp_sideband_msg_tx; 15 + struct drm_printer; 14 16 15 17 void 16 18 drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req,
+5 -5
drivers/gpu/drm/display/drm_dp_tunnel.c
··· 191 191 struct drm_dp_tunnel_group *groups; 192 192 wait_queue_head_t bw_req_queue; 193 193 194 - #ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE 194 + #ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG 195 195 struct ref_tracker_dir ref_tracker; 196 196 #endif 197 197 }; ··· 385 385 kref_put(&tunnel->kref, free_tunnel); 386 386 } 387 387 388 - #ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE 388 + #ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG 389 389 static void track_tunnel_ref(struct drm_dp_tunnel *tunnel, 390 390 struct ref_tracker **tracker) 391 391 { ··· 1603 1603 drm_atomic_private_obj_fini(&group->base); 1604 1604 } 1605 1605 1606 - #ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE 1606 + #ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG 1607 1607 static void check_unique_stream_ids(const struct drm_dp_tunnel_group_state *group_state) 1608 1608 { 1609 1609 const struct drm_dp_tunnel_state *tunnel_state; ··· 1881 1881 drm_WARN_ON(mgr->dev, !list_empty(&mgr->groups[i].tunnels)); 1882 1882 } 1883 1883 1884 - #ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE 1884 + #ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG 1885 1885 ref_tracker_dir_exit(&mgr->ref_tracker); 1886 1886 #endif 1887 1887 ··· 1918 1918 return NULL; 1919 1919 } 1920 1920 1921 - #ifdef CONFIG_DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE 1921 + #ifdef CONFIG_DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG 1922 1922 ref_tracker_dir_init(&mgr->ref_tracker, 16, "dptun"); 1923 1923 #endif 1924 1924
+22 -2
drivers/gpu/drm/drm_bridge.c
··· 657 657 * bridge will be called before the previous one to reverse the @pre_enable 658 658 * calling direction. 659 659 * 660 + * Example: 661 + * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E 662 + * 663 + * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting 664 + * @post_disable order would be, 665 + * Bridge B, Bridge A, Bridge E, Bridge D, Bridge C. 666 + * 660 667 * Note: the bridge passed should be the one closest to the encoder 661 668 */ 662 669 void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, ··· 694 687 */ 695 688 list_for_each_entry_from(next, &encoder->bridge_chain, 696 689 chain_node) { 697 - if (next->pre_enable_prev_first) { 690 + if (!next->pre_enable_prev_first) { 698 691 next = list_prev_entry(next, chain_node); 692 + limit = next; 693 + break; 694 + } 695 + 696 + if (list_is_last(&next->chain_node, 697 + &encoder->bridge_chain)) { 699 698 limit = next; 700 699 break; 701 700 } ··· 760 747 * If a bridge sets @pre_enable_prev_first, then the pre_enable for the 761 748 * prev bridge will be called before pre_enable of this bridge. 762 749 * 750 + * Example: 751 + * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E 752 + * 753 + * With pre_enable_prev_first flag enable in Bridge B, D, E then the resulting 754 + * @pre_enable order would be, 755 + * Bridge C, Bridge D, Bridge E, Bridge A, Bridge B. 756 + * 763 757 * Note: the bridge passed should be the one closest to the encoder 764 758 */ 765 759 void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, ··· 794 774 /* Found first bridge that does NOT 795 775 * request prev to be enabled first 796 776 */ 797 - limit = list_prev_entry(next, chain_node); 777 + limit = next; 798 778 break; 799 779 } 800 780 }
+81 -11
drivers/gpu/drm/drm_client.c
··· 305 305 } 306 306 307 307 /** 308 + * drm_client_buffer_vmap_local - Map DRM client buffer into address space 309 + * @buffer: DRM client buffer 310 + * @map_copy: Returns the mapped memory's address 311 + * 312 + * This function maps a client buffer into kernel address space. If the 313 + * buffer is already mapped, it returns the existing mapping's address. 314 + * 315 + * Client buffer mappings are not ref'counted. Each call to 316 + * drm_client_buffer_vmap_local() should be closely followed by a call to 317 + * drm_client_buffer_vunmap_local(). See drm_client_buffer_vmap() for 318 + * long-term mappings. 319 + * 320 + * The returned address is a copy of the internal value. In contrast to 321 + * other vmap interfaces, you don't need it for the client's vunmap 322 + * function. So you can modify it at will during blit and draw operations. 323 + * 324 + * Returns: 325 + * 0 on success, or a negative errno code otherwise. 326 + */ 327 + int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer, 328 + struct iosys_map *map_copy) 329 + { 330 + struct drm_gem_object *gem = buffer->gem; 331 + struct iosys_map *map = &buffer->map; 332 + int ret; 333 + 334 + drm_gem_lock(gem); 335 + 336 + ret = drm_gem_vmap(gem, map); 337 + if (ret) 338 + goto err_drm_gem_vmap_unlocked; 339 + *map_copy = *map; 340 + 341 + return 0; 342 + 343 + err_drm_gem_vmap_unlocked: 344 + drm_gem_unlock(gem); 345 + return 0; 346 + } 347 + EXPORT_SYMBOL(drm_client_buffer_vmap_local); 348 + 349 + /** 350 + * drm_client_buffer_vunmap_local - Unmap DRM client buffer 351 + * @buffer: DRM client buffer 352 + * 353 + * This function removes a client buffer's memory mapping established 354 + * with drm_client_buffer_vunmap_local(). Calling this function is only 355 + * required by clients that manage their buffer mappings by themselves. 356 + */ 357 + void drm_client_buffer_vunmap_local(struct drm_client_buffer *buffer) 358 + { 359 + struct drm_gem_object *gem = buffer->gem; 360 + struct iosys_map *map = &buffer->map; 361 + 362 + drm_gem_vunmap(gem, map); 363 + drm_gem_unlock(gem); 364 + } 365 + EXPORT_SYMBOL(drm_client_buffer_vunmap_local); 366 + 367 + /** 308 368 * drm_client_buffer_vmap - Map DRM client buffer into address space 309 369 * @buffer: DRM client buffer 310 370 * @map_copy: Returns the mapped memory's address ··· 388 328 drm_client_buffer_vmap(struct drm_client_buffer *buffer, 389 329 struct iosys_map *map_copy) 390 330 { 331 + struct drm_gem_object *gem = buffer->gem; 391 332 struct iosys_map *map = &buffer->map; 392 333 int ret; 393 334 394 - /* 395 - * FIXME: The dependency on GEM here isn't required, we could 396 - * convert the driver handle to a dma-buf instead and use the 397 - * backend-agnostic dma-buf vmap support instead. This would 398 - * require that the handle2fd prime ioctl is reworked to pull the 399 - * fd_install step out of the driver backend hooks, to make that 400 - * final step optional for internal users. 401 - */ 402 - ret = drm_gem_vmap_unlocked(buffer->gem, map); 335 + drm_gem_lock(gem); 336 + 337 + ret = drm_gem_pin_locked(gem); 403 338 if (ret) 404 - return ret; 339 + goto err_drm_gem_pin_locked; 340 + ret = drm_gem_vmap(gem, map); 341 + if (ret) 342 + goto err_drm_gem_vmap; 343 + 344 + drm_gem_unlock(gem); 405 345 406 346 *map_copy = *map; 407 347 408 348 return 0; 349 + 350 + err_drm_gem_vmap: 351 + drm_gem_unpin_locked(buffer->gem); 352 + err_drm_gem_pin_locked: 353 + drm_gem_unlock(gem); 354 + return ret; 409 355 } 410 356 EXPORT_SYMBOL(drm_client_buffer_vmap); 411 357 ··· 425 359 */ 426 360 void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) 427 361 { 362 + struct drm_gem_object *gem = buffer->gem; 428 363 struct iosys_map *map = &buffer->map; 429 364 430 - drm_gem_vunmap_unlocked(buffer->gem, map); 365 + drm_gem_lock(gem); 366 + drm_gem_vunmap(gem, map); 367 + drm_gem_unpin_locked(gem); 368 + drm_gem_unlock(gem); 431 369 } 432 370 EXPORT_SYMBOL(drm_client_buffer_vunmap); 433 371
+11 -4
drivers/gpu/drm/drm_crtc_helper_internal.h
··· 26 26 * implementation details and are not exported to drivers. 27 27 */ 28 28 29 - #include <drm/drm_connector.h> 30 - #include <drm/drm_crtc.h> 31 - #include <drm/drm_encoder.h> 32 - #include <drm/drm_modes.h> 29 + #ifndef __DRM_CRTC_HELPER_INTERNAL_H__ 30 + #define __DRM_CRTC_HELPER_INTERNAL_H__ 31 + 32 + enum drm_mode_status; 33 + struct drm_connector; 34 + struct drm_crtc; 35 + struct drm_display_mode; 36 + struct drm_encoder; 37 + struct drm_modeset_acquire_ctx; 33 38 34 39 /* drm_probe_helper.c */ 35 40 enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc, ··· 49 44 50 45 struct drm_encoder * 51 46 drm_connector_get_single_encoder(struct drm_connector *connector); 47 + 48 + #endif /* __DRM_CRTC_HELPER_INTERNAL_H__ */
+7
drivers/gpu/drm/drm_crtc_internal.h
··· 32 32 * and are not exported to drivers. 33 33 */ 34 34 35 + #ifndef __DRM_CRTC_INTERNAL_H__ 36 + #define __DRM_CRTC_INTERNAL_H__ 37 + 38 + #include <linux/err.h> 35 39 #include <linux/types.h> 36 40 37 41 enum drm_color_encoding; ··· 58 54 struct drm_mode_set; 59 55 struct drm_plane; 60 56 struct drm_plane_state; 57 + struct drm_printer; 61 58 struct drm_property; 62 59 struct edid; 63 60 struct fwnode_handle; ··· 308 303 return ERR_PTR(-ENOENT); 309 304 } 310 305 #endif 306 + 307 + #endif /* __DRM_CRTC_INTERNAL_H__ */
+114 -33
drivers/gpu/drm/drm_edid.c
··· 102 102 int modes; 103 103 }; 104 104 105 + struct drm_edid_match_closure { 106 + const struct drm_edid_ident *ident; 107 + bool matched; 108 + }; 109 + 105 110 #define LEVEL_DMT 0 106 111 #define LEVEL_GTF 1 107 112 #define LEVEL_GTF2 2 ··· 114 109 115 110 #define EDID_QUIRK(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _quirks) \ 116 111 { \ 117 - .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ 118 - product_id), \ 112 + .ident = { \ 113 + .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, \ 114 + vend_chr_2, product_id), \ 115 + }, \ 119 116 .quirks = _quirks \ 120 117 } 121 118 122 119 static const struct edid_quirk { 123 - u32 panel_id; 120 + const struct drm_edid_ident ident; 124 121 u32 quirks; 125 122 } edid_quirk_list[] = { 126 123 /* Acer AL1706 */ ··· 2756 2749 } 2757 2750 EXPORT_SYMBOL(drm_edid_read); 2758 2751 2759 - static u32 edid_extract_panel_id(const struct edid *edid) 2752 + /** 2753 + * drm_edid_get_panel_id - Get a panel's ID from EDID 2754 + * @drm_edid: EDID that contains panel ID. 2755 + * 2756 + * This function uses the first block of the EDID of a panel and (assuming 2757 + * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value 2758 + * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's 2759 + * supposed to be different for each different modem of panel. 2760 + * 2761 + * Return: A 32-bit ID that should be different for each make/model of panel. 2762 + * See the functions drm_edid_encode_panel_id() and 2763 + * drm_edid_decode_panel_id() for some details on the structure of this 2764 + * ID. Return 0 if the EDID size is less than a base block. 2765 + */ 2766 + u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid) 2760 2767 { 2768 + const struct edid *edid = drm_edid->edid; 2769 + 2770 + if (drm_edid->size < EDID_LENGTH) 2771 + return 0; 2772 + 2761 2773 /* 2762 2774 * We represent the ID as a 32-bit number so it can easily be compared 2763 2775 * with "==". ··· 2794 2768 (u32)edid->mfg_id[1] << 16 | 2795 2769 (u32)EDID_PRODUCT_ID(edid); 2796 2770 } 2771 + EXPORT_SYMBOL(drm_edid_get_panel_id); 2797 2772 2798 2773 /** 2799 - * drm_edid_get_panel_id - Get a panel's ID through DDC 2774 + * drm_edid_read_base_block - Get a panel's EDID base block 2800 2775 * @adapter: I2C adapter to use for DDC 2801 2776 * 2802 - * This function reads the first block of the EDID of a panel and (assuming 2803 - * that the EDID is valid) extracts the ID out of it. The ID is a 32-bit value 2804 - * (16 bits of manufacturer ID and 16 bits of per-manufacturer ID) that's 2805 - * supposed to be different for each different modem of panel. 2777 + * This function returns the drm_edid containing the first block of the EDID of 2778 + * a panel. 2806 2779 * 2807 2780 * This function is intended to be used during early probing on devices where 2808 2781 * more than one panel might be present. Because of its intended use it must 2809 - * assume that the EDID of the panel is correct, at least as far as the ID 2810 - * is concerned (in other words, we don't process any overrides here). 2782 + * assume that the EDID of the panel is correct, at least as far as the base 2783 + * block is concerned (in other words, we don't process any overrides here). 2784 + * 2785 + * Caller should call drm_edid_free() after use. 2811 2786 * 2812 2787 * NOTE: it's expected that this function and drm_do_get_edid() will both 2813 2788 * be read the EDID, but there is no caching between them. Since we're only 2814 2789 * reading the first block, hopefully this extra overhead won't be too big. 2815 2790 * 2816 - * Return: A 32-bit ID that should be different for each make/model of panel. 2817 - * See the functions drm_edid_encode_panel_id() and 2818 - * drm_edid_decode_panel_id() for some details on the structure of this 2819 - * ID. 2791 + * WARNING: Only use this function when the connector is unknown. For example, 2792 + * during the early probe of panel. The EDID read from the function is temporary 2793 + * and should be replaced by the full EDID returned from other drm_edid_read. 2794 + * 2795 + * Return: Pointer to allocated EDID base block, or NULL on any failure. 2820 2796 */ 2821 - 2822 - u32 drm_edid_get_panel_id(struct i2c_adapter *adapter) 2797 + const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter) 2823 2798 { 2824 2799 enum edid_block_status status; 2825 2800 void *base_block; 2826 - u32 panel_id = 0; 2827 - 2828 - /* 2829 - * There are no manufacturer IDs of 0, so if there is a problem reading 2830 - * the EDID then we'll just return 0. 2831 - */ 2832 2801 2833 2802 base_block = kzalloc(EDID_LENGTH, GFP_KERNEL); 2834 2803 if (!base_block) 2835 - return 0; 2804 + return NULL; 2836 2805 2837 2806 status = edid_block_read(base_block, 0, drm_do_probe_ddc_edid, adapter); 2838 2807 2839 2808 edid_block_status_print(status, base_block, 0); 2840 2809 2841 - if (edid_block_status_valid(status, edid_block_tag(base_block))) 2842 - panel_id = edid_extract_panel_id(base_block); 2843 - else 2810 + if (!edid_block_status_valid(status, edid_block_tag(base_block))) { 2844 2811 edid_block_dump(KERN_NOTICE, base_block, 0); 2812 + kfree(base_block); 2813 + return NULL; 2814 + } 2845 2815 2846 - kfree(base_block); 2847 - 2848 - return panel_id; 2816 + return _drm_edid_alloc(base_block, EDID_LENGTH); 2849 2817 } 2850 - EXPORT_SYMBOL(drm_edid_get_panel_id); 2818 + EXPORT_SYMBOL(drm_edid_read_base_block); 2851 2819 2852 2820 /** 2853 2821 * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output ··· 2923 2903 * @drm_edid: EDID to process 2924 2904 * 2925 2905 * This tells subsequent routines what fixes they need to apply. 2906 + * 2907 + * Return: A u32 represents the quirks to apply. 2926 2908 */ 2927 2909 static u32 edid_get_quirks(const struct drm_edid *drm_edid) 2928 2910 { 2929 - u32 panel_id = edid_extract_panel_id(drm_edid->edid); 2930 2911 const struct edid_quirk *quirk; 2931 2912 int i; 2932 2913 2933 2914 for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) { 2934 2915 quirk = &edid_quirk_list[i]; 2935 - if (quirk->panel_id == panel_id) 2916 + if (drm_edid_match(drm_edid, &quirk->ident)) 2936 2917 return quirk->quirks; 2937 2918 } 2938 2919 ··· 5462 5441 connector->video_latency[0], connector->video_latency[1], 5463 5442 connector->audio_latency[0], connector->audio_latency[1]); 5464 5443 } 5444 + 5445 + static void 5446 + match_identity(const struct detailed_timing *timing, void *data) 5447 + { 5448 + struct drm_edid_match_closure *closure = data; 5449 + unsigned int i; 5450 + const char *name = closure->ident->name; 5451 + unsigned int name_len = strlen(name); 5452 + const char *desc = timing->data.other_data.data.str.str; 5453 + unsigned int desc_len = ARRAY_SIZE(timing->data.other_data.data.str.str); 5454 + 5455 + if (name_len > desc_len || 5456 + !(is_display_descriptor(timing, EDID_DETAIL_MONITOR_NAME) || 5457 + is_display_descriptor(timing, EDID_DETAIL_MONITOR_STRING))) 5458 + return; 5459 + 5460 + if (strncmp(name, desc, name_len)) 5461 + return; 5462 + 5463 + for (i = name_len; i < desc_len; i++) { 5464 + if (desc[i] == '\n') 5465 + break; 5466 + /* Allow white space before EDID string terminator. */ 5467 + if (!isspace(desc[i])) 5468 + return; 5469 + } 5470 + 5471 + closure->matched = true; 5472 + } 5473 + 5474 + /** 5475 + * drm_edid_match - match drm_edid with given identity 5476 + * @drm_edid: EDID 5477 + * @ident: the EDID identity to match with 5478 + * 5479 + * Check if the EDID matches with the given identity. 5480 + * 5481 + * Return: True if the given identity matched with EDID, false otherwise. 5482 + */ 5483 + bool drm_edid_match(const struct drm_edid *drm_edid, 5484 + const struct drm_edid_ident *ident) 5485 + { 5486 + if (!drm_edid || drm_edid_get_panel_id(drm_edid) != ident->panel_id) 5487 + return false; 5488 + 5489 + /* Match with name only if it's not NULL. */ 5490 + if (ident->name) { 5491 + struct drm_edid_match_closure closure = { 5492 + .ident = ident, 5493 + .matched = false, 5494 + }; 5495 + 5496 + drm_for_each_detailed_block(drm_edid, match_identity, &closure); 5497 + 5498 + return closure.matched; 5499 + } 5500 + 5501 + return true; 5502 + } 5503 + EXPORT_SYMBOL(drm_edid_match); 5465 5504 5466 5505 static void 5467 5506 monitor_name(const struct detailed_timing *timing, void *data)
+2 -2
drivers/gpu/drm/drm_fbdev_generic.c
··· 197 197 */ 198 198 mutex_lock(&fb_helper->lock); 199 199 200 - ret = drm_client_buffer_vmap(buffer, &map); 200 + ret = drm_client_buffer_vmap_local(buffer, &map); 201 201 if (ret) 202 202 goto out; 203 203 204 204 dst = map; 205 205 drm_fbdev_generic_damage_blit_real(fb_helper, clip, &dst); 206 206 207 - drm_client_buffer_vunmap(buffer); 207 + drm_client_buffer_vunmap_local(buffer); 208 208 209 209 out: 210 210 mutex_unlock(&fb_helper->lock);
+32 -2
drivers/gpu/drm/drm_gem.c
··· 1161 1161 obj->funcs->print_info(p, indent, obj); 1162 1162 } 1163 1163 1164 - int drm_gem_pin(struct drm_gem_object *obj) 1164 + int drm_gem_pin_locked(struct drm_gem_object *obj) 1165 1165 { 1166 1166 if (obj->funcs->pin) 1167 1167 return obj->funcs->pin(obj); ··· 1169 1169 return 0; 1170 1170 } 1171 1171 1172 - void drm_gem_unpin(struct drm_gem_object *obj) 1172 + void drm_gem_unpin_locked(struct drm_gem_object *obj) 1173 1173 { 1174 1174 if (obj->funcs->unpin) 1175 1175 obj->funcs->unpin(obj); 1176 + } 1177 + 1178 + int drm_gem_pin(struct drm_gem_object *obj) 1179 + { 1180 + int ret; 1181 + 1182 + dma_resv_lock(obj->resv, NULL); 1183 + ret = drm_gem_pin_locked(obj); 1184 + dma_resv_unlock(obj->resv); 1185 + 1186 + return ret; 1187 + } 1188 + 1189 + void drm_gem_unpin(struct drm_gem_object *obj) 1190 + { 1191 + dma_resv_lock(obj->resv, NULL); 1192 + drm_gem_unpin_locked(obj); 1193 + dma_resv_unlock(obj->resv); 1176 1194 } 1177 1195 1178 1196 int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map) ··· 1226 1208 iosys_map_clear(map); 1227 1209 } 1228 1210 EXPORT_SYMBOL(drm_gem_vunmap); 1211 + 1212 + void drm_gem_lock(struct drm_gem_object *obj) 1213 + { 1214 + dma_resv_lock(obj->resv, NULL); 1215 + } 1216 + EXPORT_SYMBOL(drm_gem_lock); 1217 + 1218 + void drm_gem_unlock(struct drm_gem_object *obj) 1219 + { 1220 + dma_resv_unlock(obj->resv); 1221 + } 1222 + EXPORT_SYMBOL(drm_gem_unlock); 1229 1223 1230 1224 int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map) 1231 1225 {
+4 -3
drivers/gpu/drm/drm_gem_shmem_helper.c
··· 10 10 #include <linux/shmem_fs.h> 11 11 #include <linux/slab.h> 12 12 #include <linux/vmalloc.h> 13 - #include <linux/module.h> 14 13 15 14 #ifdef CONFIG_X86 16 15 #include <asm/set_memory.h> ··· 227 228 } 228 229 EXPORT_SYMBOL(drm_gem_shmem_put_pages); 229 230 230 - static int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem) 231 + int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem) 231 232 { 232 233 int ret; 233 234 ··· 237 238 238 239 return ret; 239 240 } 241 + EXPORT_SYMBOL(drm_gem_shmem_pin_locked); 240 242 241 - static void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem) 243 + void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem) 242 244 { 243 245 dma_resv_assert_held(shmem->base.resv); 244 246 245 247 drm_gem_shmem_put_pages(shmem); 246 248 } 249 + EXPORT_SYMBOL(drm_gem_shmem_unpin_locked); 247 250 248 251 /** 249 252 * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object
+42 -63
drivers/gpu/drm/drm_gem_vram_helper.c
··· 282 282 struct ttm_operation_ctx ctx = { false, false }; 283 283 int ret; 284 284 285 + dma_resv_assert_held(gbo->bo.base.resv); 286 + 285 287 if (gbo->bo.pin_count) 286 288 goto out; 287 289 ··· 339 337 340 338 static void drm_gem_vram_unpin_locked(struct drm_gem_vram_object *gbo) 341 339 { 340 + dma_resv_assert_held(gbo->bo.base.resv); 341 + 342 342 ttm_bo_unpin(&gbo->bo); 343 343 } 344 344 ··· 367 363 } 368 364 EXPORT_SYMBOL(drm_gem_vram_unpin); 369 365 370 - static int drm_gem_vram_kmap_locked(struct drm_gem_vram_object *gbo, 371 - struct iosys_map *map) 372 - { 373 - int ret; 374 - 375 - if (gbo->vmap_use_count > 0) 376 - goto out; 377 - 378 - /* 379 - * VRAM helpers unmap the BO only on demand. So the previous 380 - * page mapping might still be around. Only vmap if the there's 381 - * no mapping present. 382 - */ 383 - if (iosys_map_is_null(&gbo->map)) { 384 - ret = ttm_bo_vmap(&gbo->bo, &gbo->map); 385 - if (ret) 386 - return ret; 387 - } 388 - 389 - out: 390 - ++gbo->vmap_use_count; 391 - *map = gbo->map; 392 - 393 - return 0; 394 - } 395 - 396 - static void drm_gem_vram_kunmap_locked(struct drm_gem_vram_object *gbo, 397 - struct iosys_map *map) 398 - { 399 - struct drm_device *dev = gbo->bo.base.dev; 400 - 401 - if (drm_WARN_ON_ONCE(dev, !gbo->vmap_use_count)) 402 - return; 403 - 404 - if (drm_WARN_ON_ONCE(dev, !iosys_map_is_equal(&gbo->map, map))) 405 - return; /* BUG: map not mapped from this BO */ 406 - 407 - if (--gbo->vmap_use_count > 0) 408 - return; 409 - 410 - /* 411 - * Permanently mapping and unmapping buffers adds overhead from 412 - * updating the page tables and creates debugging output. Therefore, 413 - * we delay the actual unmap operation until the BO gets evicted 414 - * from memory. See drm_gem_vram_bo_driver_move_notify(). 415 - */ 416 - } 417 - 418 366 /** 419 367 * drm_gem_vram_vmap() - Pins and maps a GEM VRAM object into kernel address 420 368 * space ··· 389 433 390 434 dma_resv_assert_held(gbo->bo.base.resv); 391 435 392 - ret = drm_gem_vram_pin_locked(gbo, 0); 393 - if (ret) 394 - return ret; 395 - ret = drm_gem_vram_kmap_locked(gbo, map); 396 - if (ret) 397 - goto err_drm_gem_vram_unpin_locked; 436 + if (gbo->vmap_use_count > 0) 437 + goto out; 438 + 439 + /* 440 + * VRAM helpers unmap the BO only on demand. So the previous 441 + * page mapping might still be around. Only vmap if the there's 442 + * no mapping present. 443 + */ 444 + if (iosys_map_is_null(&gbo->map)) { 445 + ret = ttm_bo_vmap(&gbo->bo, &gbo->map); 446 + if (ret) 447 + return ret; 448 + } 449 + 450 + out: 451 + ++gbo->vmap_use_count; 452 + *map = gbo->map; 398 453 399 454 return 0; 400 - 401 - err_drm_gem_vram_unpin_locked: 402 - drm_gem_vram_unpin_locked(gbo); 403 - return ret; 404 455 } 405 456 EXPORT_SYMBOL(drm_gem_vram_vmap); 406 457 ··· 422 459 void drm_gem_vram_vunmap(struct drm_gem_vram_object *gbo, 423 460 struct iosys_map *map) 424 461 { 462 + struct drm_device *dev = gbo->bo.base.dev; 463 + 425 464 dma_resv_assert_held(gbo->bo.base.resv); 426 465 427 - drm_gem_vram_kunmap_locked(gbo, map); 428 - drm_gem_vram_unpin_locked(gbo); 466 + if (drm_WARN_ON_ONCE(dev, !gbo->vmap_use_count)) 467 + return; 468 + 469 + if (drm_WARN_ON_ONCE(dev, !iosys_map_is_equal(&gbo->map, map))) 470 + return; /* BUG: map not mapped from this BO */ 471 + 472 + if (--gbo->vmap_use_count > 0) 473 + return; 474 + 475 + /* 476 + * Permanently mapping and unmapping buffers adds overhead from 477 + * updating the page tables and creates debugging output. Therefore, 478 + * we delay the actual unmap operation until the BO gets evicted 479 + * from memory. See drm_gem_vram_bo_driver_move_notify(). 480 + */ 429 481 } 430 482 EXPORT_SYMBOL(drm_gem_vram_vunmap); 431 483 ··· 746 768 { 747 769 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); 748 770 749 - /* Fbdev console emulation is the use case of these PRIME 771 + /* 772 + * Fbdev console emulation is the use case of these PRIME 750 773 * helpers. This may involve updating a hardware buffer from 751 774 * a shadow FB. We pin the buffer to it's current location 752 775 * (either video RAM or system memory) to prevent it from ··· 755 776 * the buffer to be pinned to VRAM, implement a callback that 756 777 * sets the flags accordingly. 757 778 */ 758 - return drm_gem_vram_pin(gbo, 0); 779 + return drm_gem_vram_pin_locked(gbo, 0); 759 780 } 760 781 761 782 /** ··· 766 787 { 767 788 struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(gem); 768 789 769 - drm_gem_vram_unpin(gbo); 790 + drm_gem_vram_unpin_locked(gbo); 770 791 } 771 792 772 793 /**
+7
drivers/gpu/drm/drm_internal.h
··· 21 21 * OTHER DEALINGS IN THE SOFTWARE. 22 22 */ 23 23 24 + #ifndef __DRM_INTERNAL_H__ 25 + #define __DRM_INTERNAL_H__ 26 + 24 27 #include <linux/kthread.h> 25 28 #include <linux/types.h> 26 29 ··· 173 170 void drm_gem_print_info(struct drm_printer *p, unsigned int indent, 174 171 const struct drm_gem_object *obj); 175 172 173 + int drm_gem_pin_locked(struct drm_gem_object *obj); 174 + void drm_gem_unpin_locked(struct drm_gem_object *obj); 176 175 int drm_gem_pin(struct drm_gem_object *obj); 177 176 void drm_gem_unpin(struct drm_gem_object *obj); 178 177 int drm_gem_vmap(struct drm_gem_object *obj, struct iosys_map *map); ··· 281 276 /* drm_edid.c */ 282 277 void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad); 283 278 void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad); 279 + 280 + #endif /* __DRM_INTERNAL_H__ */
+2 -2
drivers/gpu/drm/exynos/Kconfig
··· 4 4 depends on OF && DRM && COMMON_CLK 5 5 depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST 6 6 depends on MMU 7 - select DRM_DISPLAY_HELPER if DRM_EXYNOS_DP 8 7 select DRM_KMS_HELPER 9 8 select VIDEOMODE_HELPERS 10 9 select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION ··· 67 68 config DRM_EXYNOS_DP 68 69 bool "Exynos specific extensions for Analogix DP driver" 69 70 depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON 71 + depends on DRM_DISPLAY_DP_HELPER 72 + depends on DRM_DISPLAY_HELPER 70 73 select DRM_ANALOGIX_DP 71 - select DRM_DISPLAY_DP_HELPER 72 74 default DRM_EXYNOS 73 75 select DRM_PANEL 74 76 help
-2
drivers/gpu/drm/gma500/oaktrail_lvds.c
··· 11 11 #include <linux/i2c.h> 12 12 #include <linux/pm_runtime.h> 13 13 14 - #include <asm/intel-mid.h> 15 - 16 14 #include <drm/drm_edid.h> 17 15 #include <drm/drm_modeset_helper_vtables.h> 18 16 #include <drm/drm_simple_kms_helper.h>
+4 -4
drivers/gpu/drm/i915/Kconfig
··· 2 2 config DRM_I915 3 3 tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" 4 4 depends on DRM 5 + depends on DRM_DISPLAY_DP_HELPER 6 + depends on DRM_DISPLAY_HDCP_HELPER 7 + depends on DRM_DISPLAY_HDMI_HELPER 8 + depends on DRM_DISPLAY_HELPER 5 9 depends on X86 && PCI 6 10 depends on !PREEMPT_RT 7 11 select INTEL_GTT if X86 ··· 14 10 # the shmem_readpage() which depends upon tmpfs 15 11 select SHMEM 16 12 select TMPFS 17 - select DRM_DISPLAY_DP_HELPER 18 - select DRM_DISPLAY_HDCP_HELPER 19 - select DRM_DISPLAY_HDMI_HELPER 20 - select DRM_DISPLAY_HELPER 21 13 select DRM_KMS_HELPER 22 14 select DRM_PANEL 23 15 select DRM_MIPI_DSI
+2 -2
drivers/gpu/drm/i915/Kconfig.debug
··· 27 27 select REF_TRACKER 28 28 select STACKDEPOT 29 29 select STACKTRACE 30 - select DRM_DP_AUX_CHARDEV 31 - select DRM_DISPLAY_DEBUG_DP_TUNNEL_STATE if DRM_I915_DP_TUNNEL 30 + select DRM_DISPLAY_DP_AUX_CHARDEV 31 + select DRM_DISPLAY_DP_TUNNEL_STATE_DEBUG if DRM_I915_DP_TUNNEL 32 32 select X86_MSR # used by igt/pm_rpm 33 33 select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) 34 34 select DRM_DEBUG_MM if DRM=y
+2 -2
drivers/gpu/drm/imagination/pvr_vm_mips.c
··· 46 46 if (!mips_data) 47 47 return -ENOMEM; 48 48 49 - for (page_nr = 0; page_nr < ARRAY_SIZE(mips_data->pt_pages); page_nr++) { 49 + for (page_nr = 0; page_nr < PVR_MIPS_PT_PAGE_COUNT; page_nr++) { 50 50 mips_data->pt_pages[page_nr] = alloc_page(GFP_KERNEL | __GFP_ZERO); 51 51 if (!mips_data->pt_pages[page_nr]) { 52 52 err = -ENOMEM; ··· 102 102 int page_nr; 103 103 104 104 vunmap(mips_data->pt); 105 - for (page_nr = ARRAY_SIZE(mips_data->pt_pages) - 1; page_nr >= 0; page_nr--) { 105 + for (page_nr = PVR_MIPS_PT_PAGE_COUNT - 1; page_nr >= 0; page_nr--) { 106 106 dma_unmap_page(from_pvr_device(pvr_dev)->dev, 107 107 mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE); 108 108
+3 -2
drivers/gpu/drm/imx/ipuv3/Kconfig
··· 35 35 36 36 config DRM_IMX_HDMI 37 37 tristate "Freescale i.MX DRM HDMI" 38 - select DRM_DW_HDMI 39 - depends on DRM_IMX && OF 38 + depends on DRM_DW_HDMI 39 + depends on DRM_IMX 40 + depends on OF 40 41 help 41 42 Choose this if you want to use HDMI on i.MX6.
+1 -1
drivers/gpu/drm/ingenic/Kconfig
··· 27 27 28 28 config DRM_INGENIC_DW_HDMI 29 29 tristate "Ingenic specific support for Synopsys DW HDMI" 30 + depends on DRM_DW_HDMI 30 31 depends on MACH_JZ4780 31 - select DRM_DW_HDMI 32 32 help 33 33 Choose this option to enable Synopsys DesignWare HDMI based driver. 34 34 If you want to enable HDMI on Ingenic JZ4780 based SoC, you should
+2 -11
drivers/gpu/drm/loongson/lsdc_gem.c
··· 19 19 struct lsdc_bo *lbo = gem_to_lsdc_bo(obj); 20 20 int ret; 21 21 22 - ret = lsdc_bo_reserve(lbo); 23 - if (unlikely(ret)) 24 - return ret; 22 + dma_resv_assert_held(obj->resv); 25 23 26 24 ret = lsdc_bo_pin(lbo, LSDC_GEM_DOMAIN_GTT, NULL); 27 25 if (likely(ret == 0)) 28 26 lbo->sharing_count++; 29 - 30 - lsdc_bo_unreserve(lbo); 31 27 32 28 return ret; 33 29 } ··· 31 35 static void lsdc_gem_prime_unpin(struct drm_gem_object *obj) 32 36 { 33 37 struct lsdc_bo *lbo = gem_to_lsdc_bo(obj); 34 - int ret; 35 38 36 - ret = lsdc_bo_reserve(lbo); 37 - if (unlikely(ret)) 38 - return; 39 + dma_resv_assert_held(obj->resv); 39 40 40 41 lsdc_bo_unpin(lbo); 41 42 if (lbo->sharing_count) 42 43 lbo->sharing_count--; 43 - 44 - lsdc_bo_unreserve(lbo); 45 44 } 46 45 47 46 static struct sg_table *lsdc_gem_prime_get_sg_table(struct drm_gem_object *obj)
+3 -3
drivers/gpu/drm/mediatek/Kconfig
··· 22 22 23 23 config DRM_MEDIATEK_DP 24 24 tristate "DRM DPTX Support for MediaTek SoCs" 25 + depends on DRM_DISPLAY_DP_AUX_BUS 26 + depends on DRM_DISPLAY_DP_HELPER 27 + depends on DRM_DISPLAY_HELPER 25 28 depends on DRM_MEDIATEK 26 29 select PHY_MTK_DP 27 - select DRM_DISPLAY_HELPER 28 - select DRM_DISPLAY_DP_HELPER 29 - select DRM_DP_AUX_BUS 30 30 help 31 31 DRM/KMS Display Port driver for MediaTek SoCs. 32 32
+1 -1
drivers/gpu/drm/meson/Kconfig
··· 13 13 14 14 config DRM_MESON_DW_HDMI 15 15 tristate "HDMI Synopsys Controller support for Amlogic Meson Display" 16 + depends on DRM_DW_HDMI 16 17 depends on DRM_MESON 17 18 default y if DRM_MESON 18 - select DRM_DW_HDMI 19 19 imply DRM_DW_HDMI_I2S_AUDIO 20 20 21 21 config DRM_MESON_DW_MIPI_DSI
+4 -4
drivers/gpu/drm/msm/Kconfig
··· 2 2 3 3 config DRM_MSM 4 4 tristate "MSM DRM" 5 - depends on DRM 6 5 depends on ARCH_QCOM || SOC_IMX5 || COMPILE_TEST 7 6 depends on COMMON_CLK 7 + depends on DRM 8 + depends on DRM_DISPLAY_DP_AUX_BUS 9 + depends on DRM_DISPLAY_DP_HELPER 10 + depends on DRM_DISPLAY_HELPER 8 11 depends on IOMMU_SUPPORT 9 12 depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n 10 13 depends on QCOM_OCMEM || QCOM_OCMEM=n ··· 17 14 select IOMMU_IO_PGTABLE 18 15 select QCOM_MDT_LOADER if ARCH_QCOM 19 16 select REGULATOR 20 - select DRM_DP_AUX_BUS 21 - select DRM_DISPLAY_DP_HELPER 22 - select DRM_DISPLAY_HELPER 23 17 select DRM_EXEC 24 18 select DRM_KMS_HELPER 25 19 select DRM_PANEL
+10 -10
drivers/gpu/drm/msm/msm_gem.c
··· 219 219 } 220 220 } 221 221 222 - static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj, 222 + static struct page **msm_gem_get_pages_locked(struct drm_gem_object *obj, 223 223 unsigned madv) 224 224 { 225 225 struct msm_gem_object *msm_obj = to_msm_bo(obj); ··· 257 257 mutex_unlock(&priv->lru.lock); 258 258 } 259 259 260 - struct page **msm_gem_pin_pages(struct drm_gem_object *obj) 260 + struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj) 261 261 { 262 262 struct page **p; 263 263 264 - msm_gem_lock(obj); 265 - p = msm_gem_pin_pages_locked(obj, MSM_MADV_WILLNEED); 264 + msm_gem_assert_locked(obj); 265 + 266 + p = msm_gem_get_pages_locked(obj, MSM_MADV_WILLNEED); 266 267 if (!IS_ERR(p)) 267 268 pin_obj_locked(obj); 268 - msm_gem_unlock(obj); 269 269 270 270 return p; 271 271 } 272 272 273 - void msm_gem_unpin_pages(struct drm_gem_object *obj) 273 + void msm_gem_unpin_pages_locked(struct drm_gem_object *obj) 274 274 { 275 - msm_gem_lock(obj); 275 + msm_gem_assert_locked(obj); 276 + 276 277 msm_gem_unpin_locked(obj); 277 - msm_gem_unlock(obj); 278 278 } 279 279 280 280 static pgprot_t msm_gem_pgprot(struct msm_gem_object *msm_obj, pgprot_t prot) ··· 489 489 490 490 msm_gem_assert_locked(obj); 491 491 492 - pages = msm_gem_pin_pages_locked(obj, MSM_MADV_WILLNEED); 492 + pages = msm_gem_get_pages_locked(obj, MSM_MADV_WILLNEED); 493 493 if (IS_ERR(pages)) 494 494 return PTR_ERR(pages); 495 495 ··· 703 703 if (obj->import_attach) 704 704 return ERR_PTR(-ENODEV); 705 705 706 - pages = msm_gem_pin_pages_locked(obj, madv); 706 + pages = msm_gem_get_pages_locked(obj, madv); 707 707 if (IS_ERR(pages)) 708 708 return ERR_CAST(pages); 709 709
+2 -2
drivers/gpu/drm/msm/msm_gem.h
··· 140 140 void msm_gem_unpin_iova(struct drm_gem_object *obj, 141 141 struct msm_gem_address_space *aspace); 142 142 void msm_gem_pin_obj_locked(struct drm_gem_object *obj); 143 - struct page **msm_gem_pin_pages(struct drm_gem_object *obj); 144 - void msm_gem_unpin_pages(struct drm_gem_object *obj); 143 + struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj); 144 + void msm_gem_unpin_pages_locked(struct drm_gem_object *obj); 145 145 int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, 146 146 struct drm_mode_create_dumb *args); 147 147 int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
+15 -5
drivers/gpu/drm/msm/msm_gem_prime.c
··· 47 47 48 48 int msm_gem_prime_pin(struct drm_gem_object *obj) 49 49 { 50 - if (!obj->import_attach) 51 - msm_gem_pin_pages(obj); 52 - return 0; 50 + struct page **pages; 51 + int ret = 0; 52 + 53 + if (obj->import_attach) 54 + return 0; 55 + 56 + pages = msm_gem_pin_pages_locked(obj); 57 + if (IS_ERR(pages)) 58 + ret = PTR_ERR(pages); 59 + 60 + return ret; 53 61 } 54 62 55 63 void msm_gem_prime_unpin(struct drm_gem_object *obj) 56 64 { 57 - if (!obj->import_attach) 58 - msm_gem_unpin_pages(obj); 65 + if (obj->import_attach) 66 + return; 67 + 68 + msm_gem_unpin_pages_locked(obj); 59 69 }
+5 -1
drivers/gpu/drm/mxsfb/lcdif_drv.c
··· 343 343 if (ret) 344 344 return ret; 345 345 346 + if (pm_runtime_suspended(dev)) 347 + return 0; 348 + 346 349 return lcdif_rpm_suspend(dev); 347 350 } 348 351 ··· 353 350 { 354 351 struct drm_device *drm = dev_get_drvdata(dev); 355 352 356 - lcdif_rpm_resume(dev); 353 + if (!pm_runtime_suspended(dev)) 354 + lcdif_rpm_resume(dev); 357 355 358 356 return drm_mode_config_helper_resume(drm); 359 357 }
+6 -4
drivers/gpu/drm/nouveau/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config DRM_NOUVEAU 3 3 tristate "Nouveau (NVIDIA) cards" 4 - depends on DRM && PCI && MMU 4 + depends on DRM 5 + depends on DRM_DISPLAY_DP_HELPER 6 + depends on DRM_DISPLAY_HDMI_HELPER 7 + depends on DRM_DISPLAY_HELPER 8 + depends on PCI 9 + depends on MMU 5 10 select IOMMU_API 6 11 select FW_LOADER 7 - select DRM_DISPLAY_DP_HELPER 8 - select DRM_DISPLAY_HDMI_HELPER 9 - select DRM_DISPLAY_HELPER 10 12 select DRM_KMS_HELPER 11 13 select DRM_TTM 12 14 select DRM_TTM_HELPER
+15 -5
drivers/gpu/drm/nouveau/nouveau_abi16.c
··· 312 312 if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { 313 313 if (init->fb_ctxdma_handle == ~0) { 314 314 switch (init->tt_ctxdma_handle) { 315 - case 0x01: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR ; break; 316 - case 0x02: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPDEC; break; 317 - case 0x04: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPPP ; break; 318 - case 0x08: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSVLD ; break; 319 - case 0x30: engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE ; break; 315 + case NOUVEAU_FIFO_ENGINE_GR: 316 + engine = NV_DEVICE_HOST_RUNLIST_ENGINES_GR; 317 + break; 318 + case NOUVEAU_FIFO_ENGINE_VP: 319 + engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPDEC; 320 + break; 321 + case NOUVEAU_FIFO_ENGINE_PPP: 322 + engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSPPP; 323 + break; 324 + case NOUVEAU_FIFO_ENGINE_BSP: 325 + engine = NV_DEVICE_HOST_RUNLIST_ENGINES_MSVLD; 326 + break; 327 + case NOUVEAU_FIFO_ENGINE_CE: 328 + engine = NV_DEVICE_HOST_RUNLIST_ENGINES_CE; 329 + break; 320 330 default: 321 331 return nouveau_abi16_put(abi16, -ENOSYS); 322 332 }
-12
drivers/gpu/drm/nouveau/nouveau_abi16.h
··· 50 50 int class; 51 51 }; 52 52 53 - struct drm_nouveau_notifierobj_alloc { 54 - uint32_t channel; 55 - uint32_t handle; 56 - uint32_t size; 57 - uint32_t offset; 58 - }; 59 - 60 - struct drm_nouveau_gpuobj_free { 61 - int channel; 62 - uint32_t handle; 63 - }; 64 - 65 53 struct drm_nouveau_setparam { 66 54 uint64_t param; 67 55 uint64_t value;
+30 -13
drivers/gpu/drm/nouveau/nouveau_bo.c
··· 467 467 set_placement_range(nvbo, domain); 468 468 } 469 469 470 - int 471 - nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig) 470 + int nouveau_bo_pin_locked(struct nouveau_bo *nvbo, uint32_t domain, bool contig) 472 471 { 473 472 struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); 474 473 struct ttm_buffer_object *bo = &nvbo->bo; 475 474 bool force = false, evict = false; 476 - int ret; 475 + int ret = 0; 477 476 478 - ret = ttm_bo_reserve(bo, false, false, NULL); 479 - if (ret) 480 - return ret; 477 + dma_resv_assert_held(bo->base.resv); 481 478 482 479 if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA && 483 480 domain == NOUVEAU_GEM_DOMAIN_VRAM && contig) { ··· 537 540 out: 538 541 if (force && ret) 539 542 nvbo->contig = false; 540 - ttm_bo_unreserve(bo); 541 543 return ret; 542 544 } 543 545 544 - int 545 - nouveau_bo_unpin(struct nouveau_bo *nvbo) 546 + void nouveau_bo_unpin_locked(struct nouveau_bo *nvbo) 546 547 { 547 548 struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev); 548 549 struct ttm_buffer_object *bo = &nvbo->bo; 549 - int ret; 550 550 551 - ret = ttm_bo_reserve(bo, false, false, NULL); 552 - if (ret) 553 - return ret; 551 + dma_resv_assert_held(bo->base.resv); 554 552 555 553 ttm_bo_unpin(&nvbo->bo); 556 554 if (!nvbo->bo.pin_count) { ··· 560 568 break; 561 569 } 562 570 } 571 + } 563 572 573 + int nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig) 574 + { 575 + struct ttm_buffer_object *bo = &nvbo->bo; 576 + int ret; 577 + 578 + ret = ttm_bo_reserve(bo, false, false, NULL); 579 + if (ret) 580 + return ret; 581 + ret = nouveau_bo_pin_locked(nvbo, domain, contig); 564 582 ttm_bo_unreserve(bo); 583 + 584 + return ret; 585 + } 586 + 587 + int nouveau_bo_unpin(struct nouveau_bo *nvbo) 588 + { 589 + struct ttm_buffer_object *bo = &nvbo->bo; 590 + int ret; 591 + 592 + ret = ttm_bo_reserve(bo, false, false, NULL); 593 + if (ret) 594 + return ret; 595 + nouveau_bo_unpin_locked(nvbo); 596 + ttm_bo_unreserve(bo); 597 + 565 598 return 0; 566 599 } 567 600
+2
drivers/gpu/drm/nouveau/nouveau_bo.h
··· 85 85 u32 tile_mode, u32 tile_flags, struct sg_table *sg, 86 86 struct dma_resv *robj, 87 87 struct nouveau_bo **); 88 + int nouveau_bo_pin_locked(struct nouveau_bo *nvbo, uint32_t domain, bool contig); 89 + void nouveau_bo_unpin_locked(struct nouveau_bo *nvbo); 88 90 int nouveau_bo_pin(struct nouveau_bo *, u32 flags, bool contig); 89 91 int nouveau_bo_unpin(struct nouveau_bo *); 90 92 int nouveau_bo_map(struct nouveau_bo *);
+4 -4
drivers/gpu/drm/nouveau/nouveau_prime.c
··· 89 89 int ret; 90 90 91 91 /* pin buffer into GTT */ 92 - ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_GART, false); 92 + ret = nouveau_bo_pin_locked(nvbo, NOUVEAU_GEM_DOMAIN_GART, false); 93 93 if (ret) 94 - return -EINVAL; 94 + ret = -EINVAL; 95 95 96 - return 0; 96 + return ret; 97 97 } 98 98 99 99 void nouveau_gem_prime_unpin(struct drm_gem_object *obj) 100 100 { 101 101 struct nouveau_bo *nvbo = nouveau_gem_object(obj); 102 102 103 - nouveau_bo_unpin(nvbo); 103 + nouveau_bo_unpin_locked(nvbo); 104 104 } 105 105 106 106 struct dma_buf *nouveau_gem_prime_export(struct drm_gem_object *gobj,
+1 -1
drivers/gpu/drm/nouveau/nvkm/engine/disp/r535.c
··· 1080 1080 ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl)); 1081 1081 if (ret) { 1082 1082 nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl); 1083 - return PTR_ERR(ctrl); 1083 + return ret; 1084 1084 } 1085 1085 1086 1086 memcpy(data, ctrl->data, size);
+1 -1
drivers/gpu/drm/omapdrm/Kconfig
··· 4 4 depends on DRM && OF 5 5 depends on ARCH_OMAP2PLUS 6 6 select DRM_KMS_HELPER 7 - select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION 7 + select FB_DMAMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION 8 8 select VIDEOMODE_HELPERS 9 9 select HDMI 10 10 default n
+34 -6
drivers/gpu/drm/omapdrm/omap_fbdev.c
··· 51 51 omap_gem_roll(bo, fbi->var.yoffset * npages); 52 52 } 53 53 54 + FB_GEN_DEFAULT_DEFERRED_DMAMEM_OPS(omap_fbdev, 55 + drm_fb_helper_damage_range, 56 + drm_fb_helper_damage_area) 57 + 54 58 static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, 55 59 struct fb_info *fbi) 56 60 { ··· 82 78 83 79 static int omap_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) 84 80 { 85 - struct drm_fb_helper *helper = info->par; 86 - struct drm_framebuffer *fb = helper->fb; 87 - struct drm_gem_object *bo = drm_gem_fb_get_obj(fb, 0); 81 + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); 88 82 89 - return drm_gem_mmap_obj(bo, omap_gem_mmap_size(bo), vma); 83 + return fb_deferred_io_mmap(info, vma); 90 84 } 91 85 92 86 static void omap_fbdev_fb_destroy(struct fb_info *info) ··· 96 94 97 95 DBG(); 98 96 97 + fb_deferred_io_cleanup(info); 99 98 drm_fb_helper_fini(helper); 100 99 101 100 omap_gem_unpin(bo); ··· 107 104 kfree(fbdev); 108 105 } 109 106 107 + /* 108 + * For now, we cannot use FB_DEFAULT_DEFERRED_OPS and fb_deferred_io_mmap() 109 + * because we use write-combine. 110 + */ 110 111 static const struct fb_ops omap_fb_ops = { 111 112 .owner = THIS_MODULE, 112 - __FB_DEFAULT_DMAMEM_OPS_RDWR, 113 + __FB_DEFAULT_DEFERRED_OPS_RDWR(omap_fbdev), 113 114 .fb_check_var = drm_fb_helper_check_var, 114 115 .fb_set_par = drm_fb_helper_set_par, 115 116 .fb_setcmap = drm_fb_helper_setcmap, 116 117 .fb_blank = drm_fb_helper_blank, 117 118 .fb_pan_display = omap_fbdev_pan_display, 118 - __FB_DEFAULT_DMAMEM_OPS_DRAW, 119 + __FB_DEFAULT_DEFERRED_OPS_DRAW(omap_fbdev), 119 120 .fb_ioctl = drm_fb_helper_ioctl, 120 121 .fb_mmap = omap_fbdev_fb_mmap, 121 122 .fb_destroy = omap_fbdev_fb_destroy, ··· 220 213 fbi->fix.smem_start = dma_addr; 221 214 fbi->fix.smem_len = bo->size; 222 215 216 + /* deferred I/O */ 217 + helper->fbdefio.delay = HZ / 20; 218 + helper->fbdefio.deferred_io = drm_fb_helper_deferred_io; 219 + 220 + fbi->fbdefio = &helper->fbdefio; 221 + ret = fb_deferred_io_init(fbi); 222 + if (ret) 223 + goto fail; 224 + 223 225 /* if we have DMM, then we can use it for scrolling by just 224 226 * shuffling pages around in DMM rather than doing sw blit. 225 227 */ ··· 254 238 return ret; 255 239 } 256 240 241 + static int omap_fbdev_dirty(struct drm_fb_helper *helper, struct drm_clip_rect *clip) 242 + { 243 + if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) 244 + return 0; 245 + 246 + if (helper->fb->funcs->dirty) 247 + return helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); 248 + 249 + return 0; 250 + } 251 + 257 252 static const struct drm_fb_helper_funcs omap_fb_helper_funcs = { 258 253 .fb_probe = omap_fbdev_create, 254 + .fb_dirty = omap_fbdev_dirty, 259 255 }; 260 256 261 257 static struct drm_fb_helper *get_fb(struct fb_info *fbi)
+25 -16
drivers/gpu/drm/panel/Kconfig
··· 533 533 534 534 config DRM_PANEL_RAYDIUM_RM692E5 535 535 tristate "Raydium RM692E5-based DSI panel" 536 - depends on OF 537 - depends on DRM_MIPI_DSI 538 536 depends on BACKLIGHT_CLASS_DEVICE 539 - select DRM_DISPLAY_DP_HELPER 540 - select DRM_DISPLAY_HELPER 537 + depends on DRM_DISPLAY_DP_HELPER 538 + depends on DRM_DISPLAY_HELPER 539 + depends on DRM_MIPI_DSI 540 + depends on OF 541 541 help 542 542 Say Y here if you want to enable support for Raydium RM692E5-based 543 543 display panels, such as the one found in the Fairphone 5 smartphone. ··· 559 559 560 560 config DRM_PANEL_SAMSUNG_ATNA33XC20 561 561 tristate "Samsung ATNA33XC20 eDP panel" 562 - depends on OF 563 562 depends on BACKLIGHT_CLASS_DEVICE 563 + depends on DRM_DISPLAY_DP_AUX_BUS 564 + depends on DRM_DISPLAY_DP_HELPER 565 + depends on DRM_DISPLAY_HELPER 566 + depends on OF 564 567 depends on PM 565 - select DRM_DISPLAY_DP_HELPER 566 - select DRM_DISPLAY_HELPER 567 - select DRM_DP_AUX_BUS 568 568 help 569 569 DRM panel driver for the Samsung ATNA33XC20 panel. This panel can't 570 570 be handled by the DRM_PANEL_SIMPLE driver because its power ··· 585 585 depends on OF && SPI 586 586 depends on BACKLIGHT_CLASS_DEVICE 587 587 select VIDEOMODE_HELPERS 588 + 589 + config DRM_PANEL_SAMSUNG_S6E3FA7 590 + tristate "Samsung S6E3FA7 panel driver" 591 + depends on OF 592 + depends on DRM_MIPI_DSI 593 + depends on BACKLIGHT_CLASS_DEVICE 594 + help 595 + Say Y here if you want to enable support for the Samsung S6E3FA7 596 + 1920x2220 panel. 588 597 589 598 config DRM_PANEL_SAMSUNG_S6D16D0 590 599 tristate "Samsung S6D16D0 DSI video mode panel" ··· 799 790 800 791 config DRM_PANEL_EDP 801 792 tristate "support for simple Embedded DisplayPort panels" 802 - depends on OF 803 793 depends on BACKLIGHT_CLASS_DEVICE 794 + depends on DRM_DISPLAY_DP_AUX_BUS 795 + depends on DRM_DISPLAY_DP_HELPER 796 + depends on DRM_DISPLAY_HELPER 797 + depends on OF 804 798 depends on PM 805 799 select VIDEOMODE_HELPERS 806 - select DRM_DISPLAY_DP_HELPER 807 - select DRM_DISPLAY_HELPER 808 - select DRM_DP_AUX_BUS 809 800 select DRM_KMS_HELPER 810 801 help 811 802 DRM panel driver for dumb eDP panels that need at most a regulator and ··· 879 870 880 871 config DRM_PANEL_VISIONOX_R66451 881 872 tristate "Visionox R66451" 882 - depends on OF 883 - depends on DRM_MIPI_DSI 884 873 depends on BACKLIGHT_CLASS_DEVICE 885 - select DRM_DISPLAY_DP_HELPER 886 - select DRM_DISPLAY_HELPER 874 + depends on DRM_DISPLAY_DP_HELPER 875 + depends on DRM_DISPLAY_HELPER 876 + depends on DRM_MIPI_DSI 877 + depends on OF 887 878 help 888 879 Say Y here if you want to enable support for Visionox 889 880 R66451 1080x2340 AMOLED DSI panel.
+1
drivers/gpu/drm/panel/Makefile
··· 62 62 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o 63 63 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o 64 64 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0) += panel-samsung-s6d7aa0.o 65 + obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3FA7) += panel-samsung-s6e3fa7.o 65 66 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o 66 67 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o 67 68 obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o
+63 -22
drivers/gpu/drm/panel/panel-edp.c
··· 210 210 * struct edp_panel_entry - Maps panel ID to delay / panel name. 211 211 */ 212 212 struct edp_panel_entry { 213 - /** @panel_id: 32-bit ID for panel, encoded with drm_edid_encode_panel_id(). */ 214 - u32 panel_id; 213 + /** @ident: edid identity used for panel matching. */ 214 + const struct drm_edid_ident ident; 215 215 216 216 /** @delay: The power sequencing delays needed for this panel. */ 217 217 const struct panel_delay *delay; 218 - 219 - /** @name: Name of this panel (for printing to logs). */ 220 - const char *name; 221 218 222 219 /** @override_edid_mode: Override the mode obtained by edid. */ 223 220 const struct drm_display_mode *override_edid_mode; ··· 688 691 else if (!p->detected_panel) 689 692 seq_puts(s, "HARDCODED\n"); 690 693 else 691 - seq_printf(s, "%s\n", p->detected_panel->name); 694 + seq_printf(s, "%s\n", p->detected_panel->ident.name); 692 695 693 696 return 0; 694 697 } ··· 758 761 dev_err(dev, "Reject override mode: No display_timing found\n"); 759 762 } 760 763 761 - static const struct edp_panel_entry *find_edp_panel(u32 panel_id); 764 + static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const struct drm_edid *edid); 762 765 763 766 static int generic_edp_panel_probe(struct device *dev, struct panel_edp *panel) 764 767 { 765 768 struct panel_desc *desc; 769 + const struct drm_edid *base_block; 766 770 u32 panel_id; 767 771 char vend[4]; 768 772 u16 product_id; ··· 793 795 goto exit; 794 796 } 795 797 796 - panel_id = drm_edid_get_panel_id(panel->ddc); 797 - if (!panel_id) { 798 + base_block = drm_edid_read_base_block(panel->ddc); 799 + if (base_block) { 800 + panel_id = drm_edid_get_panel_id(base_block); 801 + } else { 798 802 dev_err(dev, "Couldn't identify panel via EDID\n"); 799 803 ret = -EIO; 800 804 goto exit; 801 805 } 802 806 drm_edid_decode_panel_id(panel_id, vend, &product_id); 803 807 804 - panel->detected_panel = find_edp_panel(panel_id); 808 + panel->detected_panel = find_edp_panel(panel_id, base_block); 809 + 810 + drm_edid_free(base_block); 805 811 806 812 /* 807 813 * We're using non-optimized timings and want it really obvious that ··· 838 836 panel->detected_panel = ERR_PTR(-EINVAL); 839 837 } else { 840 838 dev_info(dev, "Detected %s %s (%#06x)\n", 841 - vend, panel->detected_panel->name, product_id); 839 + vend, panel->detected_panel->ident.name, product_id); 842 840 843 841 /* Update the delay; everything else comes from EDID */ 844 842 desc->delay = *panel->detected_panel->delay; ··· 1005 1003 .width = 217, 1006 1004 .height = 136, 1007 1005 }, 1006 + }; 1007 + 1008 + static const struct drm_display_mode auo_b116xa3_mode = { 1009 + .clock = 70589, 1010 + .hdisplay = 1366, 1011 + .hsync_start = 1366 + 40, 1012 + .hsync_end = 1366 + 40 + 40, 1013 + .htotal = 1366 + 40 + 40 + 32, 1014 + .vdisplay = 768, 1015 + .vsync_start = 768 + 10, 1016 + .vsync_end = 768 + 10 + 12, 1017 + .vtotal = 768 + 10 + 12 + 6, 1018 + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 1008 1019 }; 1009 1020 1010 1021 static const struct drm_display_mode auo_b116xak01_mode = { ··· 1880 1865 .enable = 50, 1881 1866 }; 1882 1867 1868 + static const struct panel_delay delay_200_500_e50_p2e200 = { 1869 + .hpd_absent = 200, 1870 + .unprepare = 500, 1871 + .enable = 50, 1872 + .prepare_to_enable = 200, 1873 + }; 1874 + 1883 1875 static const struct panel_delay delay_200_500_e80 = { 1884 1876 .hpd_absent = 200, 1885 1877 .unprepare = 500, ··· 1941 1919 1942 1920 #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ 1943 1921 { \ 1944 - .name = _name, \ 1945 - .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ 1946 - product_id), \ 1922 + .ident = { \ 1923 + .name = _name, \ 1924 + .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ 1925 + product_id), \ 1926 + }, \ 1947 1927 .delay = _delay \ 1948 1928 } 1949 1929 1950 1930 #define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name, _mode) \ 1951 1931 { \ 1952 - .name = _name, \ 1953 - .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ 1954 - product_id), \ 1932 + .ident = { \ 1933 + .name = _name, \ 1934 + .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ 1935 + product_id), \ 1936 + }, \ 1955 1937 .delay = _delay, \ 1956 1938 .override_edid_mode = _mode \ 1957 1939 } ··· 1979 1953 EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, "B116XAN06.1"), 1980 1954 EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, &delay_200_500_e50, "B116XTN02.5"), 1981 1955 EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), 1982 - EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0"), 1956 + EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAN04.0"), 1957 + EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", 1958 + &auo_b116xa3_mode), 1983 1959 EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"), 1984 1960 EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), 1985 1961 EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), ··· 1989 1961 EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), 1990 1962 EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), 1991 1963 EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), 1964 + EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, "B120XAN01.0"), 1992 1965 EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), 1993 1966 1994 1967 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"), ··· 2039 2010 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), 2040 2011 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), 2041 2012 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), 2013 + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"), 2042 2014 2043 2015 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), 2044 2016 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), ··· 2055 2025 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1156, &delay_200_500_e80_d50, "Unknown"), 2056 2026 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"), 2057 2027 EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), 2028 + EDP_PANEL_ENTRY('C', 'M', 'N', 0x115e, &delay_200_500_e80_d50, "N116BCA-EA1"), 2058 2029 EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), 2059 2030 EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), 2060 2031 EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"), ··· 2065 2034 EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), 2066 2035 EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), 2067 2036 2068 - EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50, "MNC207QS1-1"), 2037 + EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50_p2e200, "MNC207QS1-1"), 2069 2038 2070 2039 EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), 2071 2040 EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), ··· 2107 2076 { /* sentinal */ } 2108 2077 }; 2109 2078 2110 - static const struct edp_panel_entry *find_edp_panel(u32 panel_id) 2079 + static const struct edp_panel_entry *find_edp_panel(u32 panel_id, const struct drm_edid *edid) 2111 2080 { 2112 2081 const struct edp_panel_entry *panel; 2113 2082 2114 2083 if (!panel_id) 2115 2084 return NULL; 2116 2085 2117 - for (panel = edp_panels; panel->panel_id; panel++) 2118 - if (panel->panel_id == panel_id) 2086 + /* 2087 + * Match with identity first. This allows handling the case where 2088 + * vendors incorrectly reused the same panel ID for multiple panels that 2089 + * need different settings. If there's no match, try again with panel 2090 + * ID, which should be unique. 2091 + */ 2092 + for (panel = edp_panels; panel->ident.panel_id; panel++) 2093 + if (drm_edid_match(edid, &panel->ident)) 2094 + return panel; 2095 + 2096 + for (panel = edp_panels; panel->ident.panel_id; panel++) 2097 + if (panel->ident.panel_id == panel_id) 2119 2098 return panel; 2120 2099 2121 2100 return NULL;
+225 -3
drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
··· 455 455 ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */ 456 456 }; 457 457 458 + static const struct ili9881c_instr kd050hdfia020_init[] = { 459 + ILI9881C_SWITCH_PAGE_INSTR(3), 460 + ILI9881C_COMMAND_INSTR(0x01, 0x00), 461 + ILI9881C_COMMAND_INSTR(0x02, 0x00), 462 + ILI9881C_COMMAND_INSTR(0x03, 0x72), 463 + ILI9881C_COMMAND_INSTR(0x04, 0x00), 464 + ILI9881C_COMMAND_INSTR(0x05, 0x00), 465 + ILI9881C_COMMAND_INSTR(0x06, 0x09), 466 + ILI9881C_COMMAND_INSTR(0x07, 0x00), 467 + ILI9881C_COMMAND_INSTR(0x08, 0x00), 468 + ILI9881C_COMMAND_INSTR(0x09, 0x01), 469 + ILI9881C_COMMAND_INSTR(0x0a, 0x00), 470 + ILI9881C_COMMAND_INSTR(0x0b, 0x00), 471 + ILI9881C_COMMAND_INSTR(0x0c, 0x01), 472 + ILI9881C_COMMAND_INSTR(0x0d, 0x00), 473 + ILI9881C_COMMAND_INSTR(0x0e, 0x00), 474 + ILI9881C_COMMAND_INSTR(0x0f, 0x00), 475 + ILI9881C_COMMAND_INSTR(0x10, 0x00), 476 + ILI9881C_COMMAND_INSTR(0x11, 0x00), 477 + ILI9881C_COMMAND_INSTR(0x12, 0x00), 478 + ILI9881C_COMMAND_INSTR(0x13, 0x00), 479 + ILI9881C_COMMAND_INSTR(0x14, 0x00), 480 + ILI9881C_COMMAND_INSTR(0x15, 0x00), 481 + ILI9881C_COMMAND_INSTR(0x16, 0x00), 482 + ILI9881C_COMMAND_INSTR(0x17, 0x00), 483 + ILI9881C_COMMAND_INSTR(0x18, 0x00), 484 + ILI9881C_COMMAND_INSTR(0x19, 0x00), 485 + ILI9881C_COMMAND_INSTR(0x1a, 0x00), 486 + ILI9881C_COMMAND_INSTR(0x1b, 0x00), 487 + ILI9881C_COMMAND_INSTR(0x1c, 0x00), 488 + ILI9881C_COMMAND_INSTR(0x1d, 0x00), 489 + ILI9881C_COMMAND_INSTR(0x1e, 0x40), 490 + ILI9881C_COMMAND_INSTR(0x1f, 0x80), 491 + ILI9881C_COMMAND_INSTR(0x20, 0x05), 492 + ILI9881C_COMMAND_INSTR(0x20, 0x05), 493 + ILI9881C_COMMAND_INSTR(0x21, 0x02), 494 + ILI9881C_COMMAND_INSTR(0x22, 0x00), 495 + ILI9881C_COMMAND_INSTR(0x23, 0x00), 496 + ILI9881C_COMMAND_INSTR(0x24, 0x00), 497 + ILI9881C_COMMAND_INSTR(0x25, 0x00), 498 + ILI9881C_COMMAND_INSTR(0x26, 0x00), 499 + ILI9881C_COMMAND_INSTR(0x27, 0x00), 500 + ILI9881C_COMMAND_INSTR(0x28, 0x33), 501 + ILI9881C_COMMAND_INSTR(0x29, 0x02), 502 + ILI9881C_COMMAND_INSTR(0x2a, 0x00), 503 + ILI9881C_COMMAND_INSTR(0x2b, 0x00), 504 + ILI9881C_COMMAND_INSTR(0x2c, 0x00), 505 + ILI9881C_COMMAND_INSTR(0x2d, 0x00), 506 + ILI9881C_COMMAND_INSTR(0x2e, 0x00), 507 + ILI9881C_COMMAND_INSTR(0x2f, 0x00), 508 + ILI9881C_COMMAND_INSTR(0x30, 0x00), 509 + ILI9881C_COMMAND_INSTR(0x31, 0x00), 510 + ILI9881C_COMMAND_INSTR(0x32, 0x00), 511 + ILI9881C_COMMAND_INSTR(0x32, 0x00), 512 + ILI9881C_COMMAND_INSTR(0x33, 0x00), 513 + ILI9881C_COMMAND_INSTR(0x34, 0x04), 514 + ILI9881C_COMMAND_INSTR(0x35, 0x00), 515 + ILI9881C_COMMAND_INSTR(0x36, 0x00), 516 + ILI9881C_COMMAND_INSTR(0x37, 0x00), 517 + ILI9881C_COMMAND_INSTR(0x38, 0x3C), 518 + ILI9881C_COMMAND_INSTR(0x39, 0x00), 519 + ILI9881C_COMMAND_INSTR(0x3a, 0x40), 520 + ILI9881C_COMMAND_INSTR(0x3b, 0x40), 521 + ILI9881C_COMMAND_INSTR(0x3c, 0x00), 522 + ILI9881C_COMMAND_INSTR(0x3d, 0x00), 523 + ILI9881C_COMMAND_INSTR(0x3e, 0x00), 524 + ILI9881C_COMMAND_INSTR(0x3f, 0x00), 525 + ILI9881C_COMMAND_INSTR(0x40, 0x00), 526 + ILI9881C_COMMAND_INSTR(0x41, 0x00), 527 + ILI9881C_COMMAND_INSTR(0x42, 0x00), 528 + ILI9881C_COMMAND_INSTR(0x43, 0x00), 529 + ILI9881C_COMMAND_INSTR(0x44, 0x00), 530 + ILI9881C_COMMAND_INSTR(0x50, 0x01), 531 + ILI9881C_COMMAND_INSTR(0x51, 0x23), 532 + ILI9881C_COMMAND_INSTR(0x52, 0x45), 533 + ILI9881C_COMMAND_INSTR(0x53, 0x67), 534 + ILI9881C_COMMAND_INSTR(0x54, 0x89), 535 + ILI9881C_COMMAND_INSTR(0x55, 0xab), 536 + ILI9881C_COMMAND_INSTR(0x56, 0x01), 537 + ILI9881C_COMMAND_INSTR(0x57, 0x23), 538 + ILI9881C_COMMAND_INSTR(0x58, 0x45), 539 + ILI9881C_COMMAND_INSTR(0x59, 0x67), 540 + ILI9881C_COMMAND_INSTR(0x5a, 0x89), 541 + ILI9881C_COMMAND_INSTR(0x5b, 0xab), 542 + ILI9881C_COMMAND_INSTR(0x5c, 0xcd), 543 + ILI9881C_COMMAND_INSTR(0x5d, 0xef), 544 + ILI9881C_COMMAND_INSTR(0x5e, 0x11), 545 + ILI9881C_COMMAND_INSTR(0x5f, 0x01), 546 + ILI9881C_COMMAND_INSTR(0x60, 0x00), 547 + ILI9881C_COMMAND_INSTR(0x61, 0x15), 548 + ILI9881C_COMMAND_INSTR(0x62, 0x14), 549 + ILI9881C_COMMAND_INSTR(0x63, 0x0E), 550 + ILI9881C_COMMAND_INSTR(0x64, 0x0F), 551 + ILI9881C_COMMAND_INSTR(0x65, 0x0C), 552 + ILI9881C_COMMAND_INSTR(0x66, 0x0D), 553 + ILI9881C_COMMAND_INSTR(0x67, 0x06), 554 + ILI9881C_COMMAND_INSTR(0x68, 0x02), 555 + ILI9881C_COMMAND_INSTR(0x69, 0x07), 556 + ILI9881C_COMMAND_INSTR(0x6a, 0x02), 557 + ILI9881C_COMMAND_INSTR(0x6b, 0x02), 558 + ILI9881C_COMMAND_INSTR(0x6c, 0x02), 559 + ILI9881C_COMMAND_INSTR(0x6d, 0x02), 560 + ILI9881C_COMMAND_INSTR(0x6e, 0x02), 561 + ILI9881C_COMMAND_INSTR(0x6f, 0x02), 562 + ILI9881C_COMMAND_INSTR(0x70, 0x02), 563 + ILI9881C_COMMAND_INSTR(0x71, 0x02), 564 + ILI9881C_COMMAND_INSTR(0x72, 0x02), 565 + ILI9881C_COMMAND_INSTR(0x73, 0x02), 566 + ILI9881C_COMMAND_INSTR(0x74, 0x02), 567 + ILI9881C_COMMAND_INSTR(0x75, 0x01), 568 + ILI9881C_COMMAND_INSTR(0x76, 0x00), 569 + ILI9881C_COMMAND_INSTR(0x77, 0x14), 570 + ILI9881C_COMMAND_INSTR(0x78, 0x15), 571 + ILI9881C_COMMAND_INSTR(0x79, 0x0E), 572 + ILI9881C_COMMAND_INSTR(0x7a, 0x0F), 573 + ILI9881C_COMMAND_INSTR(0x7b, 0x0C), 574 + ILI9881C_COMMAND_INSTR(0x7c, 0x0D), 575 + ILI9881C_COMMAND_INSTR(0x7d, 0x06), 576 + ILI9881C_COMMAND_INSTR(0x7e, 0x02), 577 + ILI9881C_COMMAND_INSTR(0x7f, 0x07), 578 + ILI9881C_COMMAND_INSTR(0x80, 0x02), 579 + ILI9881C_COMMAND_INSTR(0x81, 0x02), 580 + ILI9881C_COMMAND_INSTR(0x83, 0x02), 581 + ILI9881C_COMMAND_INSTR(0x84, 0x02), 582 + ILI9881C_COMMAND_INSTR(0x85, 0x02), 583 + ILI9881C_COMMAND_INSTR(0x86, 0x02), 584 + ILI9881C_COMMAND_INSTR(0x87, 0x02), 585 + ILI9881C_COMMAND_INSTR(0x88, 0x02), 586 + ILI9881C_COMMAND_INSTR(0x89, 0x02), 587 + ILI9881C_COMMAND_INSTR(0x8A, 0x02), 588 + ILI9881C_SWITCH_PAGE_INSTR(0x4), 589 + ILI9881C_COMMAND_INSTR(0x6C, 0x15), 590 + ILI9881C_COMMAND_INSTR(0x6E, 0x2A), 591 + ILI9881C_COMMAND_INSTR(0x6F, 0x33), 592 + ILI9881C_COMMAND_INSTR(0x3A, 0x94), 593 + ILI9881C_COMMAND_INSTR(0x8D, 0x15), 594 + ILI9881C_COMMAND_INSTR(0x87, 0xBA), 595 + ILI9881C_COMMAND_INSTR(0x26, 0x76), 596 + ILI9881C_COMMAND_INSTR(0xB2, 0xD1), 597 + ILI9881C_COMMAND_INSTR(0xB5, 0x06), 598 + ILI9881C_SWITCH_PAGE_INSTR(0x1), 599 + ILI9881C_COMMAND_INSTR(0x22, 0x0A), 600 + ILI9881C_COMMAND_INSTR(0x31, 0x00), 601 + ILI9881C_COMMAND_INSTR(0x53, 0x90), 602 + ILI9881C_COMMAND_INSTR(0x55, 0xA2), 603 + ILI9881C_COMMAND_INSTR(0x50, 0xB7), 604 + ILI9881C_COMMAND_INSTR(0x51, 0xB7), 605 + ILI9881C_COMMAND_INSTR(0x60, 0x22), 606 + ILI9881C_COMMAND_INSTR(0x61, 0x00), 607 + ILI9881C_COMMAND_INSTR(0x62, 0x19), 608 + ILI9881C_COMMAND_INSTR(0x63, 0x10), 609 + ILI9881C_COMMAND_INSTR(0xA0, 0x08), 610 + ILI9881C_COMMAND_INSTR(0xA1, 0x1A), 611 + ILI9881C_COMMAND_INSTR(0xA2, 0x27), 612 + ILI9881C_COMMAND_INSTR(0xA3, 0x15), 613 + ILI9881C_COMMAND_INSTR(0xA4, 0x17), 614 + ILI9881C_COMMAND_INSTR(0xA5, 0x2A), 615 + ILI9881C_COMMAND_INSTR(0xA6, 0x1E), 616 + ILI9881C_COMMAND_INSTR(0xA7, 0x1F), 617 + ILI9881C_COMMAND_INSTR(0xA8, 0x8B), 618 + ILI9881C_COMMAND_INSTR(0xA9, 0x1B), 619 + ILI9881C_COMMAND_INSTR(0xAA, 0x27), 620 + ILI9881C_COMMAND_INSTR(0xAB, 0x78), 621 + ILI9881C_COMMAND_INSTR(0xAC, 0x18), 622 + ILI9881C_COMMAND_INSTR(0xAD, 0x18), 623 + ILI9881C_COMMAND_INSTR(0xAE, 0x4C), 624 + ILI9881C_COMMAND_INSTR(0xAF, 0x21), 625 + ILI9881C_COMMAND_INSTR(0xB0, 0x27), 626 + ILI9881C_COMMAND_INSTR(0xB1, 0x54), 627 + ILI9881C_COMMAND_INSTR(0xB2, 0x67), 628 + ILI9881C_COMMAND_INSTR(0xB3, 0x39), 629 + ILI9881C_COMMAND_INSTR(0xC0, 0x08), 630 + ILI9881C_COMMAND_INSTR(0xC1, 0x1A), 631 + ILI9881C_COMMAND_INSTR(0xC2, 0x27), 632 + ILI9881C_COMMAND_INSTR(0xC3, 0x15), 633 + ILI9881C_COMMAND_INSTR(0xC4, 0x17), 634 + ILI9881C_COMMAND_INSTR(0xC5, 0x2A), 635 + ILI9881C_COMMAND_INSTR(0xC6, 0x1E), 636 + ILI9881C_COMMAND_INSTR(0xC7, 0x1F), 637 + ILI9881C_COMMAND_INSTR(0xC8, 0x8B), 638 + ILI9881C_COMMAND_INSTR(0xC9, 0x1B), 639 + ILI9881C_COMMAND_INSTR(0xCA, 0x27), 640 + ILI9881C_COMMAND_INSTR(0xCB, 0x78), 641 + ILI9881C_COMMAND_INSTR(0xCC, 0x18), 642 + ILI9881C_COMMAND_INSTR(0xCD, 0x18), 643 + ILI9881C_COMMAND_INSTR(0xCE, 0x4C), 644 + ILI9881C_COMMAND_INSTR(0xCF, 0x21), 645 + ILI9881C_COMMAND_INSTR(0xD0, 0x27), 646 + ILI9881C_COMMAND_INSTR(0xD1, 0x54), 647 + ILI9881C_COMMAND_INSTR(0xD2, 0x67), 648 + ILI9881C_COMMAND_INSTR(0xD3, 0x39), 649 + ILI9881C_SWITCH_PAGE_INSTR(0), 650 + ILI9881C_COMMAND_INSTR(0x35, 0x00), 651 + ILI9881C_COMMAND_INSTR(0x3A, 0x7), 652 + }; 653 + 458 654 static const struct ili9881c_instr tl050hdv35_init[] = { 459 655 ILI9881C_SWITCH_PAGE_INSTR(3), 460 656 ILI9881C_COMMAND_INSTR(0x01, 0x00), ··· 1276 1080 msleep(5); 1277 1081 1278 1082 /* And reset it */ 1279 - gpiod_set_value(ctx->reset, 1); 1083 + gpiod_set_value_cansleep(ctx->reset, 1); 1280 1084 msleep(20); 1281 1085 1282 - gpiod_set_value(ctx->reset, 0); 1086 + gpiod_set_value_cansleep(ctx->reset, 0); 1283 1087 msleep(20); 1284 1088 1285 1089 for (i = 0; i < ctx->desc->init_length; i++) { ··· 1334 1138 1335 1139 mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); 1336 1140 regulator_disable(ctx->power); 1337 - gpiod_set_value(ctx->reset, 1); 1141 + gpiod_set_value_cansleep(ctx->reset, 1); 1338 1142 1339 1143 return 0; 1340 1144 } ··· 1371 1175 1372 1176 .width_mm = 135, 1373 1177 .height_mm = 217, 1178 + }; 1179 + 1180 + static const struct drm_display_mode kd050hdfia020_default_mode = { 1181 + .clock = 62000, 1182 + 1183 + .hdisplay = 720, 1184 + .hsync_start = 720 + 10, 1185 + .hsync_end = 720 + 10 + 20, 1186 + .htotal = 720 + 10 + 20 + 30, 1187 + 1188 + .vdisplay = 1280, 1189 + .vsync_start = 1280 + 10, 1190 + .vsync_end = 1280 + 10 + 10, 1191 + .vtotal = 1280 + 10 + 10 + 20, 1192 + 1193 + .width_mm = 62, 1194 + .height_mm = 110, 1374 1195 }; 1375 1196 1376 1197 static const struct drm_display_mode tl050hdv35_default_mode = { ··· 1558 1345 .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, 1559 1346 }; 1560 1347 1348 + static const struct ili9881c_desc kd050hdfia020_desc = { 1349 + .init = kd050hdfia020_init, 1350 + .init_length = ARRAY_SIZE(kd050hdfia020_init), 1351 + .mode = &kd050hdfia020_default_mode, 1352 + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 1353 + MIPI_DSI_MODE_LPM, 1354 + }; 1355 + 1561 1356 static const struct ili9881c_desc tl050hdv35_desc = { 1562 1357 .init = tl050hdv35_init, 1563 1358 .init_length = ARRAY_SIZE(tl050hdv35_init), ··· 1593 1372 static const struct of_device_id ili9881c_of_match[] = { 1594 1373 { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, 1595 1374 { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, 1375 + { .compatible = "startek,kd050hdfia020", .data = &kd050hdfia020_desc }, 1596 1376 { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, 1597 1377 { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc }, 1598 1378 { .compatible = "ampire,am8001280g", .data = &am8001280g_desc },
+2 -3
drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
··· 295 295 mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x00); 296 296 mipi_dsi_dcs_write_seq(dsi, 0xc6, 0xef); 297 297 mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x02); 298 - mipi_dsi_dcs_write_seq(dsi, 0x11); 299 - mipi_dsi_dcs_write_seq(dsi, 0x29); 300 298 301 299 ret = mipi_dsi_dcs_set_tear_on(dsi, 1); 302 300 if (ret < 0) { ··· 324 326 static const struct ltk050h3146w_desc ltk050h3148w_data = { 325 327 .mode = &ltk050h3148w_mode, 326 328 .init = ltk050h3148w_init_sequence, 327 - .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_VIDEO_BURST, 329 + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 330 + MIPI_DSI_MODE_VIDEO_BURST, 328 331 }; 329 332 330 333 static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
+13 -9
drivers/gpu/drm/panel/panel-samsung-atna33xc20.c
··· 109 109 if (hpd_asserted < 0) 110 110 ret = hpd_asserted; 111 111 112 - if (ret) 112 + if (ret) { 113 113 dev_warn(dev, "Error waiting for HPD GPIO: %d\n", ret); 114 - 115 - return ret; 116 - } 117 - 118 - if (p->aux->wait_hpd_asserted) { 114 + goto error; 115 + } 116 + } else if (p->aux->wait_hpd_asserted) { 119 117 ret = p->aux->wait_hpd_asserted(p->aux, HPD_MAX_US); 120 118 121 - if (ret) 119 + if (ret) { 122 120 dev_warn(dev, "Controller error waiting for HPD: %d\n", ret); 123 - 124 - return ret; 121 + goto error; 122 + } 125 123 } 126 124 127 125 /* ··· 131 133 * right times. 132 134 */ 133 135 return 0; 136 + 137 + error: 138 + drm_dp_dpcd_set_powered(p->aux, false); 139 + regulator_disable(p->supply); 140 + 141 + return ret; 134 142 } 135 143 136 144 static int atana33xc20_disable(struct drm_panel *panel)
+285
drivers/gpu/drm/panel/panel-samsung-s6e3fa7.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Driver for the Samsung S6E3FA7 panel. 4 + * 5 + * Copyright (c) 2022-2024, The Linux Foundation. All rights reserved. 6 + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: 7 + * Copyright (c) 2013, The Linux Foundation. All rights reserved. 8 + */ 9 + 10 + #include <linux/backlight.h> 11 + #include <linux/delay.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + 16 + #include <video/mipi_display.h> 17 + 18 + #include <drm/drm_mipi_dsi.h> 19 + #include <drm/drm_modes.h> 20 + #include <drm/drm_panel.h> 21 + 22 + struct s6e3fa7_panel { 23 + struct drm_panel panel; 24 + struct mipi_dsi_device *dsi; 25 + struct gpio_desc *reset_gpio; 26 + }; 27 + 28 + static inline struct s6e3fa7_panel *to_s6e3fa7_panel(struct drm_panel *panel) 29 + { 30 + return container_of(panel, struct s6e3fa7_panel, panel); 31 + } 32 + 33 + static void s6e3fa7_panel_reset(struct s6e3fa7_panel *ctx) 34 + { 35 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 36 + usleep_range(1000, 2000); 37 + gpiod_set_value_cansleep(ctx->reset_gpio, 0); 38 + usleep_range(10000, 11000); 39 + } 40 + 41 + static int s6e3fa7_panel_on(struct s6e3fa7_panel *ctx) 42 + { 43 + struct mipi_dsi_device *dsi = ctx->dsi; 44 + struct device *dev = &dsi->dev; 45 + int ret; 46 + 47 + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 48 + if (ret < 0) { 49 + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); 50 + return ret; 51 + } 52 + msleep(120); 53 + 54 + ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 55 + if (ret < 0) { 56 + dev_err(dev, "Failed to set tear on: %d\n", ret); 57 + return ret; 58 + } 59 + 60 + mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); 61 + mipi_dsi_dcs_write_seq(dsi, 0xf4, 62 + 0xbb, 0x23, 0x19, 0x3a, 0x9f, 0x0f, 0x09, 0xc0, 63 + 0x00, 0xb4, 0x37, 0x70, 0x79, 0x69); 64 + mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); 65 + mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); 66 + 67 + ret = mipi_dsi_dcs_set_display_on(dsi); 68 + if (ret < 0) { 69 + dev_err(dev, "Failed to set display on: %d\n", ret); 70 + return ret; 71 + } 72 + 73 + return 0; 74 + } 75 + 76 + static int s6e3fa7_panel_prepare(struct drm_panel *panel) 77 + { 78 + struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel); 79 + struct device *dev = &ctx->dsi->dev; 80 + int ret; 81 + 82 + s6e3fa7_panel_reset(ctx); 83 + 84 + ret = s6e3fa7_panel_on(ctx); 85 + if (ret < 0) { 86 + dev_err(dev, "Failed to initialize panel: %d\n", ret); 87 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 88 + return ret; 89 + } 90 + 91 + return 0; 92 + } 93 + 94 + static int s6e3fa7_panel_unprepare(struct drm_panel *panel) 95 + { 96 + struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel); 97 + 98 + gpiod_set_value_cansleep(ctx->reset_gpio, 1); 99 + 100 + return 0; 101 + } 102 + 103 + static int s6e3fa7_panel_disable(struct drm_panel *panel) 104 + { 105 + struct s6e3fa7_panel *ctx = to_s6e3fa7_panel(panel); 106 + struct mipi_dsi_device *dsi = ctx->dsi; 107 + struct device *dev = &dsi->dev; 108 + int ret; 109 + 110 + ret = mipi_dsi_dcs_set_display_off(dsi); 111 + if (ret < 0) { 112 + dev_err(dev, "Failed to set display off: %d\n", ret); 113 + return ret; 114 + } 115 + 116 + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 117 + if (ret < 0) { 118 + dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 119 + return ret; 120 + } 121 + msleep(120); 122 + 123 + return 0; 124 + } 125 + 126 + static const struct drm_display_mode s6e3fa7_panel_mode = { 127 + .clock = (1080 + 32 + 32 + 78) * (2220 + 32 + 4 + 78) * 60 / 1000, 128 + .hdisplay = 1080, 129 + .hsync_start = 1080 + 32, 130 + .hsync_end = 1080 + 32 + 32, 131 + .htotal = 1080 + 32 + 32 + 78, 132 + .vdisplay = 2220, 133 + .vsync_start = 2220 + 32, 134 + .vsync_end = 2220 + 32 + 4, 135 + .vtotal = 2220 + 32 + 4 + 78, 136 + .width_mm = 62, 137 + .height_mm = 127, 138 + }; 139 + 140 + static int s6e3fa7_panel_get_modes(struct drm_panel *panel, 141 + struct drm_connector *connector) 142 + { 143 + struct drm_display_mode *mode; 144 + 145 + mode = drm_mode_duplicate(connector->dev, &s6e3fa7_panel_mode); 146 + if (!mode) 147 + return -ENOMEM; 148 + 149 + drm_mode_set_name(mode); 150 + 151 + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 152 + connector->display_info.width_mm = mode->width_mm; 153 + connector->display_info.height_mm = mode->height_mm; 154 + drm_mode_probed_add(connector, mode); 155 + 156 + return 1; 157 + } 158 + 159 + static const struct drm_panel_funcs s6e3fa7_panel_funcs = { 160 + .prepare = s6e3fa7_panel_prepare, 161 + .unprepare = s6e3fa7_panel_unprepare, 162 + .disable = s6e3fa7_panel_disable, 163 + .get_modes = s6e3fa7_panel_get_modes, 164 + }; 165 + 166 + static int s6e3fa7_panel_bl_update_status(struct backlight_device *bl) 167 + { 168 + struct mipi_dsi_device *dsi = bl_get_data(bl); 169 + u16 brightness = backlight_get_brightness(bl); 170 + int ret; 171 + 172 + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); 173 + if (ret < 0) 174 + return ret; 175 + 176 + return 0; 177 + } 178 + 179 + static int s6e3fa7_panel_bl_get_brightness(struct backlight_device *bl) 180 + { 181 + struct mipi_dsi_device *dsi = bl_get_data(bl); 182 + u16 brightness; 183 + int ret; 184 + 185 + ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness); 186 + if (ret < 0) 187 + return ret; 188 + 189 + return brightness; 190 + } 191 + 192 + static const struct backlight_ops s6e3fa7_panel_bl_ops = { 193 + .update_status = s6e3fa7_panel_bl_update_status, 194 + .get_brightness = s6e3fa7_panel_bl_get_brightness, 195 + }; 196 + 197 + static struct backlight_device * 198 + s6e3fa7_panel_create_backlight(struct mipi_dsi_device *dsi) 199 + { 200 + struct device *dev = &dsi->dev; 201 + const struct backlight_properties props = { 202 + .type = BACKLIGHT_RAW, 203 + .brightness = 1023, 204 + .max_brightness = 1023, 205 + }; 206 + 207 + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 208 + &s6e3fa7_panel_bl_ops, &props); 209 + } 210 + 211 + static int s6e3fa7_panel_probe(struct mipi_dsi_device *dsi) 212 + { 213 + struct device *dev = &dsi->dev; 214 + struct s6e3fa7_panel *ctx; 215 + int ret; 216 + 217 + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 218 + if (!ctx) 219 + return -ENOMEM; 220 + 221 + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 222 + if (IS_ERR(ctx->reset_gpio)) 223 + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 224 + "Failed to get reset-gpios\n"); 225 + 226 + ctx->dsi = dsi; 227 + mipi_dsi_set_drvdata(dsi, ctx); 228 + 229 + dsi->lanes = 4; 230 + dsi->format = MIPI_DSI_FMT_RGB888; 231 + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | 232 + MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; 233 + 234 + drm_panel_init(&ctx->panel, dev, &s6e3fa7_panel_funcs, 235 + DRM_MODE_CONNECTOR_DSI); 236 + ctx->panel.prepare_prev_first = true; 237 + 238 + ctx->panel.backlight = s6e3fa7_panel_create_backlight(dsi); 239 + if (IS_ERR(ctx->panel.backlight)) 240 + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), 241 + "Failed to create backlight\n"); 242 + 243 + drm_panel_add(&ctx->panel); 244 + 245 + ret = mipi_dsi_attach(dsi); 246 + if (ret < 0) { 247 + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); 248 + drm_panel_remove(&ctx->panel); 249 + return ret; 250 + } 251 + 252 + return 0; 253 + } 254 + 255 + static void s6e3fa7_panel_remove(struct mipi_dsi_device *dsi) 256 + { 257 + struct s6e3fa7_panel *ctx = mipi_dsi_get_drvdata(dsi); 258 + int ret; 259 + 260 + ret = mipi_dsi_detach(dsi); 261 + if (ret < 0) 262 + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 263 + 264 + drm_panel_remove(&ctx->panel); 265 + } 266 + 267 + static const struct of_device_id s6e3fa7_panel_of_match[] = { 268 + { .compatible = "samsung,s6e3fa7-ams559nk06" }, 269 + { /* sentinel */ } 270 + }; 271 + MODULE_DEVICE_TABLE(of, s6e3fa7_panel_of_match); 272 + 273 + static struct mipi_dsi_driver s6e3fa7_panel_driver = { 274 + .probe = s6e3fa7_panel_probe, 275 + .remove = s6e3fa7_panel_remove, 276 + .driver = { 277 + .name = "panel-samsung-s6e3fa7", 278 + .of_match_table = s6e3fa7_panel_of_match, 279 + }, 280 + }; 281 + module_mipi_dsi_driver(s6e3fa7_panel_driver); 282 + 283 + MODULE_AUTHOR("Richard Acayan <mailingradian@gmail.com>"); 284 + MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA7 command mode DSI panel"); 285 + MODULE_LICENSE("GPL");
+58
drivers/gpu/drm/panel/panel-simple.c
··· 1457 1457 .connector_type = DRM_MODE_CONNECTOR_LVDS, 1458 1458 }; 1459 1459 1460 + static const struct display_timing cct_cmt430b19n00_timing = { 1461 + .pixelclock = { 8000000, 9000000, 12000000 }, 1462 + .hactive = { 480, 480, 480 }, 1463 + .hfront_porch = { 2, 8, 75 }, 1464 + .hback_porch = { 3, 43, 43 }, 1465 + .hsync_len = { 2, 4, 75 }, 1466 + .vactive = { 272, 272, 272 }, 1467 + .vfront_porch = { 2, 8, 37 }, 1468 + .vback_porch = { 2, 12, 12 }, 1469 + .vsync_len = { 2, 4, 37 }, 1470 + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW 1471 + }; 1472 + 1473 + static const struct panel_desc cct_cmt430b19n00 = { 1474 + .timings = &cct_cmt430b19n00_timing, 1475 + .num_timings = 1, 1476 + .bpc = 8, 1477 + .size = { 1478 + .width = 95, 1479 + .height = 53, 1480 + }, 1481 + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, 1482 + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, 1483 + .connector_type = DRM_MODE_CONNECTOR_DPI, 1484 + }; 1485 + 1460 1486 static const struct drm_display_mode cdtech_s043wq26h_ct7_mode = { 1461 1487 .clock = 9000, 1462 1488 .hdisplay = 480, ··· 3491 3465 .bus_format = MEDIA_BUS_FMT_RGB888_1X24, 3492 3466 }; 3493 3467 3468 + static const struct drm_display_mode powertip_ph128800t006_zhc01_mode = { 3469 + .clock = 66500, 3470 + .hdisplay = 1280, 3471 + .hsync_start = 1280 + 12, 3472 + .hsync_end = 1280 + 12 + 20, 3473 + .htotal = 1280 + 12 + 20 + 56, 3474 + .vdisplay = 800, 3475 + .vsync_start = 800 + 1, 3476 + .vsync_end = 800 + 1 + 3, 3477 + .vtotal = 800 + 1 + 3 + 20, 3478 + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, 3479 + }; 3480 + 3481 + static const struct panel_desc powertip_ph128800t006_zhc01 = { 3482 + .modes = &powertip_ph128800t006_zhc01_mode, 3483 + .num_modes = 1, 3484 + .bpc = 8, 3485 + .size = { 3486 + .width = 216, 3487 + .height = 135, 3488 + }, 3489 + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 3490 + .bus_flags = DRM_BUS_FLAG_DE_HIGH, 3491 + .connector_type = DRM_MODE_CONNECTOR_LVDS, 3492 + }; 3493 + 3494 3494 static const struct drm_display_mode powertip_ph800480t013_idf02_mode = { 3495 3495 .clock = 24750, 3496 3496 .hdisplay = 800, ··· 4455 4403 .compatible = "boe,hv070wsa-100", 4456 4404 .data = &boe_hv070wsa 4457 4405 }, { 4406 + .compatible = "cct,cmt430b19n00", 4407 + .data = &cct_cmt430b19n00, 4408 + }, { 4458 4409 .compatible = "cdtech,s043wq26h-ct7", 4459 4410 .data = &cdtech_s043wq26h_ct7, 4460 4411 }, { ··· 4694 4639 }, { 4695 4640 .compatible = "pda,91-00156-a0", 4696 4641 .data = &pda_91_00156_a0, 4642 + }, { 4643 + .compatible = "powertip,ph128800t006-zhc01", 4644 + .data = &powertip_ph128800t006_zhc01, 4697 4645 }, { 4698 4646 .compatible = "powertip,ph800480t013-idf02", 4699 4647 .data = &powertip_ph800480t013_idf02,
-2
drivers/gpu/drm/panfrost/Makefile
··· 12 12 panfrost_perfcnt.o \ 13 13 panfrost_dump.o 14 14 15 - panfrost-$(CONFIG_DEBUG_FS) += panfrost_debugfs.o 16 - 17 15 obj-$(CONFIG_DRM_PANFROST) += panfrost.o
-21
drivers/gpu/drm/panfrost/panfrost_debugfs.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* Copyright 2023 Collabora ltd. */ 3 - /* Copyright 2023 Amazon.com, Inc. or its affiliates. */ 4 - 5 - #include <linux/debugfs.h> 6 - #include <linux/platform_device.h> 7 - #include <drm/drm_debugfs.h> 8 - #include <drm/drm_file.h> 9 - #include <drm/panfrost_drm.h> 10 - 11 - #include "panfrost_device.h" 12 - #include "panfrost_gpu.h" 13 - #include "panfrost_debugfs.h" 14 - 15 - void panfrost_debugfs_init(struct drm_minor *minor) 16 - { 17 - struct drm_device *dev = minor->dev; 18 - struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev->dev)); 19 - 20 - debugfs_create_atomic_t("profile", 0600, minor->debugfs_root, &pfdev->profile_mode); 21 - }
-14
drivers/gpu/drm/panfrost/panfrost_debugfs.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* 3 - * Copyright 2023 Collabora ltd. 4 - * Copyright 2023 Amazon.com, Inc. or its affiliates. 5 - */ 6 - 7 - #ifndef PANFROST_DEBUGFS_H 8 - #define PANFROST_DEBUGFS_H 9 - 10 - #ifdef CONFIG_DEBUG_FS 11 - void panfrost_debugfs_init(struct drm_minor *minor); 12 - #endif 13 - 14 - #endif /* PANFROST_DEBUGFS_H */
+1 -1
drivers/gpu/drm/panfrost/panfrost_device.h
··· 130 130 struct list_head scheduled_jobs; 131 131 132 132 struct panfrost_perfcnt *perfcnt; 133 - atomic_t profile_mode; 133 + bool profile_mode; 134 134 135 135 struct mutex sched_lock; 136 136
+41 -9
drivers/gpu/drm/panfrost/panfrost_drv.c
··· 20 20 #include "panfrost_job.h" 21 21 #include "panfrost_gpu.h" 22 22 #include "panfrost_perfcnt.h" 23 - #include "panfrost_debugfs.h" 24 23 25 24 static bool unstable_ioctls; 26 25 module_param_unsafe(unstable_ioctls, bool, 0600); ··· 550 551 BUILD_BUG_ON(ARRAY_SIZE(engine_names) != NUM_JOB_SLOTS); 551 552 552 553 for (i = 0; i < NUM_JOB_SLOTS - 1; i++) { 553 - drm_printf(p, "drm-engine-%s:\t%llu ns\n", 554 - engine_names[i], panfrost_priv->engine_usage.elapsed_ns[i]); 555 - drm_printf(p, "drm-cycles-%s:\t%llu\n", 556 - engine_names[i], panfrost_priv->engine_usage.cycles[i]); 554 + if (pfdev->profile_mode) { 555 + drm_printf(p, "drm-engine-%s:\t%llu ns\n", 556 + engine_names[i], panfrost_priv->engine_usage.elapsed_ns[i]); 557 + drm_printf(p, "drm-cycles-%s:\t%llu\n", 558 + engine_names[i], panfrost_priv->engine_usage.cycles[i]); 559 + } 557 560 drm_printf(p, "drm-maxfreq-%s:\t%lu Hz\n", 558 561 engine_names[i], pfdev->pfdevfreq.fast_rate); 559 562 drm_printf(p, "drm-curfreq-%s:\t%lu Hz\n", ··· 601 600 602 601 .gem_create_object = panfrost_gem_create_object, 603 602 .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, 604 - 605 - #ifdef CONFIG_DEBUG_FS 606 - .debugfs_init = panfrost_debugfs_init, 607 - #endif 608 603 }; 609 604 610 605 static int panfrost_probe(struct platform_device *pdev) ··· 688 691 689 692 drm_dev_put(ddev); 690 693 } 694 + 695 + static ssize_t profiling_show(struct device *dev, 696 + struct device_attribute *attr, char *buf) 697 + { 698 + struct panfrost_device *pfdev = dev_get_drvdata(dev); 699 + 700 + return sysfs_emit(buf, "%d\n", pfdev->profile_mode); 701 + } 702 + 703 + static ssize_t profiling_store(struct device *dev, 704 + struct device_attribute *attr, 705 + const char *buf, size_t len) 706 + { 707 + struct panfrost_device *pfdev = dev_get_drvdata(dev); 708 + bool value; 709 + int err; 710 + 711 + err = kstrtobool(buf, &value); 712 + if (err) 713 + return err; 714 + 715 + pfdev->profile_mode = value; 716 + 717 + return len; 718 + } 719 + 720 + static DEVICE_ATTR_RW(profiling); 721 + 722 + static struct attribute *panfrost_attrs[] = { 723 + &dev_attr_profiling.attr, 724 + NULL, 725 + }; 726 + 727 + ATTRIBUTE_GROUPS(panfrost); 691 728 692 729 /* 693 730 * The OPP core wants the supply names to be NULL terminated, but we need the ··· 820 789 .name = "panfrost", 821 790 .pm = pm_ptr(&panfrost_pm_ops), 822 791 .of_match_table = dt_match, 792 + .dev_groups = panfrost_groups, 823 793 }, 824 794 }; 825 795 module_platform_driver(panfrost_driver);
+1 -1
drivers/gpu/drm/panfrost/panfrost_job.c
··· 243 243 subslot = panfrost_enqueue_job(pfdev, js, job); 244 244 /* Don't queue the job if a reset is in progress */ 245 245 if (!atomic_read(&pfdev->reset.pending)) { 246 - if (atomic_read(&pfdev->profile_mode)) { 246 + if (pfdev->profile_mode) { 247 247 panfrost_cycle_counter_get(pfdev); 248 248 job->is_profiled = true; 249 249 job->start_time = ktime_get();
+23
drivers/gpu/drm/panthor/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0 or MIT 2 + 3 + config DRM_PANTHOR 4 + tristate "Panthor (DRM support for ARM Mali CSF-based GPUs)" 5 + depends on DRM 6 + depends on ARM || ARM64 || COMPILE_TEST 7 + depends on !GENERIC_ATOMIC64 # for IOMMU_IO_PGTABLE_LPAE 8 + depends on MMU 9 + select DEVFREQ_GOV_SIMPLE_ONDEMAND 10 + select DRM_EXEC 11 + select DRM_GEM_SHMEM_HELPER 12 + select DRM_GPUVM 13 + select DRM_SCHED 14 + select IOMMU_IO_PGTABLE_LPAE 15 + select IOMMU_SUPPORT 16 + select PM_DEVFREQ 17 + help 18 + DRM driver for ARM Mali CSF-based GPUs. 19 + 20 + This driver is for Mali (or Immortalis) Valhall Gxxx GPUs. 21 + 22 + Note that the Mali-G68 and Mali-G78, while Valhall architecture, will 23 + be supported with the panfrost driver as they are not CSF GPUs.
+14
drivers/gpu/drm/panthor/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 or MIT 2 + 3 + panthor-y := \ 4 + panthor_devfreq.o \ 5 + panthor_device.o \ 6 + panthor_drv.o \ 7 + panthor_fw.o \ 8 + panthor_gem.o \ 9 + panthor_gpu.o \ 10 + panthor_heap.o \ 11 + panthor_mmu.o \ 12 + panthor_sched.o 13 + 14 + obj-$(CONFIG_DRM_PANTHOR) += panthor.o
+283
drivers/gpu/drm/panthor/panthor_devfreq.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2019 Collabora ltd. */ 3 + 4 + #include <linux/clk.h> 5 + #include <linux/devfreq.h> 6 + #include <linux/devfreq_cooling.h> 7 + #include <linux/platform_device.h> 8 + #include <linux/pm_opp.h> 9 + 10 + #include <drm/drm_managed.h> 11 + 12 + #include "panthor_devfreq.h" 13 + #include "panthor_device.h" 14 + 15 + /** 16 + * struct panthor_devfreq - Device frequency management 17 + */ 18 + struct panthor_devfreq { 19 + /** @devfreq: devfreq device. */ 20 + struct devfreq *devfreq; 21 + 22 + /** @gov_data: Governor data. */ 23 + struct devfreq_simple_ondemand_data gov_data; 24 + 25 + /** @busy_time: Busy time. */ 26 + ktime_t busy_time; 27 + 28 + /** @idle_time: Idle time. */ 29 + ktime_t idle_time; 30 + 31 + /** @time_last_update: Last update time. */ 32 + ktime_t time_last_update; 33 + 34 + /** @last_busy_state: True if the GPU was busy last time we updated the state. */ 35 + bool last_busy_state; 36 + 37 + /** 38 + * @lock: Lock used to protect busy_time, idle_time, time_last_update and 39 + * last_busy_state. 40 + * 41 + * These fields can be accessed concurrently by panthor_devfreq_get_dev_status() 42 + * and panthor_devfreq_record_{busy,idle}(). 43 + */ 44 + spinlock_t lock; 45 + }; 46 + 47 + static void panthor_devfreq_update_utilization(struct panthor_devfreq *pdevfreq) 48 + { 49 + ktime_t now, last; 50 + 51 + now = ktime_get(); 52 + last = pdevfreq->time_last_update; 53 + 54 + if (pdevfreq->last_busy_state) 55 + pdevfreq->busy_time += ktime_sub(now, last); 56 + else 57 + pdevfreq->idle_time += ktime_sub(now, last); 58 + 59 + pdevfreq->time_last_update = now; 60 + } 61 + 62 + static int panthor_devfreq_target(struct device *dev, unsigned long *freq, 63 + u32 flags) 64 + { 65 + struct dev_pm_opp *opp; 66 + 67 + opp = devfreq_recommended_opp(dev, freq, flags); 68 + if (IS_ERR(opp)) 69 + return PTR_ERR(opp); 70 + dev_pm_opp_put(opp); 71 + 72 + return dev_pm_opp_set_rate(dev, *freq); 73 + } 74 + 75 + static void panthor_devfreq_reset(struct panthor_devfreq *pdevfreq) 76 + { 77 + pdevfreq->busy_time = 0; 78 + pdevfreq->idle_time = 0; 79 + pdevfreq->time_last_update = ktime_get(); 80 + } 81 + 82 + static int panthor_devfreq_get_dev_status(struct device *dev, 83 + struct devfreq_dev_status *status) 84 + { 85 + struct panthor_device *ptdev = dev_get_drvdata(dev); 86 + struct panthor_devfreq *pdevfreq = ptdev->devfreq; 87 + unsigned long irqflags; 88 + 89 + status->current_frequency = clk_get_rate(ptdev->clks.core); 90 + 91 + spin_lock_irqsave(&pdevfreq->lock, irqflags); 92 + 93 + panthor_devfreq_update_utilization(pdevfreq); 94 + 95 + status->total_time = ktime_to_ns(ktime_add(pdevfreq->busy_time, 96 + pdevfreq->idle_time)); 97 + 98 + status->busy_time = ktime_to_ns(pdevfreq->busy_time); 99 + 100 + panthor_devfreq_reset(pdevfreq); 101 + 102 + spin_unlock_irqrestore(&pdevfreq->lock, irqflags); 103 + 104 + drm_dbg(&ptdev->base, "busy %lu total %lu %lu %% freq %lu MHz\n", 105 + status->busy_time, status->total_time, 106 + status->busy_time / (status->total_time / 100), 107 + status->current_frequency / 1000 / 1000); 108 + 109 + return 0; 110 + } 111 + 112 + static struct devfreq_dev_profile panthor_devfreq_profile = { 113 + .timer = DEVFREQ_TIMER_DELAYED, 114 + .polling_ms = 50, /* ~3 frames */ 115 + .target = panthor_devfreq_target, 116 + .get_dev_status = panthor_devfreq_get_dev_status, 117 + }; 118 + 119 + int panthor_devfreq_init(struct panthor_device *ptdev) 120 + { 121 + /* There's actually 2 regulators (mali and sram), but the OPP core only 122 + * supports one. 123 + * 124 + * We assume the sram regulator is coupled with the mali one and let 125 + * the coupling logic deal with voltage updates. 126 + */ 127 + static const char * const reg_names[] = { "mali", NULL }; 128 + struct thermal_cooling_device *cooling; 129 + struct device *dev = ptdev->base.dev; 130 + struct panthor_devfreq *pdevfreq; 131 + struct dev_pm_opp *opp; 132 + unsigned long cur_freq; 133 + int ret; 134 + 135 + pdevfreq = drmm_kzalloc(&ptdev->base, sizeof(*ptdev->devfreq), GFP_KERNEL); 136 + if (!pdevfreq) 137 + return -ENOMEM; 138 + 139 + ptdev->devfreq = pdevfreq; 140 + 141 + ret = devm_pm_opp_set_regulators(dev, reg_names); 142 + if (ret) { 143 + if (ret != -EPROBE_DEFER) 144 + DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n"); 145 + 146 + return ret; 147 + } 148 + 149 + ret = devm_pm_opp_of_add_table(dev); 150 + if (ret) 151 + return ret; 152 + 153 + spin_lock_init(&pdevfreq->lock); 154 + 155 + panthor_devfreq_reset(pdevfreq); 156 + 157 + cur_freq = clk_get_rate(ptdev->clks.core); 158 + 159 + opp = devfreq_recommended_opp(dev, &cur_freq, 0); 160 + if (IS_ERR(opp)) 161 + return PTR_ERR(opp); 162 + 163 + panthor_devfreq_profile.initial_freq = cur_freq; 164 + 165 + /* Regulator coupling only takes care of synchronizing/balancing voltage 166 + * updates, but the coupled regulator needs to be enabled manually. 167 + * 168 + * We use devm_regulator_get_enable_optional() and keep the sram supply 169 + * enabled until the device is removed, just like we do for the mali 170 + * supply, which is enabled when dev_pm_opp_set_opp(dev, opp) is called, 171 + * and disabled when the opp_table is torn down, using the devm action. 172 + * 173 + * If we really care about disabling regulators on suspend, we should: 174 + * - use devm_regulator_get_optional() here 175 + * - call dev_pm_opp_set_opp(dev, NULL) before leaving this function 176 + * (this disables the regulator passed to the OPP layer) 177 + * - call dev_pm_opp_set_opp(dev, NULL) and 178 + * regulator_disable(ptdev->regulators.sram) in 179 + * panthor_devfreq_suspend() 180 + * - call dev_pm_opp_set_opp(dev, default_opp) and 181 + * regulator_enable(ptdev->regulators.sram) in 182 + * panthor_devfreq_resume() 183 + * 184 + * But without knowing if it's beneficial or not (in term of power 185 + * consumption), or how much it slows down the suspend/resume steps, 186 + * let's just keep regulators enabled for the device lifetime. 187 + */ 188 + ret = devm_regulator_get_enable_optional(dev, "sram"); 189 + if (ret && ret != -ENODEV) { 190 + if (ret != -EPROBE_DEFER) 191 + DRM_DEV_ERROR(dev, "Couldn't retrieve/enable sram supply\n"); 192 + return ret; 193 + } 194 + 195 + /* 196 + * Set the recommend OPP this will enable and configure the regulator 197 + * if any and will avoid a switch off by regulator_late_cleanup() 198 + */ 199 + ret = dev_pm_opp_set_opp(dev, opp); 200 + if (ret) { 201 + DRM_DEV_ERROR(dev, "Couldn't set recommended OPP\n"); 202 + return ret; 203 + } 204 + 205 + dev_pm_opp_put(opp); 206 + 207 + /* 208 + * Setup default thresholds for the simple_ondemand governor. 209 + * The values are chosen based on experiments. 210 + */ 211 + pdevfreq->gov_data.upthreshold = 45; 212 + pdevfreq->gov_data.downdifferential = 5; 213 + 214 + pdevfreq->devfreq = devm_devfreq_add_device(dev, &panthor_devfreq_profile, 215 + DEVFREQ_GOV_SIMPLE_ONDEMAND, 216 + &pdevfreq->gov_data); 217 + if (IS_ERR(pdevfreq->devfreq)) { 218 + DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n"); 219 + ret = PTR_ERR(pdevfreq->devfreq); 220 + pdevfreq->devfreq = NULL; 221 + return ret; 222 + } 223 + 224 + cooling = devfreq_cooling_em_register(pdevfreq->devfreq, NULL); 225 + if (IS_ERR(cooling)) 226 + DRM_DEV_INFO(dev, "Failed to register cooling device\n"); 227 + 228 + return 0; 229 + } 230 + 231 + int panthor_devfreq_resume(struct panthor_device *ptdev) 232 + { 233 + struct panthor_devfreq *pdevfreq = ptdev->devfreq; 234 + 235 + if (!pdevfreq->devfreq) 236 + return 0; 237 + 238 + panthor_devfreq_reset(pdevfreq); 239 + 240 + return devfreq_resume_device(pdevfreq->devfreq); 241 + } 242 + 243 + int panthor_devfreq_suspend(struct panthor_device *ptdev) 244 + { 245 + struct panthor_devfreq *pdevfreq = ptdev->devfreq; 246 + 247 + if (!pdevfreq->devfreq) 248 + return 0; 249 + 250 + return devfreq_suspend_device(pdevfreq->devfreq); 251 + } 252 + 253 + void panthor_devfreq_record_busy(struct panthor_device *ptdev) 254 + { 255 + struct panthor_devfreq *pdevfreq = ptdev->devfreq; 256 + unsigned long irqflags; 257 + 258 + if (!pdevfreq->devfreq) 259 + return; 260 + 261 + spin_lock_irqsave(&pdevfreq->lock, irqflags); 262 + 263 + panthor_devfreq_update_utilization(pdevfreq); 264 + pdevfreq->last_busy_state = true; 265 + 266 + spin_unlock_irqrestore(&pdevfreq->lock, irqflags); 267 + } 268 + 269 + void panthor_devfreq_record_idle(struct panthor_device *ptdev) 270 + { 271 + struct panthor_devfreq *pdevfreq = ptdev->devfreq; 272 + unsigned long irqflags; 273 + 274 + if (!pdevfreq->devfreq) 275 + return; 276 + 277 + spin_lock_irqsave(&pdevfreq->lock, irqflags); 278 + 279 + panthor_devfreq_update_utilization(pdevfreq); 280 + pdevfreq->last_busy_state = false; 281 + 282 + spin_unlock_irqrestore(&pdevfreq->lock, irqflags); 283 + }
+21
drivers/gpu/drm/panthor/panthor_devfreq.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2019 Collabora ltd. */ 3 + 4 + #ifndef __PANTHOR_DEVFREQ_H__ 5 + #define __PANTHOR_DEVFREQ_H__ 6 + 7 + struct devfreq; 8 + struct thermal_cooling_device; 9 + 10 + struct panthor_device; 11 + struct panthor_devfreq; 12 + 13 + int panthor_devfreq_init(struct panthor_device *ptdev); 14 + 15 + int panthor_devfreq_resume(struct panthor_device *ptdev); 16 + int panthor_devfreq_suspend(struct panthor_device *ptdev); 17 + 18 + void panthor_devfreq_record_busy(struct panthor_device *ptdev); 19 + void panthor_devfreq_record_idle(struct panthor_device *ptdev); 20 + 21 + #endif /* __PANTHOR_DEVFREQ_H__ */
+561
drivers/gpu/drm/panthor/panthor_device.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 3 + /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 4 + /* Copyright 2023 Collabora ltd. */ 5 + 6 + #include <linux/clk.h> 7 + #include <linux/mm.h> 8 + #include <linux/platform_device.h> 9 + #include <linux/pm_domain.h> 10 + #include <linux/pm_runtime.h> 11 + #include <linux/regulator/consumer.h> 12 + #include <linux/reset.h> 13 + 14 + #include <drm/drm_drv.h> 15 + #include <drm/drm_managed.h> 16 + 17 + #include "panthor_devfreq.h" 18 + #include "panthor_device.h" 19 + #include "panthor_fw.h" 20 + #include "panthor_gpu.h" 21 + #include "panthor_mmu.h" 22 + #include "panthor_regs.h" 23 + #include "panthor_sched.h" 24 + 25 + static int panthor_clk_init(struct panthor_device *ptdev) 26 + { 27 + ptdev->clks.core = devm_clk_get(ptdev->base.dev, NULL); 28 + if (IS_ERR(ptdev->clks.core)) 29 + return dev_err_probe(ptdev->base.dev, 30 + PTR_ERR(ptdev->clks.core), 31 + "get 'core' clock failed"); 32 + 33 + ptdev->clks.stacks = devm_clk_get_optional(ptdev->base.dev, "stacks"); 34 + if (IS_ERR(ptdev->clks.stacks)) 35 + return dev_err_probe(ptdev->base.dev, 36 + PTR_ERR(ptdev->clks.stacks), 37 + "get 'stacks' clock failed"); 38 + 39 + ptdev->clks.coregroup = devm_clk_get_optional(ptdev->base.dev, "coregroup"); 40 + if (IS_ERR(ptdev->clks.coregroup)) 41 + return dev_err_probe(ptdev->base.dev, 42 + PTR_ERR(ptdev->clks.coregroup), 43 + "get 'coregroup' clock failed"); 44 + 45 + drm_info(&ptdev->base, "clock rate = %lu\n", clk_get_rate(ptdev->clks.core)); 46 + return 0; 47 + } 48 + 49 + void panthor_device_unplug(struct panthor_device *ptdev) 50 + { 51 + /* This function can be called from two different path: the reset work 52 + * and the platform device remove callback. drm_dev_unplug() doesn't 53 + * deal with concurrent callers, so we have to protect drm_dev_unplug() 54 + * calls with our own lock, and bail out if the device is already 55 + * unplugged. 56 + */ 57 + mutex_lock(&ptdev->unplug.lock); 58 + if (drm_dev_is_unplugged(&ptdev->base)) { 59 + /* Someone beat us, release the lock and wait for the unplug 60 + * operation to be reported as done. 61 + **/ 62 + mutex_unlock(&ptdev->unplug.lock); 63 + wait_for_completion(&ptdev->unplug.done); 64 + return; 65 + } 66 + 67 + /* Call drm_dev_unplug() so any access to HW blocks happening after 68 + * that point get rejected. 69 + */ 70 + drm_dev_unplug(&ptdev->base); 71 + 72 + /* We do the rest of the unplug with the unplug lock released, 73 + * future callers will wait on ptdev->unplug.done anyway. 74 + */ 75 + mutex_unlock(&ptdev->unplug.lock); 76 + 77 + drm_WARN_ON(&ptdev->base, pm_runtime_get_sync(ptdev->base.dev) < 0); 78 + 79 + /* Now, try to cleanly shutdown the GPU before the device resources 80 + * get reclaimed. 81 + */ 82 + panthor_sched_unplug(ptdev); 83 + panthor_fw_unplug(ptdev); 84 + panthor_mmu_unplug(ptdev); 85 + panthor_gpu_unplug(ptdev); 86 + 87 + pm_runtime_dont_use_autosuspend(ptdev->base.dev); 88 + pm_runtime_put_sync_suspend(ptdev->base.dev); 89 + 90 + /* If PM is disabled, we need to call the suspend handler manually. */ 91 + if (!IS_ENABLED(CONFIG_PM)) 92 + panthor_device_suspend(ptdev->base.dev); 93 + 94 + /* Report the unplug operation as done to unblock concurrent 95 + * panthor_device_unplug() callers. 96 + */ 97 + complete_all(&ptdev->unplug.done); 98 + } 99 + 100 + static void panthor_device_reset_cleanup(struct drm_device *ddev, void *data) 101 + { 102 + struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); 103 + 104 + cancel_work_sync(&ptdev->reset.work); 105 + destroy_workqueue(ptdev->reset.wq); 106 + } 107 + 108 + static void panthor_device_reset_work(struct work_struct *work) 109 + { 110 + struct panthor_device *ptdev = container_of(work, struct panthor_device, reset.work); 111 + int ret = 0, cookie; 112 + 113 + if (atomic_read(&ptdev->pm.state) != PANTHOR_DEVICE_PM_STATE_ACTIVE) { 114 + /* 115 + * No need for a reset as the device has been (or will be) 116 + * powered down 117 + */ 118 + atomic_set(&ptdev->reset.pending, 0); 119 + return; 120 + } 121 + 122 + if (!drm_dev_enter(&ptdev->base, &cookie)) 123 + return; 124 + 125 + panthor_sched_pre_reset(ptdev); 126 + panthor_fw_pre_reset(ptdev, true); 127 + panthor_mmu_pre_reset(ptdev); 128 + panthor_gpu_soft_reset(ptdev); 129 + panthor_gpu_l2_power_on(ptdev); 130 + panthor_mmu_post_reset(ptdev); 131 + ret = panthor_fw_post_reset(ptdev); 132 + if (ret) 133 + goto out_dev_exit; 134 + 135 + atomic_set(&ptdev->reset.pending, 0); 136 + panthor_sched_post_reset(ptdev); 137 + 138 + out_dev_exit: 139 + drm_dev_exit(cookie); 140 + 141 + if (ret) { 142 + panthor_device_unplug(ptdev); 143 + drm_err(&ptdev->base, "Failed to boot MCU after reset, making device unusable."); 144 + } 145 + } 146 + 147 + static bool panthor_device_is_initialized(struct panthor_device *ptdev) 148 + { 149 + return !!ptdev->scheduler; 150 + } 151 + 152 + static void panthor_device_free_page(struct drm_device *ddev, void *data) 153 + { 154 + __free_page(data); 155 + } 156 + 157 + int panthor_device_init(struct panthor_device *ptdev) 158 + { 159 + u32 *dummy_page_virt; 160 + struct resource *res; 161 + struct page *p; 162 + int ret; 163 + 164 + ptdev->coherent = device_get_dma_attr(ptdev->base.dev) == DEV_DMA_COHERENT; 165 + 166 + init_completion(&ptdev->unplug.done); 167 + ret = drmm_mutex_init(&ptdev->base, &ptdev->unplug.lock); 168 + if (ret) 169 + return ret; 170 + 171 + ret = drmm_mutex_init(&ptdev->base, &ptdev->pm.mmio_lock); 172 + if (ret) 173 + return ret; 174 + 175 + atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_SUSPENDED); 176 + p = alloc_page(GFP_KERNEL | __GFP_ZERO); 177 + if (!p) 178 + return -ENOMEM; 179 + 180 + ptdev->pm.dummy_latest_flush = p; 181 + dummy_page_virt = page_address(p); 182 + ret = drmm_add_action_or_reset(&ptdev->base, panthor_device_free_page, 183 + ptdev->pm.dummy_latest_flush); 184 + if (ret) 185 + return ret; 186 + 187 + /* 188 + * Set the dummy page holding the latest flush to 1. This will cause the 189 + * flush to avoided as we know it isn't necessary if the submission 190 + * happens while the dummy page is mapped. Zero cannot be used because 191 + * that means 'always flush'. 192 + */ 193 + *dummy_page_virt = 1; 194 + 195 + INIT_WORK(&ptdev->reset.work, panthor_device_reset_work); 196 + ptdev->reset.wq = alloc_ordered_workqueue("panthor-reset-wq", 0); 197 + if (!ptdev->reset.wq) 198 + return -ENOMEM; 199 + 200 + ret = drmm_add_action_or_reset(&ptdev->base, panthor_device_reset_cleanup, NULL); 201 + if (ret) 202 + return ret; 203 + 204 + ret = panthor_clk_init(ptdev); 205 + if (ret) 206 + return ret; 207 + 208 + ret = panthor_devfreq_init(ptdev); 209 + if (ret) 210 + return ret; 211 + 212 + ptdev->iomem = devm_platform_get_and_ioremap_resource(to_platform_device(ptdev->base.dev), 213 + 0, &res); 214 + if (IS_ERR(ptdev->iomem)) 215 + return PTR_ERR(ptdev->iomem); 216 + 217 + ptdev->phys_addr = res->start; 218 + 219 + ret = devm_pm_runtime_enable(ptdev->base.dev); 220 + if (ret) 221 + return ret; 222 + 223 + ret = pm_runtime_resume_and_get(ptdev->base.dev); 224 + if (ret) 225 + return ret; 226 + 227 + /* If PM is disabled, we need to call panthor_device_resume() manually. */ 228 + if (!IS_ENABLED(CONFIG_PM)) { 229 + ret = panthor_device_resume(ptdev->base.dev); 230 + if (ret) 231 + return ret; 232 + } 233 + 234 + ret = panthor_gpu_init(ptdev); 235 + if (ret) 236 + goto err_rpm_put; 237 + 238 + ret = panthor_mmu_init(ptdev); 239 + if (ret) 240 + goto err_unplug_gpu; 241 + 242 + ret = panthor_fw_init(ptdev); 243 + if (ret) 244 + goto err_unplug_mmu; 245 + 246 + ret = panthor_sched_init(ptdev); 247 + if (ret) 248 + goto err_unplug_fw; 249 + 250 + /* ~3 frames */ 251 + pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50); 252 + pm_runtime_use_autosuspend(ptdev->base.dev); 253 + 254 + ret = drm_dev_register(&ptdev->base, 0); 255 + if (ret) 256 + goto err_disable_autosuspend; 257 + 258 + pm_runtime_put_autosuspend(ptdev->base.dev); 259 + return 0; 260 + 261 + err_disable_autosuspend: 262 + pm_runtime_dont_use_autosuspend(ptdev->base.dev); 263 + panthor_sched_unplug(ptdev); 264 + 265 + err_unplug_fw: 266 + panthor_fw_unplug(ptdev); 267 + 268 + err_unplug_mmu: 269 + panthor_mmu_unplug(ptdev); 270 + 271 + err_unplug_gpu: 272 + panthor_gpu_unplug(ptdev); 273 + 274 + err_rpm_put: 275 + pm_runtime_put_sync_suspend(ptdev->base.dev); 276 + return ret; 277 + } 278 + 279 + #define PANTHOR_EXCEPTION(id) \ 280 + [DRM_PANTHOR_EXCEPTION_ ## id] = { \ 281 + .name = #id, \ 282 + } 283 + 284 + struct panthor_exception_info { 285 + const char *name; 286 + }; 287 + 288 + static const struct panthor_exception_info panthor_exception_infos[] = { 289 + PANTHOR_EXCEPTION(OK), 290 + PANTHOR_EXCEPTION(TERMINATED), 291 + PANTHOR_EXCEPTION(KABOOM), 292 + PANTHOR_EXCEPTION(EUREKA), 293 + PANTHOR_EXCEPTION(ACTIVE), 294 + PANTHOR_EXCEPTION(CS_RES_TERM), 295 + PANTHOR_EXCEPTION(CS_CONFIG_FAULT), 296 + PANTHOR_EXCEPTION(CS_ENDPOINT_FAULT), 297 + PANTHOR_EXCEPTION(CS_BUS_FAULT), 298 + PANTHOR_EXCEPTION(CS_INSTR_INVALID), 299 + PANTHOR_EXCEPTION(CS_CALL_STACK_OVERFLOW), 300 + PANTHOR_EXCEPTION(CS_INHERIT_FAULT), 301 + PANTHOR_EXCEPTION(INSTR_INVALID_PC), 302 + PANTHOR_EXCEPTION(INSTR_INVALID_ENC), 303 + PANTHOR_EXCEPTION(INSTR_BARRIER_FAULT), 304 + PANTHOR_EXCEPTION(DATA_INVALID_FAULT), 305 + PANTHOR_EXCEPTION(TILE_RANGE_FAULT), 306 + PANTHOR_EXCEPTION(ADDR_RANGE_FAULT), 307 + PANTHOR_EXCEPTION(IMPRECISE_FAULT), 308 + PANTHOR_EXCEPTION(OOM), 309 + PANTHOR_EXCEPTION(CSF_FW_INTERNAL_ERROR), 310 + PANTHOR_EXCEPTION(CSF_RES_EVICTION_TIMEOUT), 311 + PANTHOR_EXCEPTION(GPU_BUS_FAULT), 312 + PANTHOR_EXCEPTION(GPU_SHAREABILITY_FAULT), 313 + PANTHOR_EXCEPTION(SYS_SHAREABILITY_FAULT), 314 + PANTHOR_EXCEPTION(GPU_CACHEABILITY_FAULT), 315 + PANTHOR_EXCEPTION(TRANSLATION_FAULT_0), 316 + PANTHOR_EXCEPTION(TRANSLATION_FAULT_1), 317 + PANTHOR_EXCEPTION(TRANSLATION_FAULT_2), 318 + PANTHOR_EXCEPTION(TRANSLATION_FAULT_3), 319 + PANTHOR_EXCEPTION(TRANSLATION_FAULT_4), 320 + PANTHOR_EXCEPTION(PERM_FAULT_0), 321 + PANTHOR_EXCEPTION(PERM_FAULT_1), 322 + PANTHOR_EXCEPTION(PERM_FAULT_2), 323 + PANTHOR_EXCEPTION(PERM_FAULT_3), 324 + PANTHOR_EXCEPTION(ACCESS_FLAG_1), 325 + PANTHOR_EXCEPTION(ACCESS_FLAG_2), 326 + PANTHOR_EXCEPTION(ACCESS_FLAG_3), 327 + PANTHOR_EXCEPTION(ADDR_SIZE_FAULT_IN), 328 + PANTHOR_EXCEPTION(ADDR_SIZE_FAULT_OUT0), 329 + PANTHOR_EXCEPTION(ADDR_SIZE_FAULT_OUT1), 330 + PANTHOR_EXCEPTION(ADDR_SIZE_FAULT_OUT2), 331 + PANTHOR_EXCEPTION(ADDR_SIZE_FAULT_OUT3), 332 + PANTHOR_EXCEPTION(MEM_ATTR_FAULT_0), 333 + PANTHOR_EXCEPTION(MEM_ATTR_FAULT_1), 334 + PANTHOR_EXCEPTION(MEM_ATTR_FAULT_2), 335 + PANTHOR_EXCEPTION(MEM_ATTR_FAULT_3), 336 + }; 337 + 338 + const char *panthor_exception_name(struct panthor_device *ptdev, u32 exception_code) 339 + { 340 + if (exception_code >= ARRAY_SIZE(panthor_exception_infos) || 341 + !panthor_exception_infos[exception_code].name) 342 + return "Unknown exception type"; 343 + 344 + return panthor_exception_infos[exception_code].name; 345 + } 346 + 347 + static vm_fault_t panthor_mmio_vm_fault(struct vm_fault *vmf) 348 + { 349 + struct vm_area_struct *vma = vmf->vma; 350 + struct panthor_device *ptdev = vma->vm_private_data; 351 + u64 id = (u64)vma->vm_pgoff << PAGE_SHIFT; 352 + unsigned long pfn; 353 + pgprot_t pgprot; 354 + vm_fault_t ret; 355 + bool active; 356 + int cookie; 357 + 358 + if (!drm_dev_enter(&ptdev->base, &cookie)) 359 + return VM_FAULT_SIGBUS; 360 + 361 + mutex_lock(&ptdev->pm.mmio_lock); 362 + active = atomic_read(&ptdev->pm.state) == PANTHOR_DEVICE_PM_STATE_ACTIVE; 363 + 364 + switch (panthor_device_mmio_offset(id)) { 365 + case DRM_PANTHOR_USER_FLUSH_ID_MMIO_OFFSET: 366 + if (active) 367 + pfn = __phys_to_pfn(ptdev->phys_addr + CSF_GPU_LATEST_FLUSH_ID); 368 + else 369 + pfn = page_to_pfn(ptdev->pm.dummy_latest_flush); 370 + break; 371 + 372 + default: 373 + ret = VM_FAULT_SIGBUS; 374 + goto out_unlock; 375 + } 376 + 377 + pgprot = vma->vm_page_prot; 378 + if (active) 379 + pgprot = pgprot_noncached(pgprot); 380 + 381 + ret = vmf_insert_pfn_prot(vma, vmf->address, pfn, pgprot); 382 + 383 + out_unlock: 384 + mutex_unlock(&ptdev->pm.mmio_lock); 385 + drm_dev_exit(cookie); 386 + return ret; 387 + } 388 + 389 + static const struct vm_operations_struct panthor_mmio_vm_ops = { 390 + .fault = panthor_mmio_vm_fault, 391 + }; 392 + 393 + int panthor_device_mmap_io(struct panthor_device *ptdev, struct vm_area_struct *vma) 394 + { 395 + u64 id = (u64)vma->vm_pgoff << PAGE_SHIFT; 396 + 397 + switch (panthor_device_mmio_offset(id)) { 398 + case DRM_PANTHOR_USER_FLUSH_ID_MMIO_OFFSET: 399 + if (vma->vm_end - vma->vm_start != PAGE_SIZE || 400 + (vma->vm_flags & (VM_WRITE | VM_EXEC))) 401 + return -EINVAL; 402 + 403 + break; 404 + 405 + default: 406 + return -EINVAL; 407 + } 408 + 409 + /* Defer actual mapping to the fault handler. */ 410 + vma->vm_private_data = ptdev; 411 + vma->vm_ops = &panthor_mmio_vm_ops; 412 + vm_flags_set(vma, 413 + VM_IO | VM_DONTCOPY | VM_DONTEXPAND | 414 + VM_NORESERVE | VM_DONTDUMP | VM_PFNMAP); 415 + return 0; 416 + } 417 + 418 + int panthor_device_resume(struct device *dev) 419 + { 420 + struct panthor_device *ptdev = dev_get_drvdata(dev); 421 + int ret, cookie; 422 + 423 + if (atomic_read(&ptdev->pm.state) != PANTHOR_DEVICE_PM_STATE_SUSPENDED) 424 + return -EINVAL; 425 + 426 + atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_RESUMING); 427 + 428 + ret = clk_prepare_enable(ptdev->clks.core); 429 + if (ret) 430 + goto err_set_suspended; 431 + 432 + ret = clk_prepare_enable(ptdev->clks.stacks); 433 + if (ret) 434 + goto err_disable_core_clk; 435 + 436 + ret = clk_prepare_enable(ptdev->clks.coregroup); 437 + if (ret) 438 + goto err_disable_stacks_clk; 439 + 440 + ret = panthor_devfreq_resume(ptdev); 441 + if (ret) 442 + goto err_disable_coregroup_clk; 443 + 444 + if (panthor_device_is_initialized(ptdev) && 445 + drm_dev_enter(&ptdev->base, &cookie)) { 446 + panthor_gpu_resume(ptdev); 447 + panthor_mmu_resume(ptdev); 448 + ret = drm_WARN_ON(&ptdev->base, panthor_fw_resume(ptdev)); 449 + if (!ret) { 450 + panthor_sched_resume(ptdev); 451 + } else { 452 + panthor_mmu_suspend(ptdev); 453 + panthor_gpu_suspend(ptdev); 454 + } 455 + 456 + drm_dev_exit(cookie); 457 + 458 + if (ret) 459 + goto err_suspend_devfreq; 460 + } 461 + 462 + if (atomic_read(&ptdev->reset.pending)) 463 + queue_work(ptdev->reset.wq, &ptdev->reset.work); 464 + 465 + /* Clear all IOMEM mappings pointing to this device after we've 466 + * resumed. This way the fake mappings pointing to the dummy pages 467 + * are removed and the real iomem mapping will be restored on next 468 + * access. 469 + */ 470 + mutex_lock(&ptdev->pm.mmio_lock); 471 + unmap_mapping_range(ptdev->base.anon_inode->i_mapping, 472 + DRM_PANTHOR_USER_MMIO_OFFSET, 0, 1); 473 + atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_ACTIVE); 474 + mutex_unlock(&ptdev->pm.mmio_lock); 475 + return 0; 476 + 477 + err_suspend_devfreq: 478 + panthor_devfreq_suspend(ptdev); 479 + 480 + err_disable_coregroup_clk: 481 + clk_disable_unprepare(ptdev->clks.coregroup); 482 + 483 + err_disable_stacks_clk: 484 + clk_disable_unprepare(ptdev->clks.stacks); 485 + 486 + err_disable_core_clk: 487 + clk_disable_unprepare(ptdev->clks.core); 488 + 489 + err_set_suspended: 490 + atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_SUSPENDED); 491 + return ret; 492 + } 493 + 494 + int panthor_device_suspend(struct device *dev) 495 + { 496 + struct panthor_device *ptdev = dev_get_drvdata(dev); 497 + int ret, cookie; 498 + 499 + if (atomic_read(&ptdev->pm.state) != PANTHOR_DEVICE_PM_STATE_ACTIVE) 500 + return -EINVAL; 501 + 502 + /* Clear all IOMEM mappings pointing to this device before we 503 + * shutdown the power-domain and clocks. Failing to do that results 504 + * in external aborts when the process accesses the iomem region. 505 + * We change the state and call unmap_mapping_range() with the 506 + * mmio_lock held to make sure the vm_fault handler won't set up 507 + * invalid mappings. 508 + */ 509 + mutex_lock(&ptdev->pm.mmio_lock); 510 + atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_SUSPENDING); 511 + unmap_mapping_range(ptdev->base.anon_inode->i_mapping, 512 + DRM_PANTHOR_USER_MMIO_OFFSET, 0, 1); 513 + mutex_unlock(&ptdev->pm.mmio_lock); 514 + 515 + if (panthor_device_is_initialized(ptdev) && 516 + drm_dev_enter(&ptdev->base, &cookie)) { 517 + cancel_work_sync(&ptdev->reset.work); 518 + 519 + /* We prepare everything as if we were resetting the GPU. 520 + * The end of the reset will happen in the resume path though. 521 + */ 522 + panthor_sched_suspend(ptdev); 523 + panthor_fw_suspend(ptdev); 524 + panthor_mmu_suspend(ptdev); 525 + panthor_gpu_suspend(ptdev); 526 + drm_dev_exit(cookie); 527 + } 528 + 529 + ret = panthor_devfreq_suspend(ptdev); 530 + if (ret) { 531 + if (panthor_device_is_initialized(ptdev) && 532 + drm_dev_enter(&ptdev->base, &cookie)) { 533 + panthor_gpu_resume(ptdev); 534 + panthor_mmu_resume(ptdev); 535 + drm_WARN_ON(&ptdev->base, panthor_fw_resume(ptdev)); 536 + panthor_sched_resume(ptdev); 537 + drm_dev_exit(cookie); 538 + } 539 + 540 + goto err_set_active; 541 + } 542 + 543 + clk_disable_unprepare(ptdev->clks.coregroup); 544 + clk_disable_unprepare(ptdev->clks.stacks); 545 + clk_disable_unprepare(ptdev->clks.core); 546 + atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_SUSPENDED); 547 + return 0; 548 + 549 + err_set_active: 550 + /* If something failed and we have to revert back to an 551 + * active state, we also need to clear the MMIO userspace 552 + * mappings, so any dumb pages that were mapped while we 553 + * were trying to suspend gets invalidated. 554 + */ 555 + mutex_lock(&ptdev->pm.mmio_lock); 556 + atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_ACTIVE); 557 + unmap_mapping_range(ptdev->base.anon_inode->i_mapping, 558 + DRM_PANTHOR_USER_MMIO_OFFSET, 0, 1); 559 + mutex_unlock(&ptdev->pm.mmio_lock); 560 + return ret; 561 + }
+394
drivers/gpu/drm/panthor/panthor_device.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 3 + /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 4 + /* Copyright 2023 Collabora ltd. */ 5 + 6 + #ifndef __PANTHOR_DEVICE_H__ 7 + #define __PANTHOR_DEVICE_H__ 8 + 9 + #include <linux/atomic.h> 10 + #include <linux/io-pgtable.h> 11 + #include <linux/regulator/consumer.h> 12 + #include <linux/sched.h> 13 + #include <linux/spinlock.h> 14 + 15 + #include <drm/drm_device.h> 16 + #include <drm/drm_mm.h> 17 + #include <drm/gpu_scheduler.h> 18 + #include <drm/panthor_drm.h> 19 + 20 + struct panthor_csf; 21 + struct panthor_csf_ctx; 22 + struct panthor_device; 23 + struct panthor_gpu; 24 + struct panthor_group_pool; 25 + struct panthor_heap_pool; 26 + struct panthor_job; 27 + struct panthor_mmu; 28 + struct panthor_fw; 29 + struct panthor_perfcnt; 30 + struct panthor_vm; 31 + struct panthor_vm_pool; 32 + 33 + /** 34 + * enum panthor_device_pm_state - PM state 35 + */ 36 + enum panthor_device_pm_state { 37 + /** @PANTHOR_DEVICE_PM_STATE_SUSPENDED: Device is suspended. */ 38 + PANTHOR_DEVICE_PM_STATE_SUSPENDED = 0, 39 + 40 + /** @PANTHOR_DEVICE_PM_STATE_RESUMING: Device is being resumed. */ 41 + PANTHOR_DEVICE_PM_STATE_RESUMING, 42 + 43 + /** @PANTHOR_DEVICE_PM_STATE_ACTIVE: Device is active. */ 44 + PANTHOR_DEVICE_PM_STATE_ACTIVE, 45 + 46 + /** @PANTHOR_DEVICE_PM_STATE_SUSPENDING: Device is being suspended. */ 47 + PANTHOR_DEVICE_PM_STATE_SUSPENDING, 48 + }; 49 + 50 + /** 51 + * struct panthor_irq - IRQ data 52 + * 53 + * Used to automate IRQ handling for the 3 different IRQs we have in this driver. 54 + */ 55 + struct panthor_irq { 56 + /** @ptdev: Panthor device */ 57 + struct panthor_device *ptdev; 58 + 59 + /** @irq: IRQ number. */ 60 + int irq; 61 + 62 + /** @mask: Current mask being applied to xxx_INT_MASK. */ 63 + u32 mask; 64 + 65 + /** @suspended: Set to true when the IRQ is suspended. */ 66 + atomic_t suspended; 67 + }; 68 + 69 + /** 70 + * struct panthor_device - Panthor device 71 + */ 72 + struct panthor_device { 73 + /** @base: Base drm_device. */ 74 + struct drm_device base; 75 + 76 + /** @phys_addr: Physical address of the iomem region. */ 77 + phys_addr_t phys_addr; 78 + 79 + /** @iomem: CPU mapping of the IOMEM region. */ 80 + void __iomem *iomem; 81 + 82 + /** @clks: GPU clocks. */ 83 + struct { 84 + /** @core: Core clock. */ 85 + struct clk *core; 86 + 87 + /** @stacks: Stacks clock. This clock is optional. */ 88 + struct clk *stacks; 89 + 90 + /** @coregroup: Core group clock. This clock is optional. */ 91 + struct clk *coregroup; 92 + } clks; 93 + 94 + /** @coherent: True if the CPU/GPU are memory coherent. */ 95 + bool coherent; 96 + 97 + /** @gpu_info: GPU information. */ 98 + struct drm_panthor_gpu_info gpu_info; 99 + 100 + /** @csif_info: Command stream interface information. */ 101 + struct drm_panthor_csif_info csif_info; 102 + 103 + /** @gpu: GPU management data. */ 104 + struct panthor_gpu *gpu; 105 + 106 + /** @fw: FW management data. */ 107 + struct panthor_fw *fw; 108 + 109 + /** @mmu: MMU management data. */ 110 + struct panthor_mmu *mmu; 111 + 112 + /** @scheduler: Scheduler management data. */ 113 + struct panthor_scheduler *scheduler; 114 + 115 + /** @devfreq: Device frequency scaling management data. */ 116 + struct panthor_devfreq *devfreq; 117 + 118 + /** @unplug: Device unplug related fields. */ 119 + struct { 120 + /** @lock: Lock used to serialize unplug operations. */ 121 + struct mutex lock; 122 + 123 + /** 124 + * @done: Completion object signaled when the unplug 125 + * operation is done. 126 + */ 127 + struct completion done; 128 + } unplug; 129 + 130 + /** @reset: Reset related fields. */ 131 + struct { 132 + /** @wq: Ordered worqueud used to schedule reset operations. */ 133 + struct workqueue_struct *wq; 134 + 135 + /** @work: Reset work. */ 136 + struct work_struct work; 137 + 138 + /** @pending: Set to true if a reset is pending. */ 139 + atomic_t pending; 140 + } reset; 141 + 142 + /** @pm: Power management related data. */ 143 + struct { 144 + /** @state: Power state. */ 145 + atomic_t state; 146 + 147 + /** 148 + * @mmio_lock: Lock protecting MMIO userspace CPU mappings. 149 + * 150 + * This is needed to ensure we map the dummy IO pages when 151 + * the device is being suspended, and the real IO pages when 152 + * the device is being resumed. We can't just do with the 153 + * state atomicity to deal with this race. 154 + */ 155 + struct mutex mmio_lock; 156 + 157 + /** 158 + * @dummy_latest_flush: Dummy LATEST_FLUSH page. 159 + * 160 + * Used to replace the real LATEST_FLUSH page when the GPU 161 + * is suspended. 162 + */ 163 + struct page *dummy_latest_flush; 164 + } pm; 165 + }; 166 + 167 + /** 168 + * struct panthor_file - Panthor file 169 + */ 170 + struct panthor_file { 171 + /** @ptdev: Device attached to this file. */ 172 + struct panthor_device *ptdev; 173 + 174 + /** @vms: VM pool attached to this file. */ 175 + struct panthor_vm_pool *vms; 176 + 177 + /** @groups: Scheduling group pool attached to this file. */ 178 + struct panthor_group_pool *groups; 179 + }; 180 + 181 + int panthor_device_init(struct panthor_device *ptdev); 182 + void panthor_device_unplug(struct panthor_device *ptdev); 183 + 184 + /** 185 + * panthor_device_schedule_reset() - Schedules a reset operation 186 + */ 187 + static inline void panthor_device_schedule_reset(struct panthor_device *ptdev) 188 + { 189 + if (!atomic_cmpxchg(&ptdev->reset.pending, 0, 1) && 190 + atomic_read(&ptdev->pm.state) == PANTHOR_DEVICE_PM_STATE_ACTIVE) 191 + queue_work(ptdev->reset.wq, &ptdev->reset.work); 192 + } 193 + 194 + /** 195 + * panthor_device_reset_is_pending() - Checks if a reset is pending. 196 + * 197 + * Return: true if a reset is pending, false otherwise. 198 + */ 199 + static inline bool panthor_device_reset_is_pending(struct panthor_device *ptdev) 200 + { 201 + return atomic_read(&ptdev->reset.pending) != 0; 202 + } 203 + 204 + int panthor_device_mmap_io(struct panthor_device *ptdev, 205 + struct vm_area_struct *vma); 206 + 207 + int panthor_device_resume(struct device *dev); 208 + int panthor_device_suspend(struct device *dev); 209 + 210 + enum drm_panthor_exception_type { 211 + DRM_PANTHOR_EXCEPTION_OK = 0x00, 212 + DRM_PANTHOR_EXCEPTION_TERMINATED = 0x04, 213 + DRM_PANTHOR_EXCEPTION_KABOOM = 0x05, 214 + DRM_PANTHOR_EXCEPTION_EUREKA = 0x06, 215 + DRM_PANTHOR_EXCEPTION_ACTIVE = 0x08, 216 + DRM_PANTHOR_EXCEPTION_CS_RES_TERM = 0x0f, 217 + DRM_PANTHOR_EXCEPTION_MAX_NON_FAULT = 0x3f, 218 + DRM_PANTHOR_EXCEPTION_CS_CONFIG_FAULT = 0x40, 219 + DRM_PANTHOR_EXCEPTION_CS_ENDPOINT_FAULT = 0x44, 220 + DRM_PANTHOR_EXCEPTION_CS_BUS_FAULT = 0x48, 221 + DRM_PANTHOR_EXCEPTION_CS_INSTR_INVALID = 0x49, 222 + DRM_PANTHOR_EXCEPTION_CS_CALL_STACK_OVERFLOW = 0x4a, 223 + DRM_PANTHOR_EXCEPTION_CS_INHERIT_FAULT = 0x4b, 224 + DRM_PANTHOR_EXCEPTION_INSTR_INVALID_PC = 0x50, 225 + DRM_PANTHOR_EXCEPTION_INSTR_INVALID_ENC = 0x51, 226 + DRM_PANTHOR_EXCEPTION_INSTR_BARRIER_FAULT = 0x55, 227 + DRM_PANTHOR_EXCEPTION_DATA_INVALID_FAULT = 0x58, 228 + DRM_PANTHOR_EXCEPTION_TILE_RANGE_FAULT = 0x59, 229 + DRM_PANTHOR_EXCEPTION_ADDR_RANGE_FAULT = 0x5a, 230 + DRM_PANTHOR_EXCEPTION_IMPRECISE_FAULT = 0x5b, 231 + DRM_PANTHOR_EXCEPTION_OOM = 0x60, 232 + DRM_PANTHOR_EXCEPTION_CSF_FW_INTERNAL_ERROR = 0x68, 233 + DRM_PANTHOR_EXCEPTION_CSF_RES_EVICTION_TIMEOUT = 0x69, 234 + DRM_PANTHOR_EXCEPTION_GPU_BUS_FAULT = 0x80, 235 + DRM_PANTHOR_EXCEPTION_GPU_SHAREABILITY_FAULT = 0x88, 236 + DRM_PANTHOR_EXCEPTION_SYS_SHAREABILITY_FAULT = 0x89, 237 + DRM_PANTHOR_EXCEPTION_GPU_CACHEABILITY_FAULT = 0x8a, 238 + DRM_PANTHOR_EXCEPTION_TRANSLATION_FAULT_0 = 0xc0, 239 + DRM_PANTHOR_EXCEPTION_TRANSLATION_FAULT_1 = 0xc1, 240 + DRM_PANTHOR_EXCEPTION_TRANSLATION_FAULT_2 = 0xc2, 241 + DRM_PANTHOR_EXCEPTION_TRANSLATION_FAULT_3 = 0xc3, 242 + DRM_PANTHOR_EXCEPTION_TRANSLATION_FAULT_4 = 0xc4, 243 + DRM_PANTHOR_EXCEPTION_PERM_FAULT_0 = 0xc8, 244 + DRM_PANTHOR_EXCEPTION_PERM_FAULT_1 = 0xc9, 245 + DRM_PANTHOR_EXCEPTION_PERM_FAULT_2 = 0xca, 246 + DRM_PANTHOR_EXCEPTION_PERM_FAULT_3 = 0xcb, 247 + DRM_PANTHOR_EXCEPTION_ACCESS_FLAG_1 = 0xd9, 248 + DRM_PANTHOR_EXCEPTION_ACCESS_FLAG_2 = 0xda, 249 + DRM_PANTHOR_EXCEPTION_ACCESS_FLAG_3 = 0xdb, 250 + DRM_PANTHOR_EXCEPTION_ADDR_SIZE_FAULT_IN = 0xe0, 251 + DRM_PANTHOR_EXCEPTION_ADDR_SIZE_FAULT_OUT0 = 0xe4, 252 + DRM_PANTHOR_EXCEPTION_ADDR_SIZE_FAULT_OUT1 = 0xe5, 253 + DRM_PANTHOR_EXCEPTION_ADDR_SIZE_FAULT_OUT2 = 0xe6, 254 + DRM_PANTHOR_EXCEPTION_ADDR_SIZE_FAULT_OUT3 = 0xe7, 255 + DRM_PANTHOR_EXCEPTION_MEM_ATTR_FAULT_0 = 0xe8, 256 + DRM_PANTHOR_EXCEPTION_MEM_ATTR_FAULT_1 = 0xe9, 257 + DRM_PANTHOR_EXCEPTION_MEM_ATTR_FAULT_2 = 0xea, 258 + DRM_PANTHOR_EXCEPTION_MEM_ATTR_FAULT_3 = 0xeb, 259 + }; 260 + 261 + /** 262 + * panthor_exception_is_fault() - Checks if an exception is a fault. 263 + * 264 + * Return: true if the exception is a fault, false otherwise. 265 + */ 266 + static inline bool 267 + panthor_exception_is_fault(u32 exception_code) 268 + { 269 + return exception_code > DRM_PANTHOR_EXCEPTION_MAX_NON_FAULT; 270 + } 271 + 272 + const char *panthor_exception_name(struct panthor_device *ptdev, 273 + u32 exception_code); 274 + 275 + /** 276 + * PANTHOR_IRQ_HANDLER() - Define interrupt handlers and the interrupt 277 + * registration function. 278 + * 279 + * The boiler-plate to gracefully deal with shared interrupts is 280 + * auto-generated. All you have to do is call PANTHOR_IRQ_HANDLER() 281 + * just after the actual handler. The handler prototype is: 282 + * 283 + * void (*handler)(struct panthor_device *, u32 status); 284 + */ 285 + #define PANTHOR_IRQ_HANDLER(__name, __reg_prefix, __handler) \ 286 + static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) \ 287 + { \ 288 + struct panthor_irq *pirq = data; \ 289 + struct panthor_device *ptdev = pirq->ptdev; \ 290 + \ 291 + if (atomic_read(&pirq->suspended)) \ 292 + return IRQ_NONE; \ 293 + if (!gpu_read(ptdev, __reg_prefix ## _INT_STAT)) \ 294 + return IRQ_NONE; \ 295 + \ 296 + gpu_write(ptdev, __reg_prefix ## _INT_MASK, 0); \ 297 + return IRQ_WAKE_THREAD; \ 298 + } \ 299 + \ 300 + static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *data) \ 301 + { \ 302 + struct panthor_irq *pirq = data; \ 303 + struct panthor_device *ptdev = pirq->ptdev; \ 304 + irqreturn_t ret = IRQ_NONE; \ 305 + \ 306 + while (true) { \ 307 + u32 status = gpu_read(ptdev, __reg_prefix ## _INT_RAWSTAT) & pirq->mask; \ 308 + \ 309 + if (!status) \ 310 + break; \ 311 + \ 312 + gpu_write(ptdev, __reg_prefix ## _INT_CLEAR, status); \ 313 + \ 314 + __handler(ptdev, status); \ 315 + ret = IRQ_HANDLED; \ 316 + } \ 317 + \ 318 + if (!atomic_read(&pirq->suspended)) \ 319 + gpu_write(ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ 320 + \ 321 + return ret; \ 322 + } \ 323 + \ 324 + static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq) \ 325 + { \ 326 + int cookie; \ 327 + \ 328 + atomic_set(&pirq->suspended, true); \ 329 + \ 330 + if (drm_dev_enter(&pirq->ptdev->base, &cookie)) { \ 331 + gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, 0); \ 332 + synchronize_irq(pirq->irq); \ 333 + drm_dev_exit(cookie); \ 334 + } \ 335 + \ 336 + pirq->mask = 0; \ 337 + } \ 338 + \ 339 + static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq, u32 mask) \ 340 + { \ 341 + int cookie; \ 342 + \ 343 + atomic_set(&pirq->suspended, false); \ 344 + pirq->mask = mask; \ 345 + \ 346 + if (drm_dev_enter(&pirq->ptdev->base, &cookie)) { \ 347 + gpu_write(pirq->ptdev, __reg_prefix ## _INT_CLEAR, mask); \ 348 + gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, mask); \ 349 + drm_dev_exit(cookie); \ 350 + } \ 351 + } \ 352 + \ 353 + static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \ 354 + struct panthor_irq *pirq, \ 355 + int irq, u32 mask) \ 356 + { \ 357 + pirq->ptdev = ptdev; \ 358 + pirq->irq = irq; \ 359 + panthor_ ## __name ## _irq_resume(pirq, mask); \ 360 + \ 361 + return devm_request_threaded_irq(ptdev->base.dev, irq, \ 362 + panthor_ ## __name ## _irq_raw_handler, \ 363 + panthor_ ## __name ## _irq_threaded_handler, \ 364 + IRQF_SHARED, KBUILD_MODNAME "-" # __name, \ 365 + pirq); \ 366 + } 367 + 368 + /** 369 + * panthor_device_mmio_offset() - Turn a user MMIO offset into a kernel one 370 + * @offset: Offset to convert. 371 + * 372 + * With 32-bit systems being limited by the 32-bit representation of mmap2's 373 + * pgoffset field, we need to make the MMIO offset arch specific. This function 374 + * converts a user MMIO offset into something the kernel driver understands. 375 + * 376 + * If the kernel and userspace architecture match, the offset is unchanged. If 377 + * the kernel is 64-bit and userspace is 32-bit, the offset is adjusted to match 378 + * 64-bit offsets. 32-bit kernel with 64-bit userspace is impossible. 379 + * 380 + * Return: Adjusted offset. 381 + */ 382 + static inline u64 panthor_device_mmio_offset(u64 offset) 383 + { 384 + #ifdef CONFIG_ARM64 385 + if (test_tsk_thread_flag(current, TIF_32BIT)) 386 + offset += DRM_PANTHOR_USER_MMIO_OFFSET_64BIT - DRM_PANTHOR_USER_MMIO_OFFSET_32BIT; 387 + #endif 388 + 389 + return offset; 390 + } 391 + 392 + extern struct workqueue_struct *panthor_cleanup_wq; 393 + 394 + #endif
+1473
drivers/gpu/drm/panthor/panthor_drv.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 3 + /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */ 4 + /* Copyright 2019 Collabora ltd. */ 5 + 6 + #include <linux/list.h> 7 + #include <linux/module.h> 8 + #include <linux/of_platform.h> 9 + #include <linux/pagemap.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/pm_runtime.h> 12 + 13 + #include <drm/drm_debugfs.h> 14 + #include <drm/drm_drv.h> 15 + #include <drm/drm_exec.h> 16 + #include <drm/drm_ioctl.h> 17 + #include <drm/drm_syncobj.h> 18 + #include <drm/drm_utils.h> 19 + #include <drm/gpu_scheduler.h> 20 + #include <drm/panthor_drm.h> 21 + 22 + #include "panthor_device.h" 23 + #include "panthor_fw.h" 24 + #include "panthor_gem.h" 25 + #include "panthor_gpu.h" 26 + #include "panthor_heap.h" 27 + #include "panthor_mmu.h" 28 + #include "panthor_regs.h" 29 + #include "panthor_sched.h" 30 + 31 + /** 32 + * DOC: user <-> kernel object copy helpers. 33 + */ 34 + 35 + /** 36 + * panthor_set_uobj() - Copy kernel object to user object. 37 + * @usr_ptr: Users pointer. 38 + * @usr_size: Size of the user object. 39 + * @min_size: Minimum size for this object. 40 + * @kern_size: Size of the kernel object. 41 + * @in: Address of the kernel object to copy. 42 + * 43 + * Helper automating kernel -> user object copies. 44 + * 45 + * Don't use this function directly, use PANTHOR_UOBJ_SET() instead. 46 + * 47 + * Return: 0 on success, a negative error code otherwise. 48 + */ 49 + static int 50 + panthor_set_uobj(u64 usr_ptr, u32 usr_size, u32 min_size, u32 kern_size, const void *in) 51 + { 52 + /* User size shouldn't be smaller than the minimal object size. */ 53 + if (usr_size < min_size) 54 + return -EINVAL; 55 + 56 + if (copy_to_user(u64_to_user_ptr(usr_ptr), in, min_t(u32, usr_size, kern_size))) 57 + return -EFAULT; 58 + 59 + /* When the kernel object is smaller than the user object, we fill the gap with 60 + * zeros. 61 + */ 62 + if (usr_size > kern_size && 63 + clear_user(u64_to_user_ptr(usr_ptr + kern_size), usr_size - kern_size)) { 64 + return -EFAULT; 65 + } 66 + 67 + return 0; 68 + } 69 + 70 + /** 71 + * panthor_get_uobj_array() - Copy a user object array into a kernel accessible object array. 72 + * @in: The object array to copy. 73 + * @min_stride: Minimum array stride. 74 + * @obj_size: Kernel object size. 75 + * 76 + * Helper automating user -> kernel object copies. 77 + * 78 + * Don't use this function directly, use PANTHOR_UOBJ_GET_ARRAY() instead. 79 + * 80 + * Return: newly allocated object array or an ERR_PTR on error. 81 + */ 82 + static void * 83 + panthor_get_uobj_array(const struct drm_panthor_obj_array *in, u32 min_stride, 84 + u32 obj_size) 85 + { 86 + int ret = 0; 87 + void *out_alloc; 88 + 89 + /* User stride must be at least the minimum object size, otherwise it might 90 + * lack useful information. 91 + */ 92 + if (in->stride < min_stride) 93 + return ERR_PTR(-EINVAL); 94 + 95 + if (!in->count) 96 + return NULL; 97 + 98 + out_alloc = kvmalloc_array(in->count, obj_size, GFP_KERNEL); 99 + if (!out_alloc) 100 + return ERR_PTR(-ENOMEM); 101 + 102 + if (obj_size == in->stride) { 103 + /* Fast path when user/kernel have the same uAPI header version. */ 104 + if (copy_from_user(out_alloc, u64_to_user_ptr(in->array), 105 + (unsigned long)obj_size * in->count)) 106 + ret = -EFAULT; 107 + } else { 108 + void __user *in_ptr = u64_to_user_ptr(in->array); 109 + void *out_ptr = out_alloc; 110 + 111 + /* If the sizes differ, we need to copy elements one by one. */ 112 + for (u32 i = 0; i < in->count; i++) { 113 + ret = copy_struct_from_user(out_ptr, obj_size, in_ptr, in->stride); 114 + if (ret) 115 + break; 116 + 117 + out_ptr += obj_size; 118 + in_ptr += in->stride; 119 + } 120 + } 121 + 122 + if (ret) { 123 + kvfree(out_alloc); 124 + return ERR_PTR(ret); 125 + } 126 + 127 + return out_alloc; 128 + } 129 + 130 + /** 131 + * PANTHOR_UOBJ_MIN_SIZE_INTERNAL() - Get the minimum user object size 132 + * @_typename: Object type. 133 + * @_last_mandatory_field: Last mandatory field. 134 + * 135 + * Get the minimum user object size based on the last mandatory field name, 136 + * A.K.A, the name of the last field of the structure at the time this 137 + * structure was added to the uAPI. 138 + * 139 + * Don't use directly, use PANTHOR_UOBJ_DECL() instead. 140 + */ 141 + #define PANTHOR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) \ 142 + (offsetof(_typename, _last_mandatory_field) + \ 143 + sizeof(((_typename *)NULL)->_last_mandatory_field)) 144 + 145 + /** 146 + * PANTHOR_UOBJ_DECL() - Declare a new uAPI object whose subject to 147 + * evolutions. 148 + * @_typename: Object type. 149 + * @_last_mandatory_field: Last mandatory field. 150 + * 151 + * Should be used to extend the PANTHOR_UOBJ_MIN_SIZE() list. 152 + */ 153 + #define PANTHOR_UOBJ_DECL(_typename, _last_mandatory_field) \ 154 + _typename : PANTHOR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) 155 + 156 + /** 157 + * PANTHOR_UOBJ_MIN_SIZE() - Get the minimum size of a given uAPI object 158 + * @_obj_name: Object to get the minimum size of. 159 + * 160 + * Don't use this macro directly, it's automatically called by 161 + * PANTHOR_UOBJ_{SET,GET_ARRAY}(). 162 + */ 163 + #define PANTHOR_UOBJ_MIN_SIZE(_obj_name) \ 164 + _Generic(_obj_name, \ 165 + PANTHOR_UOBJ_DECL(struct drm_panthor_gpu_info, tiler_present), \ 166 + PANTHOR_UOBJ_DECL(struct drm_panthor_csif_info, pad), \ 167 + PANTHOR_UOBJ_DECL(struct drm_panthor_sync_op, timeline_value), \ 168 + PANTHOR_UOBJ_DECL(struct drm_panthor_queue_submit, syncs), \ 169 + PANTHOR_UOBJ_DECL(struct drm_panthor_queue_create, ringbuf_size), \ 170 + PANTHOR_UOBJ_DECL(struct drm_panthor_vm_bind_op, syncs)) 171 + 172 + /** 173 + * PANTHOR_UOBJ_SET() - Copy a kernel object to a user object. 174 + * @_dest_usr_ptr: User pointer to copy to. 175 + * @_usr_size: Size of the user object. 176 + * @_src_obj: Kernel object to copy (not a pointer). 177 + * 178 + * Return: 0 on success, a negative error code otherwise. 179 + */ 180 + #define PANTHOR_UOBJ_SET(_dest_usr_ptr, _usr_size, _src_obj) \ 181 + panthor_set_uobj(_dest_usr_ptr, _usr_size, \ 182 + PANTHOR_UOBJ_MIN_SIZE(_src_obj), \ 183 + sizeof(_src_obj), &(_src_obj)) 184 + 185 + /** 186 + * PANTHOR_UOBJ_GET_ARRAY() - Copy a user object array to a kernel accessible 187 + * object array. 188 + * @_dest_array: Local variable that will hold the newly allocated kernel 189 + * object array. 190 + * @_uobj_array: The drm_panthor_obj_array object describing the user object 191 + * array. 192 + * 193 + * Return: 0 on success, a negative error code otherwise. 194 + */ 195 + #define PANTHOR_UOBJ_GET_ARRAY(_dest_array, _uobj_array) \ 196 + ({ \ 197 + typeof(_dest_array) _tmp; \ 198 + _tmp = panthor_get_uobj_array(_uobj_array, \ 199 + PANTHOR_UOBJ_MIN_SIZE((_dest_array)[0]), \ 200 + sizeof((_dest_array)[0])); \ 201 + if (!IS_ERR(_tmp)) \ 202 + _dest_array = _tmp; \ 203 + PTR_ERR_OR_ZERO(_tmp); \ 204 + }) 205 + 206 + /** 207 + * struct panthor_sync_signal - Represent a synchronization object point to attach 208 + * our job fence to. 209 + * 210 + * This structure is here to keep track of fences that are currently bound to 211 + * a specific syncobj point. 212 + * 213 + * At the beginning of a job submission, the fence 214 + * is retrieved from the syncobj itself, and can be NULL if no fence was attached 215 + * to this point. 216 + * 217 + * At the end, it points to the fence of the last job that had a 218 + * %DRM_PANTHOR_SYNC_OP_SIGNAL on this syncobj. 219 + * 220 + * With jobs being submitted in batches, the fence might change several times during 221 + * the process, allowing one job to wait on a job that's part of the same submission 222 + * but appears earlier in the drm_panthor_group_submit::queue_submits array. 223 + */ 224 + struct panthor_sync_signal { 225 + /** @node: list_head to track signal ops within a submit operation */ 226 + struct list_head node; 227 + 228 + /** @handle: The syncobj handle. */ 229 + u32 handle; 230 + 231 + /** 232 + * @point: The syncobj point. 233 + * 234 + * Zero for regular syncobjs, and non-zero for timeline syncobjs. 235 + */ 236 + u64 point; 237 + 238 + /** 239 + * @syncobj: The sync object pointed by @handle. 240 + */ 241 + struct drm_syncobj *syncobj; 242 + 243 + /** 244 + * @chain: Chain object used to link the new fence to an existing 245 + * timeline syncobj. 246 + * 247 + * NULL for regular syncobj, non-NULL for timeline syncobjs. 248 + */ 249 + struct dma_fence_chain *chain; 250 + 251 + /** 252 + * @fence: The fence to assign to the syncobj or syncobj-point. 253 + */ 254 + struct dma_fence *fence; 255 + }; 256 + 257 + /** 258 + * struct panthor_job_ctx - Job context 259 + */ 260 + struct panthor_job_ctx { 261 + /** @job: The job that is about to be submitted to drm_sched. */ 262 + struct drm_sched_job *job; 263 + 264 + /** @syncops: Array of sync operations. */ 265 + struct drm_panthor_sync_op *syncops; 266 + 267 + /** @syncop_count: Number of sync operations. */ 268 + u32 syncop_count; 269 + }; 270 + 271 + /** 272 + * struct panthor_submit_ctx - Submission context 273 + * 274 + * Anything that's related to a submission (%DRM_IOCTL_PANTHOR_VM_BIND or 275 + * %DRM_IOCTL_PANTHOR_GROUP_SUBMIT) is kept here, so we can automate the 276 + * initialization and cleanup steps. 277 + */ 278 + struct panthor_submit_ctx { 279 + /** @file: DRM file this submission happens on. */ 280 + struct drm_file *file; 281 + 282 + /** 283 + * @signals: List of struct panthor_sync_signal. 284 + * 285 + * %DRM_PANTHOR_SYNC_OP_SIGNAL operations will be recorded here, 286 + * and %DRM_PANTHOR_SYNC_OP_WAIT will first check if an entry 287 + * matching the syncobj+point exists before calling 288 + * drm_syncobj_find_fence(). This allows us to describe dependencies 289 + * existing between jobs that are part of the same batch. 290 + */ 291 + struct list_head signals; 292 + 293 + /** @jobs: Array of jobs. */ 294 + struct panthor_job_ctx *jobs; 295 + 296 + /** @job_count: Number of entries in the @jobs array. */ 297 + u32 job_count; 298 + 299 + /** @exec: drm_exec context used to acquire and prepare resv objects. */ 300 + struct drm_exec exec; 301 + }; 302 + 303 + #define PANTHOR_SYNC_OP_FLAGS_MASK \ 304 + (DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_MASK | DRM_PANTHOR_SYNC_OP_SIGNAL) 305 + 306 + static bool sync_op_is_signal(const struct drm_panthor_sync_op *sync_op) 307 + { 308 + return !!(sync_op->flags & DRM_PANTHOR_SYNC_OP_SIGNAL); 309 + } 310 + 311 + static bool sync_op_is_wait(const struct drm_panthor_sync_op *sync_op) 312 + { 313 + /* Note that DRM_PANTHOR_SYNC_OP_WAIT == 0 */ 314 + return !(sync_op->flags & DRM_PANTHOR_SYNC_OP_SIGNAL); 315 + } 316 + 317 + /** 318 + * panthor_check_sync_op() - Check drm_panthor_sync_op fields 319 + * @sync_op: The sync operation to check. 320 + * 321 + * Return: 0 on success, -EINVAL otherwise. 322 + */ 323 + static int 324 + panthor_check_sync_op(const struct drm_panthor_sync_op *sync_op) 325 + { 326 + u8 handle_type; 327 + 328 + if (sync_op->flags & ~PANTHOR_SYNC_OP_FLAGS_MASK) 329 + return -EINVAL; 330 + 331 + handle_type = sync_op->flags & DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_MASK; 332 + if (handle_type != DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_SYNCOBJ && 333 + handle_type != DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_TIMELINE_SYNCOBJ) 334 + return -EINVAL; 335 + 336 + if (handle_type == DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_SYNCOBJ && 337 + sync_op->timeline_value != 0) 338 + return -EINVAL; 339 + 340 + return 0; 341 + } 342 + 343 + /** 344 + * panthor_sync_signal_free() - Release resources and free a panthor_sync_signal object 345 + * @sig_sync: Signal object to free. 346 + */ 347 + static void 348 + panthor_sync_signal_free(struct panthor_sync_signal *sig_sync) 349 + { 350 + if (!sig_sync) 351 + return; 352 + 353 + drm_syncobj_put(sig_sync->syncobj); 354 + dma_fence_chain_free(sig_sync->chain); 355 + dma_fence_put(sig_sync->fence); 356 + kfree(sig_sync); 357 + } 358 + 359 + /** 360 + * panthor_submit_ctx_add_sync_signal() - Add a signal operation to a submit context 361 + * @ctx: Context to add the signal operation to. 362 + * @handle: Syncobj handle. 363 + * @point: Syncobj point. 364 + * 365 + * Return: 0 on success, otherwise negative error value. 366 + */ 367 + static int 368 + panthor_submit_ctx_add_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point) 369 + { 370 + struct panthor_sync_signal *sig_sync; 371 + struct dma_fence *cur_fence; 372 + int ret; 373 + 374 + sig_sync = kzalloc(sizeof(*sig_sync), GFP_KERNEL); 375 + if (!sig_sync) 376 + return -ENOMEM; 377 + 378 + sig_sync->handle = handle; 379 + sig_sync->point = point; 380 + 381 + if (point > 0) { 382 + sig_sync->chain = dma_fence_chain_alloc(); 383 + if (!sig_sync->chain) { 384 + ret = -ENOMEM; 385 + goto err_free_sig_sync; 386 + } 387 + } 388 + 389 + sig_sync->syncobj = drm_syncobj_find(ctx->file, handle); 390 + if (!sig_sync->syncobj) { 391 + ret = -EINVAL; 392 + goto err_free_sig_sync; 393 + } 394 + 395 + /* Retrieve the current fence attached to that point. It's 396 + * perfectly fine to get a NULL fence here, it just means there's 397 + * no fence attached to that point yet. 398 + */ 399 + if (!drm_syncobj_find_fence(ctx->file, handle, point, 0, &cur_fence)) 400 + sig_sync->fence = cur_fence; 401 + 402 + list_add_tail(&sig_sync->node, &ctx->signals); 403 + 404 + return 0; 405 + 406 + err_free_sig_sync: 407 + panthor_sync_signal_free(sig_sync); 408 + return ret; 409 + } 410 + 411 + /** 412 + * panthor_submit_ctx_search_sync_signal() - Search an existing signal operation in a 413 + * submit context. 414 + * @ctx: Context to search the signal operation in. 415 + * @handle: Syncobj handle. 416 + * @point: Syncobj point. 417 + * 418 + * Return: A valid panthor_sync_signal object if found, NULL otherwise. 419 + */ 420 + static struct panthor_sync_signal * 421 + panthor_submit_ctx_search_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point) 422 + { 423 + struct panthor_sync_signal *sig_sync; 424 + 425 + list_for_each_entry(sig_sync, &ctx->signals, node) { 426 + if (handle == sig_sync->handle && point == sig_sync->point) 427 + return sig_sync; 428 + } 429 + 430 + return NULL; 431 + } 432 + 433 + /** 434 + * panthor_submit_ctx_add_job() - Add a job to a submit context 435 + * @ctx: Context to search the signal operation in. 436 + * @idx: Index of the job in the context. 437 + * @job: Job to add. 438 + * @syncs: Sync operations provided by userspace. 439 + * 440 + * Return: 0 on success, a negative error code otherwise. 441 + */ 442 + static int 443 + panthor_submit_ctx_add_job(struct panthor_submit_ctx *ctx, u32 idx, 444 + struct drm_sched_job *job, 445 + const struct drm_panthor_obj_array *syncs) 446 + { 447 + int ret; 448 + 449 + ctx->jobs[idx].job = job; 450 + 451 + ret = PANTHOR_UOBJ_GET_ARRAY(ctx->jobs[idx].syncops, syncs); 452 + if (ret) 453 + return ret; 454 + 455 + ctx->jobs[idx].syncop_count = syncs->count; 456 + return 0; 457 + } 458 + 459 + /** 460 + * panthor_submit_ctx_get_sync_signal() - Search signal operation and add one if none was found. 461 + * @ctx: Context to search the signal operation in. 462 + * @handle: Syncobj handle. 463 + * @point: Syncobj point. 464 + * 465 + * Return: 0 on success, a negative error code otherwise. 466 + */ 467 + static int 468 + panthor_submit_ctx_get_sync_signal(struct panthor_submit_ctx *ctx, u32 handle, u64 point) 469 + { 470 + struct panthor_sync_signal *sig_sync; 471 + 472 + sig_sync = panthor_submit_ctx_search_sync_signal(ctx, handle, point); 473 + if (sig_sync) 474 + return 0; 475 + 476 + return panthor_submit_ctx_add_sync_signal(ctx, handle, point); 477 + } 478 + 479 + /** 480 + * panthor_submit_ctx_update_job_sync_signal_fences() - Update fences 481 + * on the signal operations specified by a job. 482 + * @ctx: Context to search the signal operation in. 483 + * @job_idx: Index of the job to operate on. 484 + * 485 + * Return: 0 on success, a negative error code otherwise. 486 + */ 487 + static int 488 + panthor_submit_ctx_update_job_sync_signal_fences(struct panthor_submit_ctx *ctx, 489 + u32 job_idx) 490 + { 491 + struct panthor_device *ptdev = container_of(ctx->file->minor->dev, 492 + struct panthor_device, 493 + base); 494 + struct dma_fence *done_fence = &ctx->jobs[job_idx].job->s_fence->finished; 495 + const struct drm_panthor_sync_op *sync_ops = ctx->jobs[job_idx].syncops; 496 + u32 sync_op_count = ctx->jobs[job_idx].syncop_count; 497 + 498 + for (u32 i = 0; i < sync_op_count; i++) { 499 + struct dma_fence *old_fence; 500 + struct panthor_sync_signal *sig_sync; 501 + 502 + if (!sync_op_is_signal(&sync_ops[i])) 503 + continue; 504 + 505 + sig_sync = panthor_submit_ctx_search_sync_signal(ctx, sync_ops[i].handle, 506 + sync_ops[i].timeline_value); 507 + if (drm_WARN_ON(&ptdev->base, !sig_sync)) 508 + return -EINVAL; 509 + 510 + old_fence = sig_sync->fence; 511 + sig_sync->fence = dma_fence_get(done_fence); 512 + dma_fence_put(old_fence); 513 + 514 + if (drm_WARN_ON(&ptdev->base, !sig_sync->fence)) 515 + return -EINVAL; 516 + } 517 + 518 + return 0; 519 + } 520 + 521 + /** 522 + * panthor_submit_ctx_collect_job_signal_ops() - Iterate over all job signal operations 523 + * and add them to the context. 524 + * @ctx: Context to search the signal operation in. 525 + * @job_idx: Index of the job to operate on. 526 + * 527 + * Return: 0 on success, a negative error code otherwise. 528 + */ 529 + static int 530 + panthor_submit_ctx_collect_job_signal_ops(struct panthor_submit_ctx *ctx, 531 + u32 job_idx) 532 + { 533 + const struct drm_panthor_sync_op *sync_ops = ctx->jobs[job_idx].syncops; 534 + u32 sync_op_count = ctx->jobs[job_idx].syncop_count; 535 + 536 + for (u32 i = 0; i < sync_op_count; i++) { 537 + int ret; 538 + 539 + if (!sync_op_is_signal(&sync_ops[i])) 540 + continue; 541 + 542 + ret = panthor_check_sync_op(&sync_ops[i]); 543 + if (ret) 544 + return ret; 545 + 546 + ret = panthor_submit_ctx_get_sync_signal(ctx, 547 + sync_ops[i].handle, 548 + sync_ops[i].timeline_value); 549 + if (ret) 550 + return ret; 551 + } 552 + 553 + return 0; 554 + } 555 + 556 + /** 557 + * panthor_submit_ctx_push_fences() - Iterate over the signal array, and for each entry, push 558 + * the currently assigned fence to the associated syncobj. 559 + * @ctx: Context to push fences on. 560 + * 561 + * This is the last step of a submission procedure, and is done once we know the submission 562 + * is effective and job fences are guaranteed to be signaled in finite time. 563 + */ 564 + static void 565 + panthor_submit_ctx_push_fences(struct panthor_submit_ctx *ctx) 566 + { 567 + struct panthor_sync_signal *sig_sync; 568 + 569 + list_for_each_entry(sig_sync, &ctx->signals, node) { 570 + if (sig_sync->chain) { 571 + drm_syncobj_add_point(sig_sync->syncobj, sig_sync->chain, 572 + sig_sync->fence, sig_sync->point); 573 + sig_sync->chain = NULL; 574 + } else { 575 + drm_syncobj_replace_fence(sig_sync->syncobj, sig_sync->fence); 576 + } 577 + } 578 + } 579 + 580 + /** 581 + * panthor_submit_ctx_add_sync_deps_to_job() - Add sync wait operations as 582 + * job dependencies. 583 + * @ctx: Submit context. 584 + * @job_idx: Index of the job to operate on. 585 + * 586 + * Return: 0 on success, a negative error code otherwise. 587 + */ 588 + static int 589 + panthor_submit_ctx_add_sync_deps_to_job(struct panthor_submit_ctx *ctx, 590 + u32 job_idx) 591 + { 592 + struct panthor_device *ptdev = container_of(ctx->file->minor->dev, 593 + struct panthor_device, 594 + base); 595 + const struct drm_panthor_sync_op *sync_ops = ctx->jobs[job_idx].syncops; 596 + struct drm_sched_job *job = ctx->jobs[job_idx].job; 597 + u32 sync_op_count = ctx->jobs[job_idx].syncop_count; 598 + int ret = 0; 599 + 600 + for (u32 i = 0; i < sync_op_count; i++) { 601 + struct panthor_sync_signal *sig_sync; 602 + struct dma_fence *fence; 603 + 604 + if (!sync_op_is_wait(&sync_ops[i])) 605 + continue; 606 + 607 + ret = panthor_check_sync_op(&sync_ops[i]); 608 + if (ret) 609 + return ret; 610 + 611 + sig_sync = panthor_submit_ctx_search_sync_signal(ctx, sync_ops[i].handle, 612 + sync_ops[i].timeline_value); 613 + if (sig_sync) { 614 + if (drm_WARN_ON(&ptdev->base, !sig_sync->fence)) 615 + return -EINVAL; 616 + 617 + fence = dma_fence_get(sig_sync->fence); 618 + } else { 619 + ret = drm_syncobj_find_fence(ctx->file, sync_ops[i].handle, 620 + sync_ops[i].timeline_value, 621 + 0, &fence); 622 + if (ret) 623 + return ret; 624 + } 625 + 626 + ret = drm_sched_job_add_dependency(job, fence); 627 + if (ret) 628 + return ret; 629 + } 630 + 631 + return 0; 632 + } 633 + 634 + /** 635 + * panthor_submit_ctx_collect_jobs_signal_ops() - Collect all signal operations 636 + * and add them to the submit context. 637 + * @ctx: Submit context. 638 + * 639 + * Return: 0 on success, a negative error code otherwise. 640 + */ 641 + static int 642 + panthor_submit_ctx_collect_jobs_signal_ops(struct panthor_submit_ctx *ctx) 643 + { 644 + for (u32 i = 0; i < ctx->job_count; i++) { 645 + int ret; 646 + 647 + ret = panthor_submit_ctx_collect_job_signal_ops(ctx, i); 648 + if (ret) 649 + return ret; 650 + } 651 + 652 + return 0; 653 + } 654 + 655 + /** 656 + * panthor_submit_ctx_add_deps_and_arm_jobs() - Add jobs dependencies and arm jobs 657 + * @ctx: Submit context. 658 + * 659 + * Must be called after the resv preparation has been taken care of. 660 + * 661 + * Return: 0 on success, a negative error code otherwise. 662 + */ 663 + static int 664 + panthor_submit_ctx_add_deps_and_arm_jobs(struct panthor_submit_ctx *ctx) 665 + { 666 + for (u32 i = 0; i < ctx->job_count; i++) { 667 + int ret; 668 + 669 + ret = panthor_submit_ctx_add_sync_deps_to_job(ctx, i); 670 + if (ret) 671 + return ret; 672 + 673 + drm_sched_job_arm(ctx->jobs[i].job); 674 + 675 + ret = panthor_submit_ctx_update_job_sync_signal_fences(ctx, i); 676 + if (ret) 677 + return ret; 678 + } 679 + 680 + return 0; 681 + } 682 + 683 + /** 684 + * panthor_submit_ctx_push_jobs() - Push jobs to their scheduling entities. 685 + * @ctx: Submit context. 686 + * @upd_resvs: Callback used to update reservation objects that were previously 687 + * preapred. 688 + */ 689 + static void 690 + panthor_submit_ctx_push_jobs(struct panthor_submit_ctx *ctx, 691 + void (*upd_resvs)(struct drm_exec *, struct drm_sched_job *)) 692 + { 693 + for (u32 i = 0; i < ctx->job_count; i++) { 694 + upd_resvs(&ctx->exec, ctx->jobs[i].job); 695 + drm_sched_entity_push_job(ctx->jobs[i].job); 696 + 697 + /* Job is owned by the scheduler now. */ 698 + ctx->jobs[i].job = NULL; 699 + } 700 + 701 + panthor_submit_ctx_push_fences(ctx); 702 + } 703 + 704 + /** 705 + * panthor_submit_ctx_init() - Initializes a submission context 706 + * @ctx: Submit context to initialize. 707 + * @file: drm_file this submission happens on. 708 + * @job_count: Number of jobs that will be submitted. 709 + * 710 + * Return: 0 on success, a negative error code otherwise. 711 + */ 712 + static int panthor_submit_ctx_init(struct panthor_submit_ctx *ctx, 713 + struct drm_file *file, u32 job_count) 714 + { 715 + ctx->jobs = kvmalloc_array(job_count, sizeof(*ctx->jobs), 716 + GFP_KERNEL | __GFP_ZERO); 717 + if (!ctx->jobs) 718 + return -ENOMEM; 719 + 720 + ctx->file = file; 721 + ctx->job_count = job_count; 722 + INIT_LIST_HEAD(&ctx->signals); 723 + drm_exec_init(&ctx->exec, 724 + DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES, 725 + 0); 726 + return 0; 727 + } 728 + 729 + /** 730 + * panthor_submit_ctx_cleanup() - Cleanup a submission context 731 + * @ctx: Submit context to cleanup. 732 + * @job_put: Job put callback. 733 + */ 734 + static void panthor_submit_ctx_cleanup(struct panthor_submit_ctx *ctx, 735 + void (*job_put)(struct drm_sched_job *)) 736 + { 737 + struct panthor_sync_signal *sig_sync, *tmp; 738 + unsigned long i; 739 + 740 + drm_exec_fini(&ctx->exec); 741 + 742 + list_for_each_entry_safe(sig_sync, tmp, &ctx->signals, node) 743 + panthor_sync_signal_free(sig_sync); 744 + 745 + for (i = 0; i < ctx->job_count; i++) { 746 + job_put(ctx->jobs[i].job); 747 + kvfree(ctx->jobs[i].syncops); 748 + } 749 + 750 + kvfree(ctx->jobs); 751 + } 752 + 753 + static int panthor_ioctl_dev_query(struct drm_device *ddev, void *data, struct drm_file *file) 754 + { 755 + struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); 756 + struct drm_panthor_dev_query *args = data; 757 + 758 + if (!args->pointer) { 759 + switch (args->type) { 760 + case DRM_PANTHOR_DEV_QUERY_GPU_INFO: 761 + args->size = sizeof(ptdev->gpu_info); 762 + return 0; 763 + 764 + case DRM_PANTHOR_DEV_QUERY_CSIF_INFO: 765 + args->size = sizeof(ptdev->csif_info); 766 + return 0; 767 + 768 + default: 769 + return -EINVAL; 770 + } 771 + } 772 + 773 + switch (args->type) { 774 + case DRM_PANTHOR_DEV_QUERY_GPU_INFO: 775 + return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->gpu_info); 776 + 777 + case DRM_PANTHOR_DEV_QUERY_CSIF_INFO: 778 + return PANTHOR_UOBJ_SET(args->pointer, args->size, ptdev->csif_info); 779 + 780 + default: 781 + return -EINVAL; 782 + } 783 + } 784 + 785 + #define PANTHOR_VM_CREATE_FLAGS 0 786 + 787 + static int panthor_ioctl_vm_create(struct drm_device *ddev, void *data, 788 + struct drm_file *file) 789 + { 790 + struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); 791 + struct panthor_file *pfile = file->driver_priv; 792 + struct drm_panthor_vm_create *args = data; 793 + int cookie, ret; 794 + 795 + if (!drm_dev_enter(ddev, &cookie)) 796 + return -ENODEV; 797 + 798 + ret = panthor_vm_pool_create_vm(ptdev, pfile->vms, args); 799 + if (ret >= 0) { 800 + args->id = ret; 801 + ret = 0; 802 + } 803 + 804 + drm_dev_exit(cookie); 805 + return ret; 806 + } 807 + 808 + static int panthor_ioctl_vm_destroy(struct drm_device *ddev, void *data, 809 + struct drm_file *file) 810 + { 811 + struct panthor_file *pfile = file->driver_priv; 812 + struct drm_panthor_vm_destroy *args = data; 813 + 814 + if (args->pad) 815 + return -EINVAL; 816 + 817 + return panthor_vm_pool_destroy_vm(pfile->vms, args->id); 818 + } 819 + 820 + #define PANTHOR_BO_FLAGS DRM_PANTHOR_BO_NO_MMAP 821 + 822 + static int panthor_ioctl_bo_create(struct drm_device *ddev, void *data, 823 + struct drm_file *file) 824 + { 825 + struct panthor_file *pfile = file->driver_priv; 826 + struct drm_panthor_bo_create *args = data; 827 + struct panthor_vm *vm = NULL; 828 + int cookie, ret; 829 + 830 + if (!drm_dev_enter(ddev, &cookie)) 831 + return -ENODEV; 832 + 833 + if (!args->size || args->pad || 834 + (args->flags & ~PANTHOR_BO_FLAGS)) { 835 + ret = -EINVAL; 836 + goto out_dev_exit; 837 + } 838 + 839 + if (args->exclusive_vm_id) { 840 + vm = panthor_vm_pool_get_vm(pfile->vms, args->exclusive_vm_id); 841 + if (!vm) { 842 + ret = -EINVAL; 843 + goto out_dev_exit; 844 + } 845 + } 846 + 847 + ret = panthor_gem_create_with_handle(file, ddev, vm, &args->size, 848 + args->flags, &args->handle); 849 + 850 + panthor_vm_put(vm); 851 + 852 + out_dev_exit: 853 + drm_dev_exit(cookie); 854 + return ret; 855 + } 856 + 857 + static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data, 858 + struct drm_file *file) 859 + { 860 + struct drm_panthor_bo_mmap_offset *args = data; 861 + struct drm_gem_object *obj; 862 + int ret; 863 + 864 + if (args->pad) 865 + return -EINVAL; 866 + 867 + obj = drm_gem_object_lookup(file, args->handle); 868 + if (!obj) 869 + return -ENOENT; 870 + 871 + ret = drm_gem_create_mmap_offset(obj); 872 + if (ret) 873 + goto out; 874 + 875 + args->offset = drm_vma_node_offset_addr(&obj->vma_node); 876 + 877 + out: 878 + drm_gem_object_put(obj); 879 + return ret; 880 + } 881 + 882 + static int panthor_ioctl_group_submit(struct drm_device *ddev, void *data, 883 + struct drm_file *file) 884 + { 885 + struct panthor_file *pfile = file->driver_priv; 886 + struct drm_panthor_group_submit *args = data; 887 + struct drm_panthor_queue_submit *jobs_args; 888 + struct panthor_submit_ctx ctx; 889 + int ret = 0, cookie; 890 + 891 + if (args->pad) 892 + return -EINVAL; 893 + 894 + if (!drm_dev_enter(ddev, &cookie)) 895 + return -ENODEV; 896 + 897 + ret = PANTHOR_UOBJ_GET_ARRAY(jobs_args, &args->queue_submits); 898 + if (ret) 899 + goto out_dev_exit; 900 + 901 + ret = panthor_submit_ctx_init(&ctx, file, args->queue_submits.count); 902 + if (ret) 903 + goto out_free_jobs_args; 904 + 905 + /* Create jobs and attach sync operations */ 906 + for (u32 i = 0; i < args->queue_submits.count; i++) { 907 + const struct drm_panthor_queue_submit *qsubmit = &jobs_args[i]; 908 + struct drm_sched_job *job; 909 + 910 + job = panthor_job_create(pfile, args->group_handle, qsubmit); 911 + if (IS_ERR(job)) { 912 + ret = PTR_ERR(job); 913 + goto out_cleanup_submit_ctx; 914 + } 915 + 916 + ret = panthor_submit_ctx_add_job(&ctx, i, job, &qsubmit->syncs); 917 + if (ret) 918 + goto out_cleanup_submit_ctx; 919 + } 920 + 921 + /* 922 + * Collect signal operations on all jobs, such that each job can pick 923 + * from it for its dependencies and update the fence to signal when the 924 + * job is submitted. 925 + */ 926 + ret = panthor_submit_ctx_collect_jobs_signal_ops(&ctx); 927 + if (ret) 928 + goto out_cleanup_submit_ctx; 929 + 930 + /* 931 + * We acquire/prepare revs on all jobs before proceeding with the 932 + * dependency registration. 933 + * 934 + * This is solving two problems: 935 + * 1. drm_sched_job_arm() and drm_sched_entity_push_job() must be 936 + * protected by a lock to make sure no concurrent access to the same 937 + * entity get interleaved, which would mess up with the fence seqno 938 + * ordering. Luckily, one of the resv being acquired is the VM resv, 939 + * and a scheduling entity is only bound to a single VM. As soon as 940 + * we acquire the VM resv, we should be safe. 941 + * 2. Jobs might depend on fences that were issued by previous jobs in 942 + * the same batch, so we can't add dependencies on all jobs before 943 + * arming previous jobs and registering the fence to the signal 944 + * array, otherwise we might miss dependencies, or point to an 945 + * outdated fence. 946 + */ 947 + if (args->queue_submits.count > 0) { 948 + /* All jobs target the same group, so they also point to the same VM. */ 949 + struct panthor_vm *vm = panthor_job_vm(ctx.jobs[0].job); 950 + 951 + drm_exec_until_all_locked(&ctx.exec) { 952 + ret = panthor_vm_prepare_mapped_bos_resvs(&ctx.exec, vm, 953 + args->queue_submits.count); 954 + } 955 + 956 + if (ret) 957 + goto out_cleanup_submit_ctx; 958 + } 959 + 960 + /* 961 + * Now that resvs are locked/prepared, we can iterate over each job to 962 + * add the dependencies, arm the job fence, register the job fence to 963 + * the signal array. 964 + */ 965 + ret = panthor_submit_ctx_add_deps_and_arm_jobs(&ctx); 966 + if (ret) 967 + goto out_cleanup_submit_ctx; 968 + 969 + /* Nothing can fail after that point, so we can make our job fences 970 + * visible to the outside world. Push jobs and set the job fences to 971 + * the resv slots we reserved. This also pushes the fences to the 972 + * syncobjs that are part of the signal array. 973 + */ 974 + panthor_submit_ctx_push_jobs(&ctx, panthor_job_update_resvs); 975 + 976 + out_cleanup_submit_ctx: 977 + panthor_submit_ctx_cleanup(&ctx, panthor_job_put); 978 + 979 + out_free_jobs_args: 980 + kvfree(jobs_args); 981 + 982 + out_dev_exit: 983 + drm_dev_exit(cookie); 984 + return ret; 985 + } 986 + 987 + static int panthor_ioctl_group_destroy(struct drm_device *ddev, void *data, 988 + struct drm_file *file) 989 + { 990 + struct panthor_file *pfile = file->driver_priv; 991 + struct drm_panthor_group_destroy *args = data; 992 + 993 + if (args->pad) 994 + return -EINVAL; 995 + 996 + return panthor_group_destroy(pfile, args->group_handle); 997 + } 998 + 999 + static int panthor_ioctl_group_create(struct drm_device *ddev, void *data, 1000 + struct drm_file *file) 1001 + { 1002 + struct panthor_file *pfile = file->driver_priv; 1003 + struct drm_panthor_group_create *args = data; 1004 + struct drm_panthor_queue_create *queue_args; 1005 + int ret; 1006 + 1007 + if (!args->queues.count) 1008 + return -EINVAL; 1009 + 1010 + ret = PANTHOR_UOBJ_GET_ARRAY(queue_args, &args->queues); 1011 + if (ret) 1012 + return ret; 1013 + 1014 + ret = panthor_group_create(pfile, args, queue_args); 1015 + if (ret >= 0) { 1016 + args->group_handle = ret; 1017 + ret = 0; 1018 + } 1019 + 1020 + kvfree(queue_args); 1021 + return ret; 1022 + } 1023 + 1024 + static int panthor_ioctl_group_get_state(struct drm_device *ddev, void *data, 1025 + struct drm_file *file) 1026 + { 1027 + struct panthor_file *pfile = file->driver_priv; 1028 + struct drm_panthor_group_get_state *args = data; 1029 + 1030 + return panthor_group_get_state(pfile, args); 1031 + } 1032 + 1033 + static int panthor_ioctl_tiler_heap_create(struct drm_device *ddev, void *data, 1034 + struct drm_file *file) 1035 + { 1036 + struct panthor_file *pfile = file->driver_priv; 1037 + struct drm_panthor_tiler_heap_create *args = data; 1038 + struct panthor_heap_pool *pool; 1039 + struct panthor_vm *vm; 1040 + int ret; 1041 + 1042 + vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id); 1043 + if (!vm) 1044 + return -EINVAL; 1045 + 1046 + pool = panthor_vm_get_heap_pool(vm, true); 1047 + if (IS_ERR(pool)) { 1048 + ret = PTR_ERR(pool); 1049 + goto out_put_vm; 1050 + } 1051 + 1052 + ret = panthor_heap_create(pool, 1053 + args->initial_chunk_count, 1054 + args->chunk_size, 1055 + args->max_chunks, 1056 + args->target_in_flight, 1057 + &args->tiler_heap_ctx_gpu_va, 1058 + &args->first_heap_chunk_gpu_va); 1059 + if (ret < 0) 1060 + goto out_put_heap_pool; 1061 + 1062 + /* Heap pools are per-VM. We combine the VM and HEAP id to make 1063 + * a unique heap handle. 1064 + */ 1065 + args->handle = (args->vm_id << 16) | ret; 1066 + ret = 0; 1067 + 1068 + out_put_heap_pool: 1069 + panthor_heap_pool_put(pool); 1070 + 1071 + out_put_vm: 1072 + panthor_vm_put(vm); 1073 + return ret; 1074 + } 1075 + 1076 + static int panthor_ioctl_tiler_heap_destroy(struct drm_device *ddev, void *data, 1077 + struct drm_file *file) 1078 + { 1079 + struct panthor_file *pfile = file->driver_priv; 1080 + struct drm_panthor_tiler_heap_destroy *args = data; 1081 + struct panthor_heap_pool *pool; 1082 + struct panthor_vm *vm; 1083 + int ret; 1084 + 1085 + if (args->pad) 1086 + return -EINVAL; 1087 + 1088 + vm = panthor_vm_pool_get_vm(pfile->vms, args->handle >> 16); 1089 + if (!vm) 1090 + return -EINVAL; 1091 + 1092 + pool = panthor_vm_get_heap_pool(vm, false); 1093 + if (!pool) { 1094 + ret = -EINVAL; 1095 + goto out_put_vm; 1096 + } 1097 + 1098 + ret = panthor_heap_destroy(pool, args->handle & GENMASK(15, 0)); 1099 + panthor_heap_pool_put(pool); 1100 + 1101 + out_put_vm: 1102 + panthor_vm_put(vm); 1103 + return ret; 1104 + } 1105 + 1106 + static int panthor_ioctl_vm_bind_async(struct drm_device *ddev, 1107 + struct drm_panthor_vm_bind *args, 1108 + struct drm_file *file) 1109 + { 1110 + struct panthor_file *pfile = file->driver_priv; 1111 + struct drm_panthor_vm_bind_op *jobs_args; 1112 + struct panthor_submit_ctx ctx; 1113 + struct panthor_vm *vm; 1114 + int ret = 0; 1115 + 1116 + vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id); 1117 + if (!vm) 1118 + return -EINVAL; 1119 + 1120 + ret = PANTHOR_UOBJ_GET_ARRAY(jobs_args, &args->ops); 1121 + if (ret) 1122 + goto out_put_vm; 1123 + 1124 + ret = panthor_submit_ctx_init(&ctx, file, args->ops.count); 1125 + if (ret) 1126 + goto out_free_jobs_args; 1127 + 1128 + for (u32 i = 0; i < args->ops.count; i++) { 1129 + struct drm_panthor_vm_bind_op *op = &jobs_args[i]; 1130 + struct drm_sched_job *job; 1131 + 1132 + job = panthor_vm_bind_job_create(file, vm, op); 1133 + if (IS_ERR(job)) { 1134 + ret = PTR_ERR(job); 1135 + goto out_cleanup_submit_ctx; 1136 + } 1137 + 1138 + ret = panthor_submit_ctx_add_job(&ctx, i, job, &op->syncs); 1139 + if (ret) 1140 + goto out_cleanup_submit_ctx; 1141 + } 1142 + 1143 + ret = panthor_submit_ctx_collect_jobs_signal_ops(&ctx); 1144 + if (ret) 1145 + goto out_cleanup_submit_ctx; 1146 + 1147 + /* Prepare reservation objects for each VM_BIND job. */ 1148 + drm_exec_until_all_locked(&ctx.exec) { 1149 + for (u32 i = 0; i < ctx.job_count; i++) { 1150 + ret = panthor_vm_bind_job_prepare_resvs(&ctx.exec, ctx.jobs[i].job); 1151 + drm_exec_retry_on_contention(&ctx.exec); 1152 + if (ret) 1153 + goto out_cleanup_submit_ctx; 1154 + } 1155 + } 1156 + 1157 + ret = panthor_submit_ctx_add_deps_and_arm_jobs(&ctx); 1158 + if (ret) 1159 + goto out_cleanup_submit_ctx; 1160 + 1161 + /* Nothing can fail after that point. */ 1162 + panthor_submit_ctx_push_jobs(&ctx, panthor_vm_bind_job_update_resvs); 1163 + 1164 + out_cleanup_submit_ctx: 1165 + panthor_submit_ctx_cleanup(&ctx, panthor_vm_bind_job_put); 1166 + 1167 + out_free_jobs_args: 1168 + kvfree(jobs_args); 1169 + 1170 + out_put_vm: 1171 + panthor_vm_put(vm); 1172 + return ret; 1173 + } 1174 + 1175 + static int panthor_ioctl_vm_bind_sync(struct drm_device *ddev, 1176 + struct drm_panthor_vm_bind *args, 1177 + struct drm_file *file) 1178 + { 1179 + struct panthor_file *pfile = file->driver_priv; 1180 + struct drm_panthor_vm_bind_op *jobs_args; 1181 + struct panthor_vm *vm; 1182 + int ret; 1183 + 1184 + vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id); 1185 + if (!vm) 1186 + return -EINVAL; 1187 + 1188 + ret = PANTHOR_UOBJ_GET_ARRAY(jobs_args, &args->ops); 1189 + if (ret) 1190 + goto out_put_vm; 1191 + 1192 + for (u32 i = 0; i < args->ops.count; i++) { 1193 + ret = panthor_vm_bind_exec_sync_op(file, vm, &jobs_args[i]); 1194 + if (ret) { 1195 + /* Update ops.count so the user knows where things failed. */ 1196 + args->ops.count = i; 1197 + break; 1198 + } 1199 + } 1200 + 1201 + kvfree(jobs_args); 1202 + 1203 + out_put_vm: 1204 + panthor_vm_put(vm); 1205 + return ret; 1206 + } 1207 + 1208 + #define PANTHOR_VM_BIND_FLAGS DRM_PANTHOR_VM_BIND_ASYNC 1209 + 1210 + static int panthor_ioctl_vm_bind(struct drm_device *ddev, void *data, 1211 + struct drm_file *file) 1212 + { 1213 + struct drm_panthor_vm_bind *args = data; 1214 + int cookie, ret; 1215 + 1216 + if (!drm_dev_enter(ddev, &cookie)) 1217 + return -ENODEV; 1218 + 1219 + if (args->flags & DRM_PANTHOR_VM_BIND_ASYNC) 1220 + ret = panthor_ioctl_vm_bind_async(ddev, args, file); 1221 + else 1222 + ret = panthor_ioctl_vm_bind_sync(ddev, args, file); 1223 + 1224 + drm_dev_exit(cookie); 1225 + return ret; 1226 + } 1227 + 1228 + static int panthor_ioctl_vm_get_state(struct drm_device *ddev, void *data, 1229 + struct drm_file *file) 1230 + { 1231 + struct panthor_file *pfile = file->driver_priv; 1232 + struct drm_panthor_vm_get_state *args = data; 1233 + struct panthor_vm *vm; 1234 + 1235 + vm = panthor_vm_pool_get_vm(pfile->vms, args->vm_id); 1236 + if (!vm) 1237 + return -EINVAL; 1238 + 1239 + if (panthor_vm_is_unusable(vm)) 1240 + args->state = DRM_PANTHOR_VM_STATE_UNUSABLE; 1241 + else 1242 + args->state = DRM_PANTHOR_VM_STATE_USABLE; 1243 + 1244 + panthor_vm_put(vm); 1245 + return 0; 1246 + } 1247 + 1248 + static int 1249 + panthor_open(struct drm_device *ddev, struct drm_file *file) 1250 + { 1251 + struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); 1252 + struct panthor_file *pfile; 1253 + int ret; 1254 + 1255 + if (!try_module_get(THIS_MODULE)) 1256 + return -EINVAL; 1257 + 1258 + pfile = kzalloc(sizeof(*pfile), GFP_KERNEL); 1259 + if (!pfile) { 1260 + ret = -ENOMEM; 1261 + goto err_put_mod; 1262 + } 1263 + 1264 + pfile->ptdev = ptdev; 1265 + 1266 + ret = panthor_vm_pool_create(pfile); 1267 + if (ret) 1268 + goto err_free_file; 1269 + 1270 + ret = panthor_group_pool_create(pfile); 1271 + if (ret) 1272 + goto err_destroy_vm_pool; 1273 + 1274 + file->driver_priv = pfile; 1275 + return 0; 1276 + 1277 + err_destroy_vm_pool: 1278 + panthor_vm_pool_destroy(pfile); 1279 + 1280 + err_free_file: 1281 + kfree(pfile); 1282 + 1283 + err_put_mod: 1284 + module_put(THIS_MODULE); 1285 + return ret; 1286 + } 1287 + 1288 + static void 1289 + panthor_postclose(struct drm_device *ddev, struct drm_file *file) 1290 + { 1291 + struct panthor_file *pfile = file->driver_priv; 1292 + 1293 + panthor_group_pool_destroy(pfile); 1294 + panthor_vm_pool_destroy(pfile); 1295 + 1296 + kfree(pfile); 1297 + module_put(THIS_MODULE); 1298 + } 1299 + 1300 + static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = { 1301 + #define PANTHOR_IOCTL(n, func, flags) \ 1302 + DRM_IOCTL_DEF_DRV(PANTHOR_##n, panthor_ioctl_##func, flags) 1303 + 1304 + PANTHOR_IOCTL(DEV_QUERY, dev_query, DRM_RENDER_ALLOW), 1305 + PANTHOR_IOCTL(VM_CREATE, vm_create, DRM_RENDER_ALLOW), 1306 + PANTHOR_IOCTL(VM_DESTROY, vm_destroy, DRM_RENDER_ALLOW), 1307 + PANTHOR_IOCTL(VM_BIND, vm_bind, DRM_RENDER_ALLOW), 1308 + PANTHOR_IOCTL(VM_GET_STATE, vm_get_state, DRM_RENDER_ALLOW), 1309 + PANTHOR_IOCTL(BO_CREATE, bo_create, DRM_RENDER_ALLOW), 1310 + PANTHOR_IOCTL(BO_MMAP_OFFSET, bo_mmap_offset, DRM_RENDER_ALLOW), 1311 + PANTHOR_IOCTL(GROUP_CREATE, group_create, DRM_RENDER_ALLOW), 1312 + PANTHOR_IOCTL(GROUP_DESTROY, group_destroy, DRM_RENDER_ALLOW), 1313 + PANTHOR_IOCTL(GROUP_GET_STATE, group_get_state, DRM_RENDER_ALLOW), 1314 + PANTHOR_IOCTL(TILER_HEAP_CREATE, tiler_heap_create, DRM_RENDER_ALLOW), 1315 + PANTHOR_IOCTL(TILER_HEAP_DESTROY, tiler_heap_destroy, DRM_RENDER_ALLOW), 1316 + PANTHOR_IOCTL(GROUP_SUBMIT, group_submit, DRM_RENDER_ALLOW), 1317 + }; 1318 + 1319 + static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) 1320 + { 1321 + struct drm_file *file = filp->private_data; 1322 + struct panthor_file *pfile = file->driver_priv; 1323 + struct panthor_device *ptdev = pfile->ptdev; 1324 + u64 offset = (u64)vma->vm_pgoff << PAGE_SHIFT; 1325 + int ret, cookie; 1326 + 1327 + if (!drm_dev_enter(file->minor->dev, &cookie)) 1328 + return -ENODEV; 1329 + 1330 + if (panthor_device_mmio_offset(offset) >= DRM_PANTHOR_USER_MMIO_OFFSET) 1331 + ret = panthor_device_mmap_io(ptdev, vma); 1332 + else 1333 + ret = drm_gem_mmap(filp, vma); 1334 + 1335 + drm_dev_exit(cookie); 1336 + return ret; 1337 + } 1338 + 1339 + static const struct file_operations panthor_drm_driver_fops = { 1340 + .open = drm_open, 1341 + .release = drm_release, 1342 + .unlocked_ioctl = drm_ioctl, 1343 + .compat_ioctl = drm_compat_ioctl, 1344 + .poll = drm_poll, 1345 + .read = drm_read, 1346 + .llseek = noop_llseek, 1347 + .mmap = panthor_mmap, 1348 + }; 1349 + 1350 + #ifdef CONFIG_DEBUG_FS 1351 + static void panthor_debugfs_init(struct drm_minor *minor) 1352 + { 1353 + panthor_mmu_debugfs_init(minor); 1354 + } 1355 + #endif 1356 + 1357 + /* 1358 + * PanCSF driver version: 1359 + * - 1.0 - initial interface 1360 + */ 1361 + static const struct drm_driver panthor_drm_driver = { 1362 + .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | 1363 + DRIVER_SYNCOBJ_TIMELINE | DRIVER_GEM_GPUVA, 1364 + .open = panthor_open, 1365 + .postclose = panthor_postclose, 1366 + .ioctls = panthor_drm_driver_ioctls, 1367 + .num_ioctls = ARRAY_SIZE(panthor_drm_driver_ioctls), 1368 + .fops = &panthor_drm_driver_fops, 1369 + .name = "panthor", 1370 + .desc = "Panthor DRM driver", 1371 + .date = "20230801", 1372 + .major = 1, 1373 + .minor = 0, 1374 + 1375 + .gem_create_object = panthor_gem_create_object, 1376 + .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, 1377 + #ifdef CONFIG_DEBUG_FS 1378 + .debugfs_init = panthor_debugfs_init, 1379 + #endif 1380 + }; 1381 + 1382 + static int panthor_probe(struct platform_device *pdev) 1383 + { 1384 + struct panthor_device *ptdev; 1385 + 1386 + ptdev = devm_drm_dev_alloc(&pdev->dev, &panthor_drm_driver, 1387 + struct panthor_device, base); 1388 + if (!ptdev) 1389 + return -ENOMEM; 1390 + 1391 + platform_set_drvdata(pdev, ptdev); 1392 + 1393 + return panthor_device_init(ptdev); 1394 + } 1395 + 1396 + static void panthor_remove(struct platform_device *pdev) 1397 + { 1398 + struct panthor_device *ptdev = platform_get_drvdata(pdev); 1399 + 1400 + panthor_device_unplug(ptdev); 1401 + } 1402 + 1403 + static const struct of_device_id dt_match[] = { 1404 + { .compatible = "rockchip,rk3588-mali" }, 1405 + { .compatible = "arm,mali-valhall-csf" }, 1406 + {} 1407 + }; 1408 + MODULE_DEVICE_TABLE(of, dt_match); 1409 + 1410 + static DEFINE_RUNTIME_DEV_PM_OPS(panthor_pm_ops, 1411 + panthor_device_suspend, 1412 + panthor_device_resume, 1413 + NULL); 1414 + 1415 + static struct platform_driver panthor_driver = { 1416 + .probe = panthor_probe, 1417 + .remove_new = panthor_remove, 1418 + .driver = { 1419 + .name = "panthor", 1420 + .pm = pm_ptr(&panthor_pm_ops), 1421 + .of_match_table = dt_match, 1422 + }, 1423 + }; 1424 + 1425 + /* 1426 + * Workqueue used to cleanup stuff. 1427 + * 1428 + * We create a dedicated workqueue so we can drain on unplug and 1429 + * make sure all resources are freed before the module is unloaded. 1430 + */ 1431 + struct workqueue_struct *panthor_cleanup_wq; 1432 + 1433 + static int __init panthor_init(void) 1434 + { 1435 + int ret; 1436 + 1437 + ret = panthor_mmu_pt_cache_init(); 1438 + if (ret) 1439 + return ret; 1440 + 1441 + panthor_cleanup_wq = alloc_workqueue("panthor-cleanup", WQ_UNBOUND, 0); 1442 + if (!panthor_cleanup_wq) { 1443 + pr_err("panthor: Failed to allocate the workqueues"); 1444 + ret = -ENOMEM; 1445 + goto err_mmu_pt_cache_fini; 1446 + } 1447 + 1448 + ret = platform_driver_register(&panthor_driver); 1449 + if (ret) 1450 + goto err_destroy_cleanup_wq; 1451 + 1452 + return 0; 1453 + 1454 + err_destroy_cleanup_wq: 1455 + destroy_workqueue(panthor_cleanup_wq); 1456 + 1457 + err_mmu_pt_cache_fini: 1458 + panthor_mmu_pt_cache_fini(); 1459 + return ret; 1460 + } 1461 + module_init(panthor_init); 1462 + 1463 + static void __exit panthor_exit(void) 1464 + { 1465 + platform_driver_unregister(&panthor_driver); 1466 + destroy_workqueue(panthor_cleanup_wq); 1467 + panthor_mmu_pt_cache_fini(); 1468 + } 1469 + module_exit(panthor_exit); 1470 + 1471 + MODULE_AUTHOR("Panthor Project Developers"); 1472 + MODULE_DESCRIPTION("Panthor DRM Driver"); 1473 + MODULE_LICENSE("Dual MIT/GPL");
+1362
drivers/gpu/drm/panthor/panthor_fw.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2023 Collabora ltd. */ 3 + 4 + #ifdef CONFIG_ARM_ARCH_TIMER 5 + #include <asm/arch_timer.h> 6 + #endif 7 + 8 + #include <linux/clk.h> 9 + #include <linux/dma-mapping.h> 10 + #include <linux/firmware.h> 11 + #include <linux/iopoll.h> 12 + #include <linux/iosys-map.h> 13 + #include <linux/mutex.h> 14 + #include <linux/platform_device.h> 15 + 16 + #include <drm/drm_drv.h> 17 + #include <drm/drm_managed.h> 18 + 19 + #include "panthor_device.h" 20 + #include "panthor_fw.h" 21 + #include "panthor_gem.h" 22 + #include "panthor_gpu.h" 23 + #include "panthor_mmu.h" 24 + #include "panthor_regs.h" 25 + #include "panthor_sched.h" 26 + 27 + #define CSF_FW_NAME "mali_csffw.bin" 28 + 29 + #define PING_INTERVAL_MS 12000 30 + #define PROGRESS_TIMEOUT_CYCLES (5ull * 500 * 1024 * 1024) 31 + #define PROGRESS_TIMEOUT_SCALE_SHIFT 10 32 + #define IDLE_HYSTERESIS_US 800 33 + #define PWROFF_HYSTERESIS_US 10000 34 + 35 + /** 36 + * struct panthor_fw_binary_hdr - Firmware binary header. 37 + */ 38 + struct panthor_fw_binary_hdr { 39 + /** @magic: Magic value to check binary validity. */ 40 + u32 magic; 41 + #define CSF_FW_BINARY_HEADER_MAGIC 0xc3f13a6e 42 + 43 + /** @minor: Minor FW version. */ 44 + u8 minor; 45 + 46 + /** @major: Major FW version. */ 47 + u8 major; 48 + #define CSF_FW_BINARY_HEADER_MAJOR_MAX 0 49 + 50 + /** @padding1: MBZ. */ 51 + u16 padding1; 52 + 53 + /** @version_hash: FW version hash. */ 54 + u32 version_hash; 55 + 56 + /** @padding2: MBZ. */ 57 + u32 padding2; 58 + 59 + /** @size: FW binary size. */ 60 + u32 size; 61 + }; 62 + 63 + /** 64 + * enum panthor_fw_binary_entry_type - Firmware binary entry type 65 + */ 66 + enum panthor_fw_binary_entry_type { 67 + /** @CSF_FW_BINARY_ENTRY_TYPE_IFACE: Host <-> FW interface. */ 68 + CSF_FW_BINARY_ENTRY_TYPE_IFACE = 0, 69 + 70 + /** @CSF_FW_BINARY_ENTRY_TYPE_CONFIG: FW config. */ 71 + CSF_FW_BINARY_ENTRY_TYPE_CONFIG = 1, 72 + 73 + /** @CSF_FW_BINARY_ENTRY_TYPE_FUTF_TEST: Unit-tests. */ 74 + CSF_FW_BINARY_ENTRY_TYPE_FUTF_TEST = 2, 75 + 76 + /** @CSF_FW_BINARY_ENTRY_TYPE_TRACE_BUFFER: Trace buffer interface. */ 77 + CSF_FW_BINARY_ENTRY_TYPE_TRACE_BUFFER = 3, 78 + 79 + /** @CSF_FW_BINARY_ENTRY_TYPE_TIMELINE_METADATA: Timeline metadata interface. */ 80 + CSF_FW_BINARY_ENTRY_TYPE_TIMELINE_METADATA = 4, 81 + }; 82 + 83 + #define CSF_FW_BINARY_ENTRY_TYPE(ehdr) ((ehdr) & 0xff) 84 + #define CSF_FW_BINARY_ENTRY_SIZE(ehdr) (((ehdr) >> 8) & 0xff) 85 + #define CSF_FW_BINARY_ENTRY_UPDATE BIT(30) 86 + #define CSF_FW_BINARY_ENTRY_OPTIONAL BIT(31) 87 + 88 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_RD BIT(0) 89 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_WR BIT(1) 90 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_EX BIT(2) 91 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_NONE (0 << 3) 92 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_CACHED (1 << 3) 93 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_UNCACHED_COHERENT (2 << 3) 94 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_CACHED_COHERENT (3 << 3) 95 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_MASK GENMASK(4, 3) 96 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_PROT BIT(5) 97 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_SHARED BIT(30) 98 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_ZERO BIT(31) 99 + 100 + #define CSF_FW_BINARY_IFACE_ENTRY_RD_SUPPORTED_FLAGS \ 101 + (CSF_FW_BINARY_IFACE_ENTRY_RD_RD | \ 102 + CSF_FW_BINARY_IFACE_ENTRY_RD_WR | \ 103 + CSF_FW_BINARY_IFACE_ENTRY_RD_EX | \ 104 + CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_MASK | \ 105 + CSF_FW_BINARY_IFACE_ENTRY_RD_PROT | \ 106 + CSF_FW_BINARY_IFACE_ENTRY_RD_SHARED | \ 107 + CSF_FW_BINARY_IFACE_ENTRY_RD_ZERO) 108 + 109 + /** 110 + * struct panthor_fw_binary_section_entry_hdr - Describes a section of FW binary 111 + */ 112 + struct panthor_fw_binary_section_entry_hdr { 113 + /** @flags: Section flags. */ 114 + u32 flags; 115 + 116 + /** @va: MCU virtual range to map this binary section to. */ 117 + struct { 118 + /** @start: Start address. */ 119 + u32 start; 120 + 121 + /** @end: End address. */ 122 + u32 end; 123 + } va; 124 + 125 + /** @data: Data to initialize the FW section with. */ 126 + struct { 127 + /** @start: Start offset in the FW binary. */ 128 + u32 start; 129 + 130 + /** @end: End offset in the FW binary. */ 131 + u32 end; 132 + } data; 133 + }; 134 + 135 + /** 136 + * struct panthor_fw_binary_iter - Firmware binary iterator 137 + * 138 + * Used to parse a firmware binary. 139 + */ 140 + struct panthor_fw_binary_iter { 141 + /** @data: FW binary data. */ 142 + const void *data; 143 + 144 + /** @size: FW binary size. */ 145 + size_t size; 146 + 147 + /** @offset: Iterator offset. */ 148 + size_t offset; 149 + }; 150 + 151 + /** 152 + * struct panthor_fw_section - FW section 153 + */ 154 + struct panthor_fw_section { 155 + /** @node: Used to keep track of FW sections. */ 156 + struct list_head node; 157 + 158 + /** @flags: Section flags, as encoded in the FW binary. */ 159 + u32 flags; 160 + 161 + /** @mem: Section memory. */ 162 + struct panthor_kernel_bo *mem; 163 + 164 + /** 165 + * @name: Name of the section, as specified in the binary. 166 + * 167 + * Can be NULL. 168 + */ 169 + const char *name; 170 + 171 + /** 172 + * @data: Initial data copied to the FW memory. 173 + * 174 + * We keep data around so we can reload sections after a reset. 175 + */ 176 + struct { 177 + /** @buf: Buffed used to store init data. */ 178 + const void *buf; 179 + 180 + /** @size: Size of @buf in bytes. */ 181 + size_t size; 182 + } data; 183 + }; 184 + 185 + #define CSF_MCU_SHARED_REGION_START 0x04000000ULL 186 + #define CSF_MCU_SHARED_REGION_SIZE 0x04000000ULL 187 + 188 + #define MIN_CS_PER_CSG 8 189 + #define MIN_CSGS 3 190 + #define MAX_CSG_PRIO 0xf 191 + 192 + #define CSF_IFACE_VERSION(major, minor, patch) \ 193 + (((major) << 24) | ((minor) << 16) | (patch)) 194 + #define CSF_IFACE_VERSION_MAJOR(v) ((v) >> 24) 195 + #define CSF_IFACE_VERSION_MINOR(v) (((v) >> 16) & 0xff) 196 + #define CSF_IFACE_VERSION_PATCH(v) ((v) & 0xffff) 197 + 198 + #define CSF_GROUP_CONTROL_OFFSET 0x1000 199 + #define CSF_STREAM_CONTROL_OFFSET 0x40 200 + #define CSF_UNPRESERVED_REG_COUNT 4 201 + 202 + /** 203 + * struct panthor_fw_iface - FW interfaces 204 + */ 205 + struct panthor_fw_iface { 206 + /** @global: Global interface. */ 207 + struct panthor_fw_global_iface global; 208 + 209 + /** @groups: Group slot interfaces. */ 210 + struct panthor_fw_csg_iface groups[MAX_CSGS]; 211 + 212 + /** @streams: Command stream slot interfaces. */ 213 + struct panthor_fw_cs_iface streams[MAX_CSGS][MAX_CS_PER_CSG]; 214 + }; 215 + 216 + /** 217 + * struct panthor_fw - Firmware management 218 + */ 219 + struct panthor_fw { 220 + /** @vm: MCU VM. */ 221 + struct panthor_vm *vm; 222 + 223 + /** @sections: List of FW sections. */ 224 + struct list_head sections; 225 + 226 + /** @shared_section: The section containing the FW interfaces. */ 227 + struct panthor_fw_section *shared_section; 228 + 229 + /** @iface: FW interfaces. */ 230 + struct panthor_fw_iface iface; 231 + 232 + /** @watchdog: Collection of fields relating to the FW watchdog. */ 233 + struct { 234 + /** @ping_work: Delayed work used to ping the FW. */ 235 + struct delayed_work ping_work; 236 + } watchdog; 237 + 238 + /** 239 + * @req_waitqueue: FW request waitqueue. 240 + * 241 + * Everytime a request is sent to a command stream group or the global 242 + * interface, the caller will first busy wait for the request to be 243 + * acknowledged, and then fallback to a sleeping wait. 244 + * 245 + * This wait queue is here to support the sleeping wait flavor. 246 + */ 247 + wait_queue_head_t req_waitqueue; 248 + 249 + /** @booted: True is the FW is booted */ 250 + bool booted; 251 + 252 + /** 253 + * @fast_reset: True if the post_reset logic can proceed with a fast reset. 254 + * 255 + * A fast reset is just a reset where the driver doesn't reload the FW sections. 256 + * 257 + * Any time the firmware is properly suspended, a fast reset can take place. 258 + * On the other hand, if the halt operation failed, the driver will reload 259 + * all sections to make sure we start from a fresh state. 260 + */ 261 + bool fast_reset; 262 + 263 + /** @irq: Job irq data. */ 264 + struct panthor_irq irq; 265 + }; 266 + 267 + struct panthor_vm *panthor_fw_vm(struct panthor_device *ptdev) 268 + { 269 + return ptdev->fw->vm; 270 + } 271 + 272 + /** 273 + * panthor_fw_get_glb_iface() - Get the global interface 274 + * @ptdev: Device. 275 + * 276 + * Return: The global interface. 277 + */ 278 + struct panthor_fw_global_iface * 279 + panthor_fw_get_glb_iface(struct panthor_device *ptdev) 280 + { 281 + return &ptdev->fw->iface.global; 282 + } 283 + 284 + /** 285 + * panthor_fw_get_csg_iface() - Get a command stream group slot interface 286 + * @ptdev: Device. 287 + * @csg_slot: Index of the command stream group slot. 288 + * 289 + * Return: The command stream group slot interface. 290 + */ 291 + struct panthor_fw_csg_iface * 292 + panthor_fw_get_csg_iface(struct panthor_device *ptdev, u32 csg_slot) 293 + { 294 + if (drm_WARN_ON(&ptdev->base, csg_slot >= MAX_CSGS)) 295 + return NULL; 296 + 297 + return &ptdev->fw->iface.groups[csg_slot]; 298 + } 299 + 300 + /** 301 + * panthor_fw_get_cs_iface() - Get a command stream slot interface 302 + * @ptdev: Device. 303 + * @csg_slot: Index of the command stream group slot. 304 + * @cs_slot: Index of the command stream slot. 305 + * 306 + * Return: The command stream slot interface. 307 + */ 308 + struct panthor_fw_cs_iface * 309 + panthor_fw_get_cs_iface(struct panthor_device *ptdev, u32 csg_slot, u32 cs_slot) 310 + { 311 + if (drm_WARN_ON(&ptdev->base, csg_slot >= MAX_CSGS || cs_slot > MAX_CS_PER_CSG)) 312 + return NULL; 313 + 314 + return &ptdev->fw->iface.streams[csg_slot][cs_slot]; 315 + } 316 + 317 + /** 318 + * panthor_fw_conv_timeout() - Convert a timeout into a cycle-count 319 + * @ptdev: Device. 320 + * @timeout_us: Timeout expressed in micro-seconds. 321 + * 322 + * The FW has two timer sources: the GPU counter or arch-timer. We need 323 + * to express timeouts in term of number of cycles and specify which 324 + * timer source should be used. 325 + * 326 + * Return: A value suitable for timeout fields in the global interface. 327 + */ 328 + static u32 panthor_fw_conv_timeout(struct panthor_device *ptdev, u32 timeout_us) 329 + { 330 + bool use_cycle_counter = false; 331 + u32 timer_rate = 0; 332 + u64 mod_cycles; 333 + 334 + #ifdef CONFIG_ARM_ARCH_TIMER 335 + timer_rate = arch_timer_get_cntfrq(); 336 + #endif 337 + 338 + if (!timer_rate) { 339 + use_cycle_counter = true; 340 + timer_rate = clk_get_rate(ptdev->clks.core); 341 + } 342 + 343 + if (drm_WARN_ON(&ptdev->base, !timer_rate)) { 344 + /* We couldn't get a valid clock rate, let's just pick the 345 + * maximum value so the FW still handles the core 346 + * power on/off requests. 347 + */ 348 + return GLB_TIMER_VAL(~0) | 349 + GLB_TIMER_SOURCE_GPU_COUNTER; 350 + } 351 + 352 + mod_cycles = DIV_ROUND_UP_ULL((u64)timeout_us * timer_rate, 353 + 1000000ull << 10); 354 + if (drm_WARN_ON(&ptdev->base, mod_cycles > GLB_TIMER_VAL(~0))) 355 + mod_cycles = GLB_TIMER_VAL(~0); 356 + 357 + return GLB_TIMER_VAL(mod_cycles) | 358 + (use_cycle_counter ? GLB_TIMER_SOURCE_GPU_COUNTER : 0); 359 + } 360 + 361 + static int panthor_fw_binary_iter_read(struct panthor_device *ptdev, 362 + struct panthor_fw_binary_iter *iter, 363 + void *out, size_t size) 364 + { 365 + size_t new_offset = iter->offset + size; 366 + 367 + if (new_offset > iter->size || new_offset < iter->offset) { 368 + drm_err(&ptdev->base, "Firmware too small\n"); 369 + return -EINVAL; 370 + } 371 + 372 + memcpy(out, iter->data + iter->offset, size); 373 + iter->offset = new_offset; 374 + return 0; 375 + } 376 + 377 + static int panthor_fw_binary_sub_iter_init(struct panthor_device *ptdev, 378 + struct panthor_fw_binary_iter *iter, 379 + struct panthor_fw_binary_iter *sub_iter, 380 + size_t size) 381 + { 382 + size_t new_offset = iter->offset + size; 383 + 384 + if (new_offset > iter->size || new_offset < iter->offset) { 385 + drm_err(&ptdev->base, "Firmware entry too long\n"); 386 + return -EINVAL; 387 + } 388 + 389 + sub_iter->offset = 0; 390 + sub_iter->data = iter->data + iter->offset; 391 + sub_iter->size = size; 392 + iter->offset = new_offset; 393 + return 0; 394 + } 395 + 396 + static void panthor_fw_init_section_mem(struct panthor_device *ptdev, 397 + struct panthor_fw_section *section) 398 + { 399 + bool was_mapped = !!section->mem->kmap; 400 + int ret; 401 + 402 + if (!section->data.size && 403 + !(section->flags & CSF_FW_BINARY_IFACE_ENTRY_RD_ZERO)) 404 + return; 405 + 406 + ret = panthor_kernel_bo_vmap(section->mem); 407 + if (drm_WARN_ON(&ptdev->base, ret)) 408 + return; 409 + 410 + memcpy(section->mem->kmap, section->data.buf, section->data.size); 411 + if (section->flags & CSF_FW_BINARY_IFACE_ENTRY_RD_ZERO) { 412 + memset(section->mem->kmap + section->data.size, 0, 413 + panthor_kernel_bo_size(section->mem) - section->data.size); 414 + } 415 + 416 + if (!was_mapped) 417 + panthor_kernel_bo_vunmap(section->mem); 418 + } 419 + 420 + /** 421 + * panthor_fw_alloc_queue_iface_mem() - Allocate a ring-buffer interfaces. 422 + * @ptdev: Device. 423 + * @input: Pointer holding the input interface on success. 424 + * Should be ignored on failure. 425 + * @output: Pointer holding the output interface on success. 426 + * Should be ignored on failure. 427 + * @input_fw_va: Pointer holding the input interface FW VA on success. 428 + * Should be ignored on failure. 429 + * @output_fw_va: Pointer holding the output interface FW VA on success. 430 + * Should be ignored on failure. 431 + * 432 + * Allocates panthor_fw_ringbuf_{input,out}_iface interfaces. The input 433 + * interface is at offset 0, and the output interface at offset 4096. 434 + * 435 + * Return: A valid pointer in case of success, an ERR_PTR() otherwise. 436 + */ 437 + struct panthor_kernel_bo * 438 + panthor_fw_alloc_queue_iface_mem(struct panthor_device *ptdev, 439 + struct panthor_fw_ringbuf_input_iface **input, 440 + const struct panthor_fw_ringbuf_output_iface **output, 441 + u32 *input_fw_va, u32 *output_fw_va) 442 + { 443 + struct panthor_kernel_bo *mem; 444 + int ret; 445 + 446 + mem = panthor_kernel_bo_create(ptdev, ptdev->fw->vm, SZ_8K, 447 + DRM_PANTHOR_BO_NO_MMAP, 448 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | 449 + DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED, 450 + PANTHOR_VM_KERNEL_AUTO_VA); 451 + if (IS_ERR(mem)) 452 + return mem; 453 + 454 + ret = panthor_kernel_bo_vmap(mem); 455 + if (ret) { 456 + panthor_kernel_bo_destroy(panthor_fw_vm(ptdev), mem); 457 + return ERR_PTR(ret); 458 + } 459 + 460 + memset(mem->kmap, 0, panthor_kernel_bo_size(mem)); 461 + *input = mem->kmap; 462 + *output = mem->kmap + SZ_4K; 463 + *input_fw_va = panthor_kernel_bo_gpuva(mem); 464 + *output_fw_va = *input_fw_va + SZ_4K; 465 + 466 + return mem; 467 + } 468 + 469 + /** 470 + * panthor_fw_alloc_suspend_buf_mem() - Allocate a suspend buffer for a command stream group. 471 + * @ptdev: Device. 472 + * @size: Size of the suspend buffer. 473 + * 474 + * Return: A valid pointer in case of success, an ERR_PTR() otherwise. 475 + */ 476 + struct panthor_kernel_bo * 477 + panthor_fw_alloc_suspend_buf_mem(struct panthor_device *ptdev, size_t size) 478 + { 479 + return panthor_kernel_bo_create(ptdev, panthor_fw_vm(ptdev), size, 480 + DRM_PANTHOR_BO_NO_MMAP, 481 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, 482 + PANTHOR_VM_KERNEL_AUTO_VA); 483 + } 484 + 485 + static int panthor_fw_load_section_entry(struct panthor_device *ptdev, 486 + const struct firmware *fw, 487 + struct panthor_fw_binary_iter *iter, 488 + u32 ehdr) 489 + { 490 + struct panthor_fw_binary_section_entry_hdr hdr; 491 + struct panthor_fw_section *section; 492 + u32 section_size; 493 + u32 name_len; 494 + int ret; 495 + 496 + ret = panthor_fw_binary_iter_read(ptdev, iter, &hdr, sizeof(hdr)); 497 + if (ret) 498 + return ret; 499 + 500 + if (hdr.data.end < hdr.data.start) { 501 + drm_err(&ptdev->base, "Firmware corrupted, data.end < data.start (0x%x < 0x%x)\n", 502 + hdr.data.end, hdr.data.start); 503 + return -EINVAL; 504 + } 505 + 506 + if (hdr.va.end < hdr.va.start) { 507 + drm_err(&ptdev->base, "Firmware corrupted, hdr.va.end < hdr.va.start (0x%x < 0x%x)\n", 508 + hdr.va.end, hdr.va.start); 509 + return -EINVAL; 510 + } 511 + 512 + if (hdr.data.end > fw->size) { 513 + drm_err(&ptdev->base, "Firmware corrupted, file truncated? data_end=0x%x > fw size=0x%zx\n", 514 + hdr.data.end, fw->size); 515 + return -EINVAL; 516 + } 517 + 518 + if ((hdr.va.start & ~PAGE_MASK) != 0 || 519 + (hdr.va.end & ~PAGE_MASK) != 0) { 520 + drm_err(&ptdev->base, "Firmware corrupted, virtual addresses not page aligned: 0x%x-0x%x\n", 521 + hdr.va.start, hdr.va.end); 522 + return -EINVAL; 523 + } 524 + 525 + if (hdr.flags & ~CSF_FW_BINARY_IFACE_ENTRY_RD_SUPPORTED_FLAGS) { 526 + drm_err(&ptdev->base, "Firmware contains interface with unsupported flags (0x%x)\n", 527 + hdr.flags); 528 + return -EINVAL; 529 + } 530 + 531 + if (hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_RD_PROT) { 532 + drm_warn(&ptdev->base, 533 + "Firmware protected mode entry not be supported, ignoring"); 534 + return 0; 535 + } 536 + 537 + if (hdr.va.start == CSF_MCU_SHARED_REGION_START && 538 + !(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_RD_SHARED)) { 539 + drm_err(&ptdev->base, 540 + "Interface at 0x%llx must be shared", CSF_MCU_SHARED_REGION_START); 541 + return -EINVAL; 542 + } 543 + 544 + name_len = iter->size - iter->offset; 545 + 546 + section = drmm_kzalloc(&ptdev->base, sizeof(*section), GFP_KERNEL); 547 + if (!section) 548 + return -ENOMEM; 549 + 550 + list_add_tail(&section->node, &ptdev->fw->sections); 551 + section->flags = hdr.flags; 552 + section->data.size = hdr.data.end - hdr.data.start; 553 + 554 + if (section->data.size > 0) { 555 + void *data = drmm_kmalloc(&ptdev->base, section->data.size, GFP_KERNEL); 556 + 557 + if (!data) 558 + return -ENOMEM; 559 + 560 + memcpy(data, fw->data + hdr.data.start, section->data.size); 561 + section->data.buf = data; 562 + } 563 + 564 + if (name_len > 0) { 565 + char *name = drmm_kmalloc(&ptdev->base, name_len + 1, GFP_KERNEL); 566 + 567 + if (!name) 568 + return -ENOMEM; 569 + 570 + memcpy(name, iter->data + iter->offset, name_len); 571 + name[name_len] = '\0'; 572 + section->name = name; 573 + } 574 + 575 + section_size = hdr.va.end - hdr.va.start; 576 + if (section_size) { 577 + u32 cache_mode = hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_MASK; 578 + struct panthor_gem_object *bo; 579 + u32 vm_map_flags = 0; 580 + struct sg_table *sgt; 581 + u64 va = hdr.va.start; 582 + 583 + if (!(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_RD_WR)) 584 + vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_READONLY; 585 + 586 + if (!(hdr.flags & CSF_FW_BINARY_IFACE_ENTRY_RD_EX)) 587 + vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC; 588 + 589 + /* TODO: CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_*_COHERENT are mapped to 590 + * non-cacheable for now. We might want to introduce a new 591 + * IOMMU_xxx flag (or abuse IOMMU_MMIO, which maps to device 592 + * memory and is currently not used by our driver) for 593 + * AS_MEMATTR_AARCH64_SHARED memory, so we can take benefit 594 + * of IO-coherent systems. 595 + */ 596 + if (cache_mode != CSF_FW_BINARY_IFACE_ENTRY_RD_CACHE_MODE_CACHED) 597 + vm_map_flags |= DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED; 598 + 599 + section->mem = panthor_kernel_bo_create(ptdev, panthor_fw_vm(ptdev), 600 + section_size, 601 + DRM_PANTHOR_BO_NO_MMAP, 602 + vm_map_flags, va); 603 + if (IS_ERR(section->mem)) 604 + return PTR_ERR(section->mem); 605 + 606 + if (drm_WARN_ON(&ptdev->base, section->mem->va_node.start != hdr.va.start)) 607 + return -EINVAL; 608 + 609 + if (section->flags & CSF_FW_BINARY_IFACE_ENTRY_RD_SHARED) { 610 + ret = panthor_kernel_bo_vmap(section->mem); 611 + if (ret) 612 + return ret; 613 + } 614 + 615 + panthor_fw_init_section_mem(ptdev, section); 616 + 617 + bo = to_panthor_bo(section->mem->obj); 618 + sgt = drm_gem_shmem_get_pages_sgt(&bo->base); 619 + if (IS_ERR(sgt)) 620 + return PTR_ERR(sgt); 621 + 622 + dma_sync_sgtable_for_device(ptdev->base.dev, sgt, DMA_TO_DEVICE); 623 + } 624 + 625 + if (hdr.va.start == CSF_MCU_SHARED_REGION_START) 626 + ptdev->fw->shared_section = section; 627 + 628 + return 0; 629 + } 630 + 631 + static void 632 + panthor_reload_fw_sections(struct panthor_device *ptdev, bool full_reload) 633 + { 634 + struct panthor_fw_section *section; 635 + 636 + list_for_each_entry(section, &ptdev->fw->sections, node) { 637 + struct sg_table *sgt; 638 + 639 + if (!full_reload && !(section->flags & CSF_FW_BINARY_IFACE_ENTRY_RD_WR)) 640 + continue; 641 + 642 + panthor_fw_init_section_mem(ptdev, section); 643 + sgt = drm_gem_shmem_get_pages_sgt(&to_panthor_bo(section->mem->obj)->base); 644 + if (!drm_WARN_ON(&ptdev->base, IS_ERR_OR_NULL(sgt))) 645 + dma_sync_sgtable_for_device(ptdev->base.dev, sgt, DMA_TO_DEVICE); 646 + } 647 + } 648 + 649 + static int panthor_fw_load_entry(struct panthor_device *ptdev, 650 + const struct firmware *fw, 651 + struct panthor_fw_binary_iter *iter) 652 + { 653 + struct panthor_fw_binary_iter eiter; 654 + u32 ehdr; 655 + int ret; 656 + 657 + ret = panthor_fw_binary_iter_read(ptdev, iter, &ehdr, sizeof(ehdr)); 658 + if (ret) 659 + return ret; 660 + 661 + if ((iter->offset % sizeof(u32)) || 662 + (CSF_FW_BINARY_ENTRY_SIZE(ehdr) % sizeof(u32))) { 663 + drm_err(&ptdev->base, "Firmware entry isn't 32 bit aligned, offset=0x%x size=0x%x\n", 664 + (u32)(iter->offset - sizeof(u32)), CSF_FW_BINARY_ENTRY_SIZE(ehdr)); 665 + return -EINVAL; 666 + } 667 + 668 + if (panthor_fw_binary_sub_iter_init(ptdev, iter, &eiter, 669 + CSF_FW_BINARY_ENTRY_SIZE(ehdr) - sizeof(ehdr))) 670 + return -EINVAL; 671 + 672 + switch (CSF_FW_BINARY_ENTRY_TYPE(ehdr)) { 673 + case CSF_FW_BINARY_ENTRY_TYPE_IFACE: 674 + return panthor_fw_load_section_entry(ptdev, fw, &eiter, ehdr); 675 + 676 + /* FIXME: handle those entry types? */ 677 + case CSF_FW_BINARY_ENTRY_TYPE_CONFIG: 678 + case CSF_FW_BINARY_ENTRY_TYPE_FUTF_TEST: 679 + case CSF_FW_BINARY_ENTRY_TYPE_TRACE_BUFFER: 680 + case CSF_FW_BINARY_ENTRY_TYPE_TIMELINE_METADATA: 681 + return 0; 682 + default: 683 + break; 684 + } 685 + 686 + if (ehdr & CSF_FW_BINARY_ENTRY_OPTIONAL) 687 + return 0; 688 + 689 + drm_err(&ptdev->base, 690 + "Unsupported non-optional entry type %u in firmware\n", 691 + CSF_FW_BINARY_ENTRY_TYPE(ehdr)); 692 + return -EINVAL; 693 + } 694 + 695 + static int panthor_fw_load(struct panthor_device *ptdev) 696 + { 697 + const struct firmware *fw = NULL; 698 + struct panthor_fw_binary_iter iter = {}; 699 + struct panthor_fw_binary_hdr hdr; 700 + char fw_path[128]; 701 + int ret; 702 + 703 + snprintf(fw_path, sizeof(fw_path), "arm/mali/arch%d.%d/%s", 704 + (u32)GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id), 705 + (u32)GPU_ARCH_MINOR(ptdev->gpu_info.gpu_id), 706 + CSF_FW_NAME); 707 + 708 + ret = request_firmware(&fw, fw_path, ptdev->base.dev); 709 + if (ret) { 710 + drm_err(&ptdev->base, "Failed to load firmware image '%s'\n", 711 + CSF_FW_NAME); 712 + return ret; 713 + } 714 + 715 + iter.data = fw->data; 716 + iter.size = fw->size; 717 + ret = panthor_fw_binary_iter_read(ptdev, &iter, &hdr, sizeof(hdr)); 718 + if (ret) 719 + goto out; 720 + 721 + if (hdr.magic != CSF_FW_BINARY_HEADER_MAGIC) { 722 + ret = -EINVAL; 723 + drm_err(&ptdev->base, "Invalid firmware magic\n"); 724 + goto out; 725 + } 726 + 727 + if (hdr.major != CSF_FW_BINARY_HEADER_MAJOR_MAX) { 728 + ret = -EINVAL; 729 + drm_err(&ptdev->base, "Unsupported firmware binary header version %d.%d (expected %d.x)\n", 730 + hdr.major, hdr.minor, CSF_FW_BINARY_HEADER_MAJOR_MAX); 731 + goto out; 732 + } 733 + 734 + if (hdr.size > iter.size) { 735 + drm_err(&ptdev->base, "Firmware image is truncated\n"); 736 + goto out; 737 + } 738 + 739 + iter.size = hdr.size; 740 + 741 + while (iter.offset < hdr.size) { 742 + ret = panthor_fw_load_entry(ptdev, fw, &iter); 743 + if (ret) 744 + goto out; 745 + } 746 + 747 + if (!ptdev->fw->shared_section) { 748 + drm_err(&ptdev->base, "Shared interface region not found\n"); 749 + ret = -EINVAL; 750 + goto out; 751 + } 752 + 753 + out: 754 + release_firmware(fw); 755 + return ret; 756 + } 757 + 758 + /** 759 + * iface_fw_to_cpu_addr() - Turn an MCU address into a CPU address 760 + * @ptdev: Device. 761 + * @mcu_va: MCU address. 762 + * 763 + * Return: NULL if the address is not part of the shared section, non-NULL otherwise. 764 + */ 765 + static void *iface_fw_to_cpu_addr(struct panthor_device *ptdev, u32 mcu_va) 766 + { 767 + u64 shared_mem_start = panthor_kernel_bo_gpuva(ptdev->fw->shared_section->mem); 768 + u64 shared_mem_end = shared_mem_start + 769 + panthor_kernel_bo_size(ptdev->fw->shared_section->mem); 770 + if (mcu_va < shared_mem_start || mcu_va >= shared_mem_end) 771 + return NULL; 772 + 773 + return ptdev->fw->shared_section->mem->kmap + (mcu_va - shared_mem_start); 774 + } 775 + 776 + static int panthor_init_cs_iface(struct panthor_device *ptdev, 777 + unsigned int csg_idx, unsigned int cs_idx) 778 + { 779 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 780 + struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, csg_idx); 781 + struct panthor_fw_cs_iface *cs_iface = &ptdev->fw->iface.streams[csg_idx][cs_idx]; 782 + u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem); 783 + u32 iface_offset = CSF_GROUP_CONTROL_OFFSET + 784 + (csg_idx * glb_iface->control->group_stride) + 785 + CSF_STREAM_CONTROL_OFFSET + 786 + (cs_idx * csg_iface->control->stream_stride); 787 + struct panthor_fw_cs_iface *first_cs_iface = 788 + panthor_fw_get_cs_iface(ptdev, 0, 0); 789 + 790 + if (iface_offset + sizeof(*cs_iface) >= shared_section_sz) 791 + return -EINVAL; 792 + 793 + spin_lock_init(&cs_iface->lock); 794 + cs_iface->control = ptdev->fw->shared_section->mem->kmap + iface_offset; 795 + cs_iface->input = iface_fw_to_cpu_addr(ptdev, cs_iface->control->input_va); 796 + cs_iface->output = iface_fw_to_cpu_addr(ptdev, cs_iface->control->output_va); 797 + 798 + if (!cs_iface->input || !cs_iface->output) { 799 + drm_err(&ptdev->base, "Invalid stream control interface input/output VA"); 800 + return -EINVAL; 801 + } 802 + 803 + if (cs_iface != first_cs_iface) { 804 + if (cs_iface->control->features != first_cs_iface->control->features) { 805 + drm_err(&ptdev->base, "Expecting identical CS slots"); 806 + return -EINVAL; 807 + } 808 + } else { 809 + u32 reg_count = CS_FEATURES_WORK_REGS(cs_iface->control->features); 810 + 811 + ptdev->csif_info.cs_reg_count = reg_count; 812 + ptdev->csif_info.unpreserved_cs_reg_count = CSF_UNPRESERVED_REG_COUNT; 813 + } 814 + 815 + return 0; 816 + } 817 + 818 + static bool compare_csg(const struct panthor_fw_csg_control_iface *a, 819 + const struct panthor_fw_csg_control_iface *b) 820 + { 821 + if (a->features != b->features) 822 + return false; 823 + if (a->suspend_size != b->suspend_size) 824 + return false; 825 + if (a->protm_suspend_size != b->protm_suspend_size) 826 + return false; 827 + if (a->stream_num != b->stream_num) 828 + return false; 829 + return true; 830 + } 831 + 832 + static int panthor_init_csg_iface(struct panthor_device *ptdev, 833 + unsigned int csg_idx) 834 + { 835 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 836 + struct panthor_fw_csg_iface *csg_iface = &ptdev->fw->iface.groups[csg_idx]; 837 + u64 shared_section_sz = panthor_kernel_bo_size(ptdev->fw->shared_section->mem); 838 + u32 iface_offset = CSF_GROUP_CONTROL_OFFSET + (csg_idx * glb_iface->control->group_stride); 839 + unsigned int i; 840 + 841 + if (iface_offset + sizeof(*csg_iface) >= shared_section_sz) 842 + return -EINVAL; 843 + 844 + spin_lock_init(&csg_iface->lock); 845 + csg_iface->control = ptdev->fw->shared_section->mem->kmap + iface_offset; 846 + csg_iface->input = iface_fw_to_cpu_addr(ptdev, csg_iface->control->input_va); 847 + csg_iface->output = iface_fw_to_cpu_addr(ptdev, csg_iface->control->output_va); 848 + 849 + if (csg_iface->control->stream_num < MIN_CS_PER_CSG || 850 + csg_iface->control->stream_num > MAX_CS_PER_CSG) 851 + return -EINVAL; 852 + 853 + if (!csg_iface->input || !csg_iface->output) { 854 + drm_err(&ptdev->base, "Invalid group control interface input/output VA"); 855 + return -EINVAL; 856 + } 857 + 858 + if (csg_idx > 0) { 859 + struct panthor_fw_csg_iface *first_csg_iface = 860 + panthor_fw_get_csg_iface(ptdev, 0); 861 + 862 + if (!compare_csg(first_csg_iface->control, csg_iface->control)) { 863 + drm_err(&ptdev->base, "Expecting identical CSG slots"); 864 + return -EINVAL; 865 + } 866 + } 867 + 868 + for (i = 0; i < csg_iface->control->stream_num; i++) { 869 + int ret = panthor_init_cs_iface(ptdev, csg_idx, i); 870 + 871 + if (ret) 872 + return ret; 873 + } 874 + 875 + return 0; 876 + } 877 + 878 + static u32 panthor_get_instr_features(struct panthor_device *ptdev) 879 + { 880 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 881 + 882 + if (glb_iface->control->version < CSF_IFACE_VERSION(1, 1, 0)) 883 + return 0; 884 + 885 + return glb_iface->control->instr_features; 886 + } 887 + 888 + static int panthor_fw_init_ifaces(struct panthor_device *ptdev) 889 + { 890 + struct panthor_fw_global_iface *glb_iface = &ptdev->fw->iface.global; 891 + unsigned int i; 892 + 893 + if (!ptdev->fw->shared_section->mem->kmap) 894 + return -EINVAL; 895 + 896 + spin_lock_init(&glb_iface->lock); 897 + glb_iface->control = ptdev->fw->shared_section->mem->kmap; 898 + 899 + if (!glb_iface->control->version) { 900 + drm_err(&ptdev->base, "Firmware version is 0. Firmware may have failed to boot"); 901 + return -EINVAL; 902 + } 903 + 904 + glb_iface->input = iface_fw_to_cpu_addr(ptdev, glb_iface->control->input_va); 905 + glb_iface->output = iface_fw_to_cpu_addr(ptdev, glb_iface->control->output_va); 906 + if (!glb_iface->input || !glb_iface->output) { 907 + drm_err(&ptdev->base, "Invalid global control interface input/output VA"); 908 + return -EINVAL; 909 + } 910 + 911 + if (glb_iface->control->group_num > MAX_CSGS || 912 + glb_iface->control->group_num < MIN_CSGS) { 913 + drm_err(&ptdev->base, "Invalid number of control groups"); 914 + return -EINVAL; 915 + } 916 + 917 + for (i = 0; i < glb_iface->control->group_num; i++) { 918 + int ret = panthor_init_csg_iface(ptdev, i); 919 + 920 + if (ret) 921 + return ret; 922 + } 923 + 924 + drm_info(&ptdev->base, "CSF FW v%d.%d.%d, Features %#x Instrumentation features %#x", 925 + CSF_IFACE_VERSION_MAJOR(glb_iface->control->version), 926 + CSF_IFACE_VERSION_MINOR(glb_iface->control->version), 927 + CSF_IFACE_VERSION_PATCH(glb_iface->control->version), 928 + glb_iface->control->features, 929 + panthor_get_instr_features(ptdev)); 930 + return 0; 931 + } 932 + 933 + static void panthor_fw_init_global_iface(struct panthor_device *ptdev) 934 + { 935 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 936 + 937 + /* Enable all cores. */ 938 + glb_iface->input->core_en_mask = ptdev->gpu_info.shader_present; 939 + 940 + /* Setup timers. */ 941 + glb_iface->input->poweroff_timer = panthor_fw_conv_timeout(ptdev, PWROFF_HYSTERESIS_US); 942 + glb_iface->input->progress_timer = PROGRESS_TIMEOUT_CYCLES >> PROGRESS_TIMEOUT_SCALE_SHIFT; 943 + glb_iface->input->idle_timer = panthor_fw_conv_timeout(ptdev, IDLE_HYSTERESIS_US); 944 + 945 + /* Enable interrupts we care about. */ 946 + glb_iface->input->ack_irq_mask = GLB_CFG_ALLOC_EN | 947 + GLB_PING | 948 + GLB_CFG_PROGRESS_TIMER | 949 + GLB_CFG_POWEROFF_TIMER | 950 + GLB_IDLE_EN | 951 + GLB_IDLE; 952 + 953 + panthor_fw_update_reqs(glb_iface, req, GLB_IDLE_EN, GLB_IDLE_EN); 954 + panthor_fw_toggle_reqs(glb_iface, req, ack, 955 + GLB_CFG_ALLOC_EN | 956 + GLB_CFG_POWEROFF_TIMER | 957 + GLB_CFG_PROGRESS_TIMER); 958 + 959 + gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); 960 + 961 + /* Kick the watchdog. */ 962 + mod_delayed_work(ptdev->reset.wq, &ptdev->fw->watchdog.ping_work, 963 + msecs_to_jiffies(PING_INTERVAL_MS)); 964 + } 965 + 966 + static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status) 967 + { 968 + if (!ptdev->fw->booted && (status & JOB_INT_GLOBAL_IF)) 969 + ptdev->fw->booted = true; 970 + 971 + wake_up_all(&ptdev->fw->req_waitqueue); 972 + 973 + /* If the FW is not booted, don't process IRQs, just flag the FW as booted. */ 974 + if (!ptdev->fw->booted) 975 + return; 976 + 977 + panthor_sched_report_fw_events(ptdev, status); 978 + } 979 + PANTHOR_IRQ_HANDLER(job, JOB, panthor_job_irq_handler); 980 + 981 + static int panthor_fw_start(struct panthor_device *ptdev) 982 + { 983 + bool timedout = false; 984 + 985 + ptdev->fw->booted = false; 986 + panthor_job_irq_resume(&ptdev->fw->irq, ~0); 987 + gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_AUTO); 988 + 989 + if (!wait_event_timeout(ptdev->fw->req_waitqueue, 990 + ptdev->fw->booted, 991 + msecs_to_jiffies(1000))) { 992 + if (!ptdev->fw->booted && 993 + !(gpu_read(ptdev, JOB_INT_STAT) & JOB_INT_GLOBAL_IF)) 994 + timedout = true; 995 + } 996 + 997 + if (timedout) { 998 + static const char * const status_str[] = { 999 + [MCU_STATUS_DISABLED] = "disabled", 1000 + [MCU_STATUS_ENABLED] = "enabled", 1001 + [MCU_STATUS_HALT] = "halt", 1002 + [MCU_STATUS_FATAL] = "fatal", 1003 + }; 1004 + u32 status = gpu_read(ptdev, MCU_STATUS); 1005 + 1006 + drm_err(&ptdev->base, "Failed to boot MCU (status=%s)", 1007 + status < ARRAY_SIZE(status_str) ? status_str[status] : "unknown"); 1008 + return -ETIMEDOUT; 1009 + } 1010 + 1011 + return 0; 1012 + } 1013 + 1014 + static void panthor_fw_stop(struct panthor_device *ptdev) 1015 + { 1016 + u32 status; 1017 + 1018 + gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_DISABLE); 1019 + if (readl_poll_timeout(ptdev->iomem + MCU_STATUS, status, 1020 + status == MCU_STATUS_DISABLED, 10, 100000)) 1021 + drm_err(&ptdev->base, "Failed to stop MCU"); 1022 + } 1023 + 1024 + /** 1025 + * panthor_fw_pre_reset() - Call before a reset. 1026 + * @ptdev: Device. 1027 + * @on_hang: true if the reset was triggered on a GPU hang. 1028 + * 1029 + * If the reset is not triggered on a hang, we try to gracefully halt the 1030 + * MCU, so we can do a fast-reset when panthor_fw_post_reset() is called. 1031 + */ 1032 + void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang) 1033 + { 1034 + /* Make sure we won't be woken up by a ping. */ 1035 + cancel_delayed_work_sync(&ptdev->fw->watchdog.ping_work); 1036 + 1037 + ptdev->fw->fast_reset = false; 1038 + 1039 + if (!on_hang) { 1040 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 1041 + u32 status; 1042 + 1043 + panthor_fw_update_reqs(glb_iface, req, GLB_HALT, GLB_HALT); 1044 + gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); 1045 + if (!readl_poll_timeout(ptdev->iomem + MCU_STATUS, status, 1046 + status == MCU_STATUS_HALT, 10, 100000) && 1047 + glb_iface->output->halt_status == PANTHOR_FW_HALT_OK) { 1048 + ptdev->fw->fast_reset = true; 1049 + } else { 1050 + drm_warn(&ptdev->base, "Failed to cleanly suspend MCU"); 1051 + } 1052 + 1053 + /* The FW detects 0 -> 1 transitions. Make sure we reset 1054 + * the HALT bit before the FW is rebooted. 1055 + */ 1056 + panthor_fw_update_reqs(glb_iface, req, 0, GLB_HALT); 1057 + } 1058 + 1059 + panthor_job_irq_suspend(&ptdev->fw->irq); 1060 + } 1061 + 1062 + /** 1063 + * panthor_fw_post_reset() - Call after a reset. 1064 + * @ptdev: Device. 1065 + * 1066 + * Start the FW. If this is not a fast reset, all FW sections are reloaded to 1067 + * make sure we can recover from a memory corruption. 1068 + */ 1069 + int panthor_fw_post_reset(struct panthor_device *ptdev) 1070 + { 1071 + int ret; 1072 + 1073 + /* Make the MCU VM active. */ 1074 + ret = panthor_vm_active(ptdev->fw->vm); 1075 + if (ret) 1076 + return ret; 1077 + 1078 + /* If this is a fast reset, try to start the MCU without reloading 1079 + * the FW sections. If it fails, go for a full reset. 1080 + */ 1081 + if (ptdev->fw->fast_reset) { 1082 + ret = panthor_fw_start(ptdev); 1083 + if (!ret) 1084 + goto out; 1085 + 1086 + /* Force a disable, so we get a fresh boot on the next 1087 + * panthor_fw_start() call. 1088 + */ 1089 + gpu_write(ptdev, MCU_CONTROL, MCU_CONTROL_DISABLE); 1090 + drm_err(&ptdev->base, "FW fast reset failed, trying a slow reset"); 1091 + } 1092 + 1093 + /* Reload all sections, including RO ones. We're not supposed 1094 + * to end up here anyway, let's just assume the overhead of 1095 + * reloading everything is acceptable. 1096 + */ 1097 + panthor_reload_fw_sections(ptdev, true); 1098 + 1099 + ret = panthor_fw_start(ptdev); 1100 + if (ret) { 1101 + drm_err(&ptdev->base, "FW slow reset failed"); 1102 + return ret; 1103 + } 1104 + 1105 + out: 1106 + /* We must re-initialize the global interface even on fast-reset. */ 1107 + panthor_fw_init_global_iface(ptdev); 1108 + return 0; 1109 + } 1110 + 1111 + /** 1112 + * panthor_fw_unplug() - Called when the device is unplugged. 1113 + * @ptdev: Device. 1114 + * 1115 + * This function must make sure all pending operations are flushed before 1116 + * will release device resources, thus preventing any interaction with 1117 + * the HW. 1118 + * 1119 + * If there is still FW-related work running after this function returns, 1120 + * they must use drm_dev_{enter,exit}() and skip any HW access when 1121 + * drm_dev_enter() returns false. 1122 + */ 1123 + void panthor_fw_unplug(struct panthor_device *ptdev) 1124 + { 1125 + struct panthor_fw_section *section; 1126 + 1127 + cancel_delayed_work_sync(&ptdev->fw->watchdog.ping_work); 1128 + 1129 + /* Make sure the IRQ handler can be called after that point. */ 1130 + if (ptdev->fw->irq.irq) 1131 + panthor_job_irq_suspend(&ptdev->fw->irq); 1132 + 1133 + panthor_fw_stop(ptdev); 1134 + 1135 + list_for_each_entry(section, &ptdev->fw->sections, node) 1136 + panthor_kernel_bo_destroy(panthor_fw_vm(ptdev), section->mem); 1137 + 1138 + /* We intentionally don't call panthor_vm_idle() and let 1139 + * panthor_mmu_unplug() release the AS we acquired with 1140 + * panthor_vm_active() so we don't have to track the VM active/idle 1141 + * state to keep the active_refcnt balanced. 1142 + */ 1143 + panthor_vm_put(ptdev->fw->vm); 1144 + 1145 + panthor_gpu_power_off(ptdev, L2, ptdev->gpu_info.l2_present, 20000); 1146 + } 1147 + 1148 + /** 1149 + * panthor_fw_wait_acks() - Wait for requests to be acknowledged by the FW. 1150 + * @req_ptr: Pointer to the req register. 1151 + * @ack_ptr: Pointer to the ack register. 1152 + * @wq: Wait queue to use for the sleeping wait. 1153 + * @req_mask: Mask of requests to wait for. 1154 + * @acked: Pointer to field that's updated with the acked requests. 1155 + * If the function returns 0, *acked == req_mask. 1156 + * @timeout_ms: Timeout expressed in milliseconds. 1157 + * 1158 + * Return: 0 on success, -ETIMEDOUT otherwise. 1159 + */ 1160 + static int panthor_fw_wait_acks(const u32 *req_ptr, const u32 *ack_ptr, 1161 + wait_queue_head_t *wq, 1162 + u32 req_mask, u32 *acked, 1163 + u32 timeout_ms) 1164 + { 1165 + u32 ack, req = READ_ONCE(*req_ptr) & req_mask; 1166 + int ret; 1167 + 1168 + /* Busy wait for a few µsecs before falling back to a sleeping wait. */ 1169 + *acked = req_mask; 1170 + ret = read_poll_timeout_atomic(READ_ONCE, ack, 1171 + (ack & req_mask) == req, 1172 + 0, 10, 0, 1173 + *ack_ptr); 1174 + if (!ret) 1175 + return 0; 1176 + 1177 + if (wait_event_timeout(*wq, (READ_ONCE(*ack_ptr) & req_mask) == req, 1178 + msecs_to_jiffies(timeout_ms))) 1179 + return 0; 1180 + 1181 + /* Check one last time, in case we were not woken up for some reason. */ 1182 + ack = READ_ONCE(*ack_ptr); 1183 + if ((ack & req_mask) == req) 1184 + return 0; 1185 + 1186 + *acked = ~(req ^ ack) & req_mask; 1187 + return -ETIMEDOUT; 1188 + } 1189 + 1190 + /** 1191 + * panthor_fw_glb_wait_acks() - Wait for global requests to be acknowledged. 1192 + * @ptdev: Device. 1193 + * @req_mask: Mask of requests to wait for. 1194 + * @acked: Pointer to field that's updated with the acked requests. 1195 + * If the function returns 0, *acked == req_mask. 1196 + * @timeout_ms: Timeout expressed in milliseconds. 1197 + * 1198 + * Return: 0 on success, -ETIMEDOUT otherwise. 1199 + */ 1200 + int panthor_fw_glb_wait_acks(struct panthor_device *ptdev, 1201 + u32 req_mask, u32 *acked, 1202 + u32 timeout_ms) 1203 + { 1204 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 1205 + 1206 + /* GLB_HALT doesn't get acked through the FW interface. */ 1207 + if (drm_WARN_ON(&ptdev->base, req_mask & (~GLB_REQ_MASK | GLB_HALT))) 1208 + return -EINVAL; 1209 + 1210 + return panthor_fw_wait_acks(&glb_iface->input->req, 1211 + &glb_iface->output->ack, 1212 + &ptdev->fw->req_waitqueue, 1213 + req_mask, acked, timeout_ms); 1214 + } 1215 + 1216 + /** 1217 + * panthor_fw_csg_wait_acks() - Wait for command stream group requests to be acknowledged. 1218 + * @ptdev: Device. 1219 + * @csg_slot: CSG slot ID. 1220 + * @req_mask: Mask of requests to wait for. 1221 + * @acked: Pointer to field that's updated with the acked requests. 1222 + * If the function returns 0, *acked == req_mask. 1223 + * @timeout_ms: Timeout expressed in milliseconds. 1224 + * 1225 + * Return: 0 on success, -ETIMEDOUT otherwise. 1226 + */ 1227 + int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_slot, 1228 + u32 req_mask, u32 *acked, u32 timeout_ms) 1229 + { 1230 + struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, csg_slot); 1231 + int ret; 1232 + 1233 + if (drm_WARN_ON(&ptdev->base, req_mask & ~CSG_REQ_MASK)) 1234 + return -EINVAL; 1235 + 1236 + ret = panthor_fw_wait_acks(&csg_iface->input->req, 1237 + &csg_iface->output->ack, 1238 + &ptdev->fw->req_waitqueue, 1239 + req_mask, acked, timeout_ms); 1240 + 1241 + /* 1242 + * Check that all bits in the state field were updated, if any mismatch 1243 + * then clear all bits in the state field. This allows code to do 1244 + * (acked & CSG_STATE_MASK) and get the right value. 1245 + */ 1246 + 1247 + if ((*acked & CSG_STATE_MASK) != CSG_STATE_MASK) 1248 + *acked &= ~CSG_STATE_MASK; 1249 + 1250 + return ret; 1251 + } 1252 + 1253 + /** 1254 + * panthor_fw_ring_csg_doorbells() - Ring command stream group doorbells. 1255 + * @ptdev: Device. 1256 + * @csg_mask: Bitmask encoding the command stream group doorbells to ring. 1257 + * 1258 + * This function is toggling bits in the doorbell_req and ringing the 1259 + * global doorbell. It doesn't require a user doorbell to be attached to 1260 + * the group. 1261 + */ 1262 + void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_mask) 1263 + { 1264 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 1265 + 1266 + panthor_fw_toggle_reqs(glb_iface, doorbell_req, doorbell_ack, csg_mask); 1267 + gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); 1268 + } 1269 + 1270 + static void panthor_fw_ping_work(struct work_struct *work) 1271 + { 1272 + struct panthor_fw *fw = container_of(work, struct panthor_fw, watchdog.ping_work.work); 1273 + struct panthor_device *ptdev = fw->irq.ptdev; 1274 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 1275 + u32 acked; 1276 + int ret; 1277 + 1278 + if (panthor_device_reset_is_pending(ptdev)) 1279 + return; 1280 + 1281 + panthor_fw_toggle_reqs(glb_iface, req, ack, GLB_PING); 1282 + gpu_write(ptdev, CSF_DOORBELL(CSF_GLB_DOORBELL_ID), 1); 1283 + 1284 + ret = panthor_fw_glb_wait_acks(ptdev, GLB_PING, &acked, 100); 1285 + if (ret) { 1286 + panthor_device_schedule_reset(ptdev); 1287 + drm_err(&ptdev->base, "FW ping timeout, scheduling a reset"); 1288 + } else { 1289 + mod_delayed_work(ptdev->reset.wq, &fw->watchdog.ping_work, 1290 + msecs_to_jiffies(PING_INTERVAL_MS)); 1291 + } 1292 + } 1293 + 1294 + /** 1295 + * panthor_fw_init() - Initialize FW related data. 1296 + * @ptdev: Device. 1297 + * 1298 + * Return: 0 on success, a negative error code otherwise. 1299 + */ 1300 + int panthor_fw_init(struct panthor_device *ptdev) 1301 + { 1302 + struct panthor_fw *fw; 1303 + int ret, irq; 1304 + 1305 + fw = drmm_kzalloc(&ptdev->base, sizeof(*fw), GFP_KERNEL); 1306 + if (!fw) 1307 + return -ENOMEM; 1308 + 1309 + ptdev->fw = fw; 1310 + init_waitqueue_head(&fw->req_waitqueue); 1311 + INIT_LIST_HEAD(&fw->sections); 1312 + INIT_DELAYED_WORK(&fw->watchdog.ping_work, panthor_fw_ping_work); 1313 + 1314 + irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "job"); 1315 + if (irq <= 0) 1316 + return -ENODEV; 1317 + 1318 + ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0); 1319 + if (ret) { 1320 + drm_err(&ptdev->base, "failed to request job irq"); 1321 + return ret; 1322 + } 1323 + 1324 + ret = panthor_gpu_l2_power_on(ptdev); 1325 + if (ret) 1326 + return ret; 1327 + 1328 + fw->vm = panthor_vm_create(ptdev, true, 1329 + 0, SZ_4G, 1330 + CSF_MCU_SHARED_REGION_START, 1331 + CSF_MCU_SHARED_REGION_SIZE); 1332 + if (IS_ERR(fw->vm)) { 1333 + ret = PTR_ERR(fw->vm); 1334 + fw->vm = NULL; 1335 + goto err_unplug_fw; 1336 + } 1337 + 1338 + ret = panthor_fw_load(ptdev); 1339 + if (ret) 1340 + goto err_unplug_fw; 1341 + 1342 + ret = panthor_vm_active(fw->vm); 1343 + if (ret) 1344 + goto err_unplug_fw; 1345 + 1346 + ret = panthor_fw_start(ptdev); 1347 + if (ret) 1348 + goto err_unplug_fw; 1349 + 1350 + ret = panthor_fw_init_ifaces(ptdev); 1351 + if (ret) 1352 + goto err_unplug_fw; 1353 + 1354 + panthor_fw_init_global_iface(ptdev); 1355 + return 0; 1356 + 1357 + err_unplug_fw: 1358 + panthor_fw_unplug(ptdev); 1359 + return ret; 1360 + } 1361 + 1362 + MODULE_FIRMWARE("arm/mali/arch10.8/mali_csffw.bin");
+503
drivers/gpu/drm/panthor/panthor_fw.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2023 Collabora ltd. */ 3 + 4 + #ifndef __PANTHOR_MCU_H__ 5 + #define __PANTHOR_MCU_H__ 6 + 7 + #include <linux/types.h> 8 + 9 + struct panthor_device; 10 + struct panthor_kernel_bo; 11 + 12 + #define MAX_CSGS 31 13 + #define MAX_CS_PER_CSG 32 14 + 15 + struct panthor_fw_ringbuf_input_iface { 16 + u64 insert; 17 + u64 extract; 18 + }; 19 + 20 + struct panthor_fw_ringbuf_output_iface { 21 + u64 extract; 22 + u32 active; 23 + }; 24 + 25 + struct panthor_fw_cs_control_iface { 26 + #define CS_FEATURES_WORK_REGS(x) (((x) & GENMASK(7, 0)) + 1) 27 + #define CS_FEATURES_SCOREBOARDS(x) (((x) & GENMASK(15, 8)) >> 8) 28 + #define CS_FEATURES_COMPUTE BIT(16) 29 + #define CS_FEATURES_FRAGMENT BIT(17) 30 + #define CS_FEATURES_TILER BIT(18) 31 + u32 features; 32 + u32 input_va; 33 + u32 output_va; 34 + }; 35 + 36 + struct panthor_fw_cs_input_iface { 37 + #define CS_STATE_MASK GENMASK(2, 0) 38 + #define CS_STATE_STOP 0 39 + #define CS_STATE_START 1 40 + #define CS_EXTRACT_EVENT BIT(4) 41 + #define CS_IDLE_SYNC_WAIT BIT(8) 42 + #define CS_IDLE_PROTM_PENDING BIT(9) 43 + #define CS_IDLE_EMPTY BIT(10) 44 + #define CS_IDLE_RESOURCE_REQ BIT(11) 45 + #define CS_TILER_OOM BIT(26) 46 + #define CS_PROTM_PENDING BIT(27) 47 + #define CS_FATAL BIT(30) 48 + #define CS_FAULT BIT(31) 49 + #define CS_REQ_MASK (CS_STATE_MASK | \ 50 + CS_EXTRACT_EVENT | \ 51 + CS_IDLE_SYNC_WAIT | \ 52 + CS_IDLE_PROTM_PENDING | \ 53 + CS_IDLE_EMPTY | \ 54 + CS_IDLE_RESOURCE_REQ) 55 + #define CS_EVT_MASK (CS_TILER_OOM | \ 56 + CS_PROTM_PENDING | \ 57 + CS_FATAL | \ 58 + CS_FAULT) 59 + u32 req; 60 + 61 + #define CS_CONFIG_PRIORITY(x) ((x) & GENMASK(3, 0)) 62 + #define CS_CONFIG_DOORBELL(x) (((x) << 8) & GENMASK(15, 8)) 63 + u32 config; 64 + u32 reserved1; 65 + u32 ack_irq_mask; 66 + u64 ringbuf_base; 67 + u32 ringbuf_size; 68 + u32 reserved2; 69 + u64 heap_start; 70 + u64 heap_end; 71 + u64 ringbuf_input; 72 + u64 ringbuf_output; 73 + u32 instr_config; 74 + u32 instrbuf_size; 75 + u64 instrbuf_base; 76 + u64 instrbuf_offset_ptr; 77 + }; 78 + 79 + struct panthor_fw_cs_output_iface { 80 + u32 ack; 81 + u32 reserved1[15]; 82 + u64 status_cmd_ptr; 83 + 84 + #define CS_STATUS_WAIT_SB_MASK GENMASK(15, 0) 85 + #define CS_STATUS_WAIT_SB_SRC_MASK GENMASK(19, 16) 86 + #define CS_STATUS_WAIT_SB_SRC_NONE (0 << 16) 87 + #define CS_STATUS_WAIT_SB_SRC_WAIT (8 << 16) 88 + #define CS_STATUS_WAIT_SYNC_COND_LE (0 << 24) 89 + #define CS_STATUS_WAIT_SYNC_COND_GT (1 << 24) 90 + #define CS_STATUS_WAIT_SYNC_COND_MASK GENMASK(27, 24) 91 + #define CS_STATUS_WAIT_PROGRESS BIT(28) 92 + #define CS_STATUS_WAIT_PROTM BIT(29) 93 + #define CS_STATUS_WAIT_SYNC_64B BIT(30) 94 + #define CS_STATUS_WAIT_SYNC BIT(31) 95 + u32 status_wait; 96 + u32 status_req_resource; 97 + u64 status_wait_sync_ptr; 98 + u32 status_wait_sync_value; 99 + u32 status_scoreboards; 100 + 101 + #define CS_STATUS_BLOCKED_REASON_UNBLOCKED 0 102 + #define CS_STATUS_BLOCKED_REASON_SB_WAIT 1 103 + #define CS_STATUS_BLOCKED_REASON_PROGRESS_WAIT 2 104 + #define CS_STATUS_BLOCKED_REASON_SYNC_WAIT 3 105 + #define CS_STATUS_BLOCKED_REASON_DEFERRED 5 106 + #define CS_STATUS_BLOCKED_REASON_RES 6 107 + #define CS_STATUS_BLOCKED_REASON_FLUSH 7 108 + #define CS_STATUS_BLOCKED_REASON_MASK GENMASK(3, 0) 109 + u32 status_blocked_reason; 110 + u32 status_wait_sync_value_hi; 111 + u32 reserved2[6]; 112 + 113 + #define CS_EXCEPTION_TYPE(x) ((x) & GENMASK(7, 0)) 114 + #define CS_EXCEPTION_DATA(x) (((x) >> 8) & GENMASK(23, 0)) 115 + u32 fault; 116 + u32 fatal; 117 + u64 fault_info; 118 + u64 fatal_info; 119 + u32 reserved3[10]; 120 + u32 heap_vt_start; 121 + u32 heap_vt_end; 122 + u32 reserved4; 123 + u32 heap_frag_end; 124 + u64 heap_address; 125 + }; 126 + 127 + struct panthor_fw_csg_control_iface { 128 + u32 features; 129 + u32 input_va; 130 + u32 output_va; 131 + u32 suspend_size; 132 + u32 protm_suspend_size; 133 + u32 stream_num; 134 + u32 stream_stride; 135 + }; 136 + 137 + struct panthor_fw_csg_input_iface { 138 + #define CSG_STATE_MASK GENMASK(2, 0) 139 + #define CSG_STATE_TERMINATE 0 140 + #define CSG_STATE_START 1 141 + #define CSG_STATE_SUSPEND 2 142 + #define CSG_STATE_RESUME 3 143 + #define CSG_ENDPOINT_CONFIG BIT(4) 144 + #define CSG_STATUS_UPDATE BIT(5) 145 + #define CSG_SYNC_UPDATE BIT(28) 146 + #define CSG_IDLE BIT(29) 147 + #define CSG_DOORBELL BIT(30) 148 + #define CSG_PROGRESS_TIMER_EVENT BIT(31) 149 + #define CSG_REQ_MASK (CSG_STATE_MASK | \ 150 + CSG_ENDPOINT_CONFIG | \ 151 + CSG_STATUS_UPDATE) 152 + #define CSG_EVT_MASK (CSG_SYNC_UPDATE | \ 153 + CSG_IDLE | \ 154 + CSG_PROGRESS_TIMER_EVENT) 155 + u32 req; 156 + u32 ack_irq_mask; 157 + 158 + u32 doorbell_req; 159 + u32 cs_irq_ack; 160 + u32 reserved1[4]; 161 + u64 allow_compute; 162 + u64 allow_fragment; 163 + u32 allow_other; 164 + 165 + #define CSG_EP_REQ_COMPUTE(x) ((x) & GENMASK(7, 0)) 166 + #define CSG_EP_REQ_FRAGMENT(x) (((x) << 8) & GENMASK(15, 8)) 167 + #define CSG_EP_REQ_TILER(x) (((x) << 16) & GENMASK(19, 16)) 168 + #define CSG_EP_REQ_EXCL_COMPUTE BIT(20) 169 + #define CSG_EP_REQ_EXCL_FRAGMENT BIT(21) 170 + #define CSG_EP_REQ_PRIORITY(x) (((x) << 28) & GENMASK(31, 28)) 171 + #define CSG_EP_REQ_PRIORITY_MASK GENMASK(31, 28) 172 + u32 endpoint_req; 173 + u32 reserved2[2]; 174 + u64 suspend_buf; 175 + u64 protm_suspend_buf; 176 + u32 config; 177 + u32 iter_trace_config; 178 + }; 179 + 180 + struct panthor_fw_csg_output_iface { 181 + u32 ack; 182 + u32 reserved1; 183 + u32 doorbell_ack; 184 + u32 cs_irq_req; 185 + u32 status_endpoint_current; 186 + u32 status_endpoint_req; 187 + 188 + #define CSG_STATUS_STATE_IS_IDLE BIT(0) 189 + u32 status_state; 190 + u32 resource_dep; 191 + }; 192 + 193 + struct panthor_fw_global_control_iface { 194 + u32 version; 195 + u32 features; 196 + u32 input_va; 197 + u32 output_va; 198 + u32 group_num; 199 + u32 group_stride; 200 + u32 perfcnt_size; 201 + u32 instr_features; 202 + }; 203 + 204 + struct panthor_fw_global_input_iface { 205 + #define GLB_HALT BIT(0) 206 + #define GLB_CFG_PROGRESS_TIMER BIT(1) 207 + #define GLB_CFG_ALLOC_EN BIT(2) 208 + #define GLB_CFG_POWEROFF_TIMER BIT(3) 209 + #define GLB_PROTM_ENTER BIT(4) 210 + #define GLB_PERFCNT_EN BIT(5) 211 + #define GLB_PERFCNT_SAMPLE BIT(6) 212 + #define GLB_COUNTER_EN BIT(7) 213 + #define GLB_PING BIT(8) 214 + #define GLB_FWCFG_UPDATE BIT(9) 215 + #define GLB_IDLE_EN BIT(10) 216 + #define GLB_SLEEP BIT(12) 217 + #define GLB_INACTIVE_COMPUTE BIT(20) 218 + #define GLB_INACTIVE_FRAGMENT BIT(21) 219 + #define GLB_INACTIVE_TILER BIT(22) 220 + #define GLB_PROTM_EXIT BIT(23) 221 + #define GLB_PERFCNT_THRESHOLD BIT(24) 222 + #define GLB_PERFCNT_OVERFLOW BIT(25) 223 + #define GLB_IDLE BIT(26) 224 + #define GLB_DBG_CSF BIT(30) 225 + #define GLB_DBG_HOST BIT(31) 226 + #define GLB_REQ_MASK GENMASK(10, 0) 227 + #define GLB_EVT_MASK GENMASK(26, 20) 228 + u32 req; 229 + u32 ack_irq_mask; 230 + u32 doorbell_req; 231 + u32 reserved1; 232 + u32 progress_timer; 233 + 234 + #define GLB_TIMER_VAL(x) ((x) & GENMASK(30, 0)) 235 + #define GLB_TIMER_SOURCE_GPU_COUNTER BIT(31) 236 + u32 poweroff_timer; 237 + u64 core_en_mask; 238 + u32 reserved2; 239 + u32 perfcnt_as; 240 + u64 perfcnt_base; 241 + u32 perfcnt_extract; 242 + u32 reserved3[3]; 243 + u32 perfcnt_config; 244 + u32 perfcnt_csg_select; 245 + u32 perfcnt_fw_enable; 246 + u32 perfcnt_csg_enable; 247 + u32 perfcnt_csf_enable; 248 + u32 perfcnt_shader_enable; 249 + u32 perfcnt_tiler_enable; 250 + u32 perfcnt_mmu_l2_enable; 251 + u32 reserved4[8]; 252 + u32 idle_timer; 253 + }; 254 + 255 + enum panthor_fw_halt_status { 256 + PANTHOR_FW_HALT_OK = 0, 257 + PANTHOR_FW_HALT_ON_PANIC = 0x4e, 258 + PANTHOR_FW_HALT_ON_WATCHDOG_EXPIRATION = 0x4f, 259 + }; 260 + 261 + struct panthor_fw_global_output_iface { 262 + u32 ack; 263 + u32 reserved1; 264 + u32 doorbell_ack; 265 + u32 reserved2; 266 + u32 halt_status; 267 + u32 perfcnt_status; 268 + u32 perfcnt_insert; 269 + }; 270 + 271 + /** 272 + * struct panthor_fw_cs_iface - Firmware command stream slot interface 273 + */ 274 + struct panthor_fw_cs_iface { 275 + /** 276 + * @lock: Lock protecting access to the panthor_fw_cs_input_iface::req 277 + * field. 278 + * 279 + * Needed so we can update the req field concurrently from the interrupt 280 + * handler and the scheduler logic. 281 + * 282 + * TODO: Ideally we'd want to use a cmpxchg() to update the req, but FW 283 + * interface sections are mapped uncached/write-combined right now, and 284 + * using cmpxchg() on such mappings leads to SError faults. Revisit when 285 + * we have 'SHARED' GPU mappings hooked up. 286 + */ 287 + spinlock_t lock; 288 + 289 + /** 290 + * @control: Command stream slot control interface. 291 + * 292 + * Used to expose command stream slot properties. 293 + * 294 + * This interface is read-only. 295 + */ 296 + struct panthor_fw_cs_control_iface *control; 297 + 298 + /** 299 + * @input: Command stream slot input interface. 300 + * 301 + * Used for host updates/events. 302 + */ 303 + struct panthor_fw_cs_input_iface *input; 304 + 305 + /** 306 + * @output: Command stream slot output interface. 307 + * 308 + * Used for FW updates/events. 309 + * 310 + * This interface is read-only. 311 + */ 312 + const struct panthor_fw_cs_output_iface *output; 313 + }; 314 + 315 + /** 316 + * struct panthor_fw_csg_iface - Firmware command stream group slot interface 317 + */ 318 + struct panthor_fw_csg_iface { 319 + /** 320 + * @lock: Lock protecting access to the panthor_fw_csg_input_iface::req 321 + * field. 322 + * 323 + * Needed so we can update the req field concurrently from the interrupt 324 + * handler and the scheduler logic. 325 + * 326 + * TODO: Ideally we'd want to use a cmpxchg() to update the req, but FW 327 + * interface sections are mapped uncached/write-combined right now, and 328 + * using cmpxchg() on such mappings leads to SError faults. Revisit when 329 + * we have 'SHARED' GPU mappings hooked up. 330 + */ 331 + spinlock_t lock; 332 + 333 + /** 334 + * @control: Command stream group slot control interface. 335 + * 336 + * Used to expose command stream group slot properties. 337 + * 338 + * This interface is read-only. 339 + */ 340 + const struct panthor_fw_csg_control_iface *control; 341 + 342 + /** 343 + * @input: Command stream slot input interface. 344 + * 345 + * Used for host updates/events. 346 + */ 347 + struct panthor_fw_csg_input_iface *input; 348 + 349 + /** 350 + * @output: Command stream group slot output interface. 351 + * 352 + * Used for FW updates/events. 353 + * 354 + * This interface is read-only. 355 + */ 356 + const struct panthor_fw_csg_output_iface *output; 357 + }; 358 + 359 + /** 360 + * struct panthor_fw_global_iface - Firmware global interface 361 + */ 362 + struct panthor_fw_global_iface { 363 + /** 364 + * @lock: Lock protecting access to the panthor_fw_global_input_iface::req 365 + * field. 366 + * 367 + * Needed so we can update the req field concurrently from the interrupt 368 + * handler and the scheduler/FW management logic. 369 + * 370 + * TODO: Ideally we'd want to use a cmpxchg() to update the req, but FW 371 + * interface sections are mapped uncached/write-combined right now, and 372 + * using cmpxchg() on such mappings leads to SError faults. Revisit when 373 + * we have 'SHARED' GPU mappings hooked up. 374 + */ 375 + spinlock_t lock; 376 + 377 + /** 378 + * @control: Command stream group slot control interface. 379 + * 380 + * Used to expose global FW properties. 381 + * 382 + * This interface is read-only. 383 + */ 384 + const struct panthor_fw_global_control_iface *control; 385 + 386 + /** 387 + * @input: Global input interface. 388 + * 389 + * Used for host updates/events. 390 + */ 391 + struct panthor_fw_global_input_iface *input; 392 + 393 + /** 394 + * @output: Global output interface. 395 + * 396 + * Used for FW updates/events. 397 + * 398 + * This interface is read-only. 399 + */ 400 + const struct panthor_fw_global_output_iface *output; 401 + }; 402 + 403 + /** 404 + * panthor_fw_toggle_reqs() - Toggle acknowledge bits to send an event to the FW 405 + * @__iface: The interface to operate on. 406 + * @__in_reg: Name of the register to update in the input section of the interface. 407 + * @__out_reg: Name of the register to take as a reference in the output section of the 408 + * interface. 409 + * @__mask: Mask to apply to the update. 410 + * 411 + * The Host -> FW event/message passing was designed to be lockless, with each side of 412 + * the channel having its writeable section. Events are signaled as a difference between 413 + * the host and FW side in the req/ack registers (when a bit differs, there's an event 414 + * pending, when they are the same, nothing needs attention). 415 + * 416 + * This helper allows one to update the req register based on the current value of the 417 + * ack register managed by the FW. Toggling a specific bit will flag an event. In order 418 + * for events to be re-evaluated, the interface doorbell needs to be rung. 419 + * 420 + * Concurrent accesses to the same req register is covered. 421 + * 422 + * Anything requiring atomic updates to multiple registers requires a dedicated lock. 423 + */ 424 + #define panthor_fw_toggle_reqs(__iface, __in_reg, __out_reg, __mask) \ 425 + do { \ 426 + u32 __cur_val, __new_val, __out_val; \ 427 + spin_lock(&(__iface)->lock); \ 428 + __cur_val = READ_ONCE((__iface)->input->__in_reg); \ 429 + __out_val = READ_ONCE((__iface)->output->__out_reg); \ 430 + __new_val = ((__out_val ^ (__mask)) & (__mask)) | (__cur_val & ~(__mask)); \ 431 + WRITE_ONCE((__iface)->input->__in_reg, __new_val); \ 432 + spin_unlock(&(__iface)->lock); \ 433 + } while (0) 434 + 435 + /** 436 + * panthor_fw_update_reqs() - Update bits to reflect a configuration change 437 + * @__iface: The interface to operate on. 438 + * @__in_reg: Name of the register to update in the input section of the interface. 439 + * @__val: Value to set. 440 + * @__mask: Mask to apply to the update. 441 + * 442 + * Some configuration get passed through req registers that are also used to 443 + * send events to the FW. Those req registers being updated from the interrupt 444 + * handler, they require special helpers to update the configuration part as well. 445 + * 446 + * Concurrent accesses to the same req register is covered. 447 + * 448 + * Anything requiring atomic updates to multiple registers requires a dedicated lock. 449 + */ 450 + #define panthor_fw_update_reqs(__iface, __in_reg, __val, __mask) \ 451 + do { \ 452 + u32 __cur_val, __new_val; \ 453 + spin_lock(&(__iface)->lock); \ 454 + __cur_val = READ_ONCE((__iface)->input->__in_reg); \ 455 + __new_val = (__cur_val & ~(__mask)) | ((__val) & (__mask)); \ 456 + WRITE_ONCE((__iface)->input->__in_reg, __new_val); \ 457 + spin_unlock(&(__iface)->lock); \ 458 + } while (0) 459 + 460 + struct panthor_fw_global_iface * 461 + panthor_fw_get_glb_iface(struct panthor_device *ptdev); 462 + 463 + struct panthor_fw_csg_iface * 464 + panthor_fw_get_csg_iface(struct panthor_device *ptdev, u32 csg_slot); 465 + 466 + struct panthor_fw_cs_iface * 467 + panthor_fw_get_cs_iface(struct panthor_device *ptdev, u32 csg_slot, u32 cs_slot); 468 + 469 + int panthor_fw_csg_wait_acks(struct panthor_device *ptdev, u32 csg_id, u32 req_mask, 470 + u32 *acked, u32 timeout_ms); 471 + 472 + int panthor_fw_glb_wait_acks(struct panthor_device *ptdev, u32 req_mask, u32 *acked, 473 + u32 timeout_ms); 474 + 475 + void panthor_fw_ring_csg_doorbells(struct panthor_device *ptdev, u32 csg_slot); 476 + 477 + struct panthor_kernel_bo * 478 + panthor_fw_alloc_queue_iface_mem(struct panthor_device *ptdev, 479 + struct panthor_fw_ringbuf_input_iface **input, 480 + const struct panthor_fw_ringbuf_output_iface **output, 481 + u32 *input_fw_va, u32 *output_fw_va); 482 + struct panthor_kernel_bo * 483 + panthor_fw_alloc_suspend_buf_mem(struct panthor_device *ptdev, size_t size); 484 + 485 + struct panthor_vm *panthor_fw_vm(struct panthor_device *ptdev); 486 + 487 + void panthor_fw_pre_reset(struct panthor_device *ptdev, bool on_hang); 488 + int panthor_fw_post_reset(struct panthor_device *ptdev); 489 + 490 + static inline void panthor_fw_suspend(struct panthor_device *ptdev) 491 + { 492 + panthor_fw_pre_reset(ptdev, false); 493 + } 494 + 495 + static inline int panthor_fw_resume(struct panthor_device *ptdev) 496 + { 497 + return panthor_fw_post_reset(ptdev); 498 + } 499 + 500 + int panthor_fw_init(struct panthor_device *ptdev); 501 + void panthor_fw_unplug(struct panthor_device *ptdev); 502 + 503 + #endif
+230
drivers/gpu/drm/panthor/panthor_gem.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 3 + /* Copyright 2023 Collabora ltd. */ 4 + 5 + #include <linux/dma-buf.h> 6 + #include <linux/dma-mapping.h> 7 + #include <linux/err.h> 8 + #include <linux/slab.h> 9 + 10 + #include <drm/panthor_drm.h> 11 + 12 + #include "panthor_device.h" 13 + #include "panthor_gem.h" 14 + #include "panthor_mmu.h" 15 + 16 + static void panthor_gem_free_object(struct drm_gem_object *obj) 17 + { 18 + struct panthor_gem_object *bo = to_panthor_bo(obj); 19 + struct drm_gem_object *vm_root_gem = bo->exclusive_vm_root_gem; 20 + 21 + drm_gem_free_mmap_offset(&bo->base.base); 22 + mutex_destroy(&bo->gpuva_list_lock); 23 + drm_gem_shmem_free(&bo->base); 24 + drm_gem_object_put(vm_root_gem); 25 + } 26 + 27 + /** 28 + * panthor_kernel_bo_destroy() - Destroy a kernel buffer object 29 + * @vm: The VM this BO was mapped to. 30 + * @bo: Kernel buffer object to destroy. If NULL or an ERR_PTR(), the destruction 31 + * is skipped. 32 + */ 33 + void panthor_kernel_bo_destroy(struct panthor_vm *vm, 34 + struct panthor_kernel_bo *bo) 35 + { 36 + int ret; 37 + 38 + if (IS_ERR_OR_NULL(bo)) 39 + return; 40 + 41 + panthor_kernel_bo_vunmap(bo); 42 + 43 + if (drm_WARN_ON(bo->obj->dev, 44 + to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm))) 45 + goto out_free_bo; 46 + 47 + ret = panthor_vm_unmap_range(vm, bo->va_node.start, 48 + panthor_kernel_bo_size(bo)); 49 + if (ret) 50 + goto out_free_bo; 51 + 52 + panthor_vm_free_va(vm, &bo->va_node); 53 + drm_gem_object_put(bo->obj); 54 + 55 + out_free_bo: 56 + kfree(bo); 57 + } 58 + 59 + /** 60 + * panthor_kernel_bo_create() - Create and map a GEM object to a VM 61 + * @ptdev: Device. 62 + * @vm: VM to map the GEM to. If NULL, the kernel object is not GPU mapped. 63 + * @size: Size of the buffer object. 64 + * @bo_flags: Combination of drm_panthor_bo_flags flags. 65 + * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those 66 + * that are related to map operations). 67 + * @gpu_va: GPU address assigned when mapping to the VM. 68 + * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be 69 + * automatically allocated. 70 + * 71 + * Return: A valid pointer in case of success, an ERR_PTR() otherwise. 72 + */ 73 + struct panthor_kernel_bo * 74 + panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, 75 + size_t size, u32 bo_flags, u32 vm_map_flags, 76 + u64 gpu_va) 77 + { 78 + struct drm_gem_shmem_object *obj; 79 + struct panthor_kernel_bo *kbo; 80 + struct panthor_gem_object *bo; 81 + int ret; 82 + 83 + if (drm_WARN_ON(&ptdev->base, !vm)) 84 + return ERR_PTR(-EINVAL); 85 + 86 + kbo = kzalloc(sizeof(*kbo), GFP_KERNEL); 87 + if (!kbo) 88 + return ERR_PTR(-ENOMEM); 89 + 90 + obj = drm_gem_shmem_create(&ptdev->base, size); 91 + if (IS_ERR(obj)) { 92 + ret = PTR_ERR(obj); 93 + goto err_free_bo; 94 + } 95 + 96 + bo = to_panthor_bo(&obj->base); 97 + size = obj->base.size; 98 + kbo->obj = &obj->base; 99 + bo->flags = bo_flags; 100 + 101 + ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node); 102 + if (ret) 103 + goto err_put_obj; 104 + 105 + ret = panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_map_flags); 106 + if (ret) 107 + goto err_free_va; 108 + 109 + bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm); 110 + drm_gem_object_get(bo->exclusive_vm_root_gem); 111 + bo->base.base.resv = bo->exclusive_vm_root_gem->resv; 112 + return kbo; 113 + 114 + err_free_va: 115 + panthor_vm_free_va(vm, &kbo->va_node); 116 + 117 + err_put_obj: 118 + drm_gem_object_put(&obj->base); 119 + 120 + err_free_bo: 121 + kfree(kbo); 122 + return ERR_PTR(ret); 123 + } 124 + 125 + static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) 126 + { 127 + struct panthor_gem_object *bo = to_panthor_bo(obj); 128 + 129 + /* Don't allow mmap on objects that have the NO_MMAP flag set. */ 130 + if (bo->flags & DRM_PANTHOR_BO_NO_MMAP) 131 + return -EINVAL; 132 + 133 + return drm_gem_shmem_object_mmap(obj, vma); 134 + } 135 + 136 + static struct dma_buf * 137 + panthor_gem_prime_export(struct drm_gem_object *obj, int flags) 138 + { 139 + /* We can't export GEMs that have an exclusive VM. */ 140 + if (to_panthor_bo(obj)->exclusive_vm_root_gem) 141 + return ERR_PTR(-EINVAL); 142 + 143 + return drm_gem_prime_export(obj, flags); 144 + } 145 + 146 + static const struct drm_gem_object_funcs panthor_gem_funcs = { 147 + .free = panthor_gem_free_object, 148 + .print_info = drm_gem_shmem_object_print_info, 149 + .pin = drm_gem_shmem_object_pin, 150 + .unpin = drm_gem_shmem_object_unpin, 151 + .get_sg_table = drm_gem_shmem_object_get_sg_table, 152 + .vmap = drm_gem_shmem_object_vmap, 153 + .vunmap = drm_gem_shmem_object_vunmap, 154 + .mmap = panthor_gem_mmap, 155 + .export = panthor_gem_prime_export, 156 + .vm_ops = &drm_gem_shmem_vm_ops, 157 + }; 158 + 159 + /** 160 + * panthor_gem_create_object - Implementation of driver->gem_create_object. 161 + * @ddev: DRM device 162 + * @size: Size in bytes of the memory the object will reference 163 + * 164 + * This lets the GEM helpers allocate object structs for us, and keep 165 + * our BO stats correct. 166 + */ 167 + struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size) 168 + { 169 + struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); 170 + struct panthor_gem_object *obj; 171 + 172 + obj = kzalloc(sizeof(*obj), GFP_KERNEL); 173 + if (!obj) 174 + return ERR_PTR(-ENOMEM); 175 + 176 + obj->base.base.funcs = &panthor_gem_funcs; 177 + obj->base.map_wc = !ptdev->coherent; 178 + mutex_init(&obj->gpuva_list_lock); 179 + drm_gem_gpuva_set_lock(&obj->base.base, &obj->gpuva_list_lock); 180 + 181 + return &obj->base.base; 182 + } 183 + 184 + /** 185 + * panthor_gem_create_with_handle() - Create a GEM object and attach it to a handle. 186 + * @file: DRM file. 187 + * @ddev: DRM device. 188 + * @exclusive_vm: Exclusive VM. Not NULL if the GEM object can't be shared. 189 + * @size: Size of the GEM object to allocate. 190 + * @flags: Combination of drm_panthor_bo_flags flags. 191 + * @handle: Pointer holding the handle pointing to the new GEM object. 192 + * 193 + * Return: Zero on success 194 + */ 195 + int 196 + panthor_gem_create_with_handle(struct drm_file *file, 197 + struct drm_device *ddev, 198 + struct panthor_vm *exclusive_vm, 199 + u64 *size, u32 flags, u32 *handle) 200 + { 201 + int ret; 202 + struct drm_gem_shmem_object *shmem; 203 + struct panthor_gem_object *bo; 204 + 205 + shmem = drm_gem_shmem_create(ddev, *size); 206 + if (IS_ERR(shmem)) 207 + return PTR_ERR(shmem); 208 + 209 + bo = to_panthor_bo(&shmem->base); 210 + bo->flags = flags; 211 + 212 + if (exclusive_vm) { 213 + bo->exclusive_vm_root_gem = panthor_vm_root_gem(exclusive_vm); 214 + drm_gem_object_get(bo->exclusive_vm_root_gem); 215 + bo->base.base.resv = bo->exclusive_vm_root_gem->resv; 216 + } 217 + 218 + /* 219 + * Allocate an id of idr table where the obj is registered 220 + * and handle has the id what user can see. 221 + */ 222 + ret = drm_gem_handle_create(file, &shmem->base, handle); 223 + if (!ret) 224 + *size = bo->base.base.size; 225 + 226 + /* drop reference from allocate - handle holds it now. */ 227 + drm_gem_object_put(&shmem->base); 228 + 229 + return ret; 230 + }
+142
drivers/gpu/drm/panthor/panthor_gem.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 3 + /* Copyright 2023 Collabora ltd. */ 4 + 5 + #ifndef __PANTHOR_GEM_H__ 6 + #define __PANTHOR_GEM_H__ 7 + 8 + #include <drm/drm_gem_shmem_helper.h> 9 + #include <drm/drm_mm.h> 10 + 11 + #include <linux/iosys-map.h> 12 + #include <linux/rwsem.h> 13 + 14 + struct panthor_vm; 15 + 16 + /** 17 + * struct panthor_gem_object - Driver specific GEM object. 18 + */ 19 + struct panthor_gem_object { 20 + /** @base: Inherit from drm_gem_shmem_object. */ 21 + struct drm_gem_shmem_object base; 22 + 23 + /** 24 + * @exclusive_vm_root_gem: Root GEM of the exclusive VM this GEM object 25 + * is attached to. 26 + * 27 + * If @exclusive_vm_root_gem != NULL, any attempt to bind the GEM to a 28 + * different VM will fail. 29 + * 30 + * All FW memory objects have this field set to the root GEM of the MCU 31 + * VM. 32 + */ 33 + struct drm_gem_object *exclusive_vm_root_gem; 34 + 35 + /** 36 + * @gpuva_list_lock: Custom GPUVA lock. 37 + * 38 + * Used to protect insertion of drm_gpuva elements to the 39 + * drm_gem_object.gpuva.list list. 40 + * 41 + * We can't use the GEM resv for that, because drm_gpuva_link() is 42 + * called in a dma-signaling path, where we're not allowed to take 43 + * resv locks. 44 + */ 45 + struct mutex gpuva_list_lock; 46 + 47 + /** @flags: Combination of drm_panthor_bo_flags flags. */ 48 + u32 flags; 49 + }; 50 + 51 + /** 52 + * struct panthor_kernel_bo - Kernel buffer object. 53 + * 54 + * These objects are only manipulated by the kernel driver and not 55 + * directly exposed to the userspace. The GPU address of a kernel 56 + * BO might be passed to userspace though. 57 + */ 58 + struct panthor_kernel_bo { 59 + /** 60 + * @obj: The GEM object backing this kernel buffer object. 61 + */ 62 + struct drm_gem_object *obj; 63 + 64 + /** 65 + * @va_node: VA space allocated to this GEM. 66 + */ 67 + struct drm_mm_node va_node; 68 + 69 + /** 70 + * @kmap: Kernel CPU mapping of @gem. 71 + */ 72 + void *kmap; 73 + }; 74 + 75 + static inline 76 + struct panthor_gem_object *to_panthor_bo(struct drm_gem_object *obj) 77 + { 78 + return container_of(to_drm_gem_shmem_obj(obj), struct panthor_gem_object, base); 79 + } 80 + 81 + struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size); 82 + 83 + struct drm_gem_object * 84 + panthor_gem_prime_import_sg_table(struct drm_device *ddev, 85 + struct dma_buf_attachment *attach, 86 + struct sg_table *sgt); 87 + 88 + int 89 + panthor_gem_create_with_handle(struct drm_file *file, 90 + struct drm_device *ddev, 91 + struct panthor_vm *exclusive_vm, 92 + u64 *size, u32 flags, uint32_t *handle); 93 + 94 + static inline u64 95 + panthor_kernel_bo_gpuva(struct panthor_kernel_bo *bo) 96 + { 97 + return bo->va_node.start; 98 + } 99 + 100 + static inline size_t 101 + panthor_kernel_bo_size(struct panthor_kernel_bo *bo) 102 + { 103 + return bo->obj->size; 104 + } 105 + 106 + static inline int 107 + panthor_kernel_bo_vmap(struct panthor_kernel_bo *bo) 108 + { 109 + struct iosys_map map; 110 + int ret; 111 + 112 + if (bo->kmap) 113 + return 0; 114 + 115 + ret = drm_gem_vmap_unlocked(bo->obj, &map); 116 + if (ret) 117 + return ret; 118 + 119 + bo->kmap = map.vaddr; 120 + return 0; 121 + } 122 + 123 + static inline void 124 + panthor_kernel_bo_vunmap(struct panthor_kernel_bo *bo) 125 + { 126 + if (bo->kmap) { 127 + struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->kmap); 128 + 129 + drm_gem_vunmap_unlocked(bo->obj, &map); 130 + bo->kmap = NULL; 131 + } 132 + } 133 + 134 + struct panthor_kernel_bo * 135 + panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, 136 + size_t size, u32 bo_flags, u32 vm_map_flags, 137 + u64 gpu_va); 138 + 139 + void panthor_kernel_bo_destroy(struct panthor_vm *vm, 140 + struct panthor_kernel_bo *bo); 141 + 142 + #endif /* __PANTHOR_GEM_H__ */
+482
drivers/gpu/drm/panthor/panthor_gpu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 3 + /* Copyright 2019 Linaro, Ltd., Rob Herring <robh@kernel.org> */ 4 + /* Copyright 2019 Collabora ltd. */ 5 + 6 + #include <linux/bitfield.h> 7 + #include <linux/bitmap.h> 8 + #include <linux/delay.h> 9 + #include <linux/dma-mapping.h> 10 + #include <linux/interrupt.h> 11 + #include <linux/io.h> 12 + #include <linux/iopoll.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/pm_runtime.h> 15 + 16 + #include <drm/drm_drv.h> 17 + #include <drm/drm_managed.h> 18 + 19 + #include "panthor_device.h" 20 + #include "panthor_gpu.h" 21 + #include "panthor_regs.h" 22 + 23 + /** 24 + * struct panthor_gpu - GPU block management data. 25 + */ 26 + struct panthor_gpu { 27 + /** @irq: GPU irq. */ 28 + struct panthor_irq irq; 29 + 30 + /** @reqs_lock: Lock protecting access to pending_reqs. */ 31 + spinlock_t reqs_lock; 32 + 33 + /** @pending_reqs: Pending GPU requests. */ 34 + u32 pending_reqs; 35 + 36 + /** @reqs_acked: GPU request wait queue. */ 37 + wait_queue_head_t reqs_acked; 38 + }; 39 + 40 + /** 41 + * struct panthor_model - GPU model description 42 + */ 43 + struct panthor_model { 44 + /** @name: Model name. */ 45 + const char *name; 46 + 47 + /** @arch_major: Major version number of architecture. */ 48 + u8 arch_major; 49 + 50 + /** @product_major: Major version number of product. */ 51 + u8 product_major; 52 + }; 53 + 54 + /** 55 + * GPU_MODEL() - Define a GPU model. A GPU product can be uniquely identified 56 + * by a combination of the major architecture version and the major product 57 + * version. 58 + * @_name: Name for the GPU model. 59 + * @_arch_major: Architecture major. 60 + * @_product_major: Product major. 61 + */ 62 + #define GPU_MODEL(_name, _arch_major, _product_major) \ 63 + {\ 64 + .name = __stringify(_name), \ 65 + .arch_major = _arch_major, \ 66 + .product_major = _product_major, \ 67 + } 68 + 69 + static const struct panthor_model gpu_models[] = { 70 + GPU_MODEL(g610, 10, 7), 71 + {}, 72 + }; 73 + 74 + #define GPU_INTERRUPTS_MASK \ 75 + (GPU_IRQ_FAULT | \ 76 + GPU_IRQ_PROTM_FAULT | \ 77 + GPU_IRQ_RESET_COMPLETED | \ 78 + GPU_IRQ_CLEAN_CACHES_COMPLETED) 79 + 80 + static void panthor_gpu_init_info(struct panthor_device *ptdev) 81 + { 82 + const struct panthor_model *model; 83 + u32 arch_major, product_major; 84 + u32 major, minor, status; 85 + unsigned int i; 86 + 87 + ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID); 88 + ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID); 89 + ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID); 90 + ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES); 91 + ptdev->gpu_info.l2_features = gpu_read(ptdev, GPU_L2_FEATURES); 92 + ptdev->gpu_info.tiler_features = gpu_read(ptdev, GPU_TILER_FEATURES); 93 + ptdev->gpu_info.mem_features = gpu_read(ptdev, GPU_MEM_FEATURES); 94 + ptdev->gpu_info.mmu_features = gpu_read(ptdev, GPU_MMU_FEATURES); 95 + ptdev->gpu_info.thread_features = gpu_read(ptdev, GPU_THREAD_FEATURES); 96 + ptdev->gpu_info.max_threads = gpu_read(ptdev, GPU_THREAD_MAX_THREADS); 97 + ptdev->gpu_info.thread_max_workgroup_size = gpu_read(ptdev, GPU_THREAD_MAX_WORKGROUP_SIZE); 98 + ptdev->gpu_info.thread_max_barrier_size = gpu_read(ptdev, GPU_THREAD_MAX_BARRIER_SIZE); 99 + ptdev->gpu_info.coherency_features = gpu_read(ptdev, GPU_COHERENCY_FEATURES); 100 + for (i = 0; i < 4; i++) 101 + ptdev->gpu_info.texture_features[i] = gpu_read(ptdev, GPU_TEXTURE_FEATURES(i)); 102 + 103 + ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT); 104 + 105 + ptdev->gpu_info.shader_present = gpu_read(ptdev, GPU_SHADER_PRESENT_LO); 106 + ptdev->gpu_info.shader_present |= (u64)gpu_read(ptdev, GPU_SHADER_PRESENT_HI) << 32; 107 + 108 + ptdev->gpu_info.tiler_present = gpu_read(ptdev, GPU_TILER_PRESENT_LO); 109 + ptdev->gpu_info.tiler_present |= (u64)gpu_read(ptdev, GPU_TILER_PRESENT_HI) << 32; 110 + 111 + ptdev->gpu_info.l2_present = gpu_read(ptdev, GPU_L2_PRESENT_LO); 112 + ptdev->gpu_info.l2_present |= (u64)gpu_read(ptdev, GPU_L2_PRESENT_HI) << 32; 113 + 114 + arch_major = GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id); 115 + product_major = GPU_PROD_MAJOR(ptdev->gpu_info.gpu_id); 116 + major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id); 117 + minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id); 118 + status = GPU_VER_STATUS(ptdev->gpu_info.gpu_id); 119 + 120 + for (model = gpu_models; model->name; model++) { 121 + if (model->arch_major == arch_major && 122 + model->product_major == product_major) 123 + break; 124 + } 125 + 126 + drm_info(&ptdev->base, 127 + "mali-%s id 0x%x major 0x%x minor 0x%x status 0x%x", 128 + model->name ?: "unknown", ptdev->gpu_info.gpu_id >> 16, 129 + major, minor, status); 130 + 131 + drm_info(&ptdev->base, 132 + "Features: L2:%#x Tiler:%#x Mem:%#x MMU:%#x AS:%#x", 133 + ptdev->gpu_info.l2_features, 134 + ptdev->gpu_info.tiler_features, 135 + ptdev->gpu_info.mem_features, 136 + ptdev->gpu_info.mmu_features, 137 + ptdev->gpu_info.as_present); 138 + 139 + drm_info(&ptdev->base, 140 + "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx", 141 + ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present, 142 + ptdev->gpu_info.tiler_present); 143 + } 144 + 145 + static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) 146 + { 147 + if (status & GPU_IRQ_FAULT) { 148 + u32 fault_status = gpu_read(ptdev, GPU_FAULT_STATUS); 149 + u64 address = ((u64)gpu_read(ptdev, GPU_FAULT_ADDR_HI) << 32) | 150 + gpu_read(ptdev, GPU_FAULT_ADDR_LO); 151 + 152 + drm_warn(&ptdev->base, "GPU Fault 0x%08x (%s) at 0x%016llx\n", 153 + fault_status, panthor_exception_name(ptdev, fault_status & 0xFF), 154 + address); 155 + } 156 + if (status & GPU_IRQ_PROTM_FAULT) 157 + drm_warn(&ptdev->base, "GPU Fault in protected mode\n"); 158 + 159 + spin_lock(&ptdev->gpu->reqs_lock); 160 + if (status & ptdev->gpu->pending_reqs) { 161 + ptdev->gpu->pending_reqs &= ~status; 162 + wake_up_all(&ptdev->gpu->reqs_acked); 163 + } 164 + spin_unlock(&ptdev->gpu->reqs_lock); 165 + } 166 + PANTHOR_IRQ_HANDLER(gpu, GPU, panthor_gpu_irq_handler); 167 + 168 + /** 169 + * panthor_gpu_unplug() - Called when the GPU is unplugged. 170 + * @ptdev: Device to unplug. 171 + */ 172 + void panthor_gpu_unplug(struct panthor_device *ptdev) 173 + { 174 + unsigned long flags; 175 + 176 + /* Make sure the IRQ handler is not running after that point. */ 177 + panthor_gpu_irq_suspend(&ptdev->gpu->irq); 178 + 179 + /* Wake-up all waiters. */ 180 + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); 181 + ptdev->gpu->pending_reqs = 0; 182 + wake_up_all(&ptdev->gpu->reqs_acked); 183 + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); 184 + } 185 + 186 + /** 187 + * panthor_gpu_init() - Initialize the GPU block 188 + * @ptdev: Device. 189 + * 190 + * Return: 0 on success, a negative error code otherwise. 191 + */ 192 + int panthor_gpu_init(struct panthor_device *ptdev) 193 + { 194 + struct panthor_gpu *gpu; 195 + u32 pa_bits; 196 + int ret, irq; 197 + 198 + gpu = drmm_kzalloc(&ptdev->base, sizeof(*gpu), GFP_KERNEL); 199 + if (!gpu) 200 + return -ENOMEM; 201 + 202 + spin_lock_init(&gpu->reqs_lock); 203 + init_waitqueue_head(&gpu->reqs_acked); 204 + ptdev->gpu = gpu; 205 + panthor_gpu_init_info(ptdev); 206 + 207 + dma_set_max_seg_size(ptdev->base.dev, UINT_MAX); 208 + pa_bits = GPU_MMU_FEATURES_PA_BITS(ptdev->gpu_info.mmu_features); 209 + ret = dma_set_mask_and_coherent(ptdev->base.dev, DMA_BIT_MASK(pa_bits)); 210 + if (ret) 211 + return ret; 212 + 213 + irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "gpu"); 214 + if (irq <= 0) 215 + return ret; 216 + 217 + ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq, GPU_INTERRUPTS_MASK); 218 + if (ret) 219 + return ret; 220 + 221 + return 0; 222 + } 223 + 224 + /** 225 + * panthor_gpu_block_power_off() - Power-off a specific block of the GPU 226 + * @ptdev: Device. 227 + * @blk_name: Block name. 228 + * @pwroff_reg: Power-off register for this block. 229 + * @pwrtrans_reg: Power transition register for this block. 230 + * @mask: Sub-elements to power-off. 231 + * @timeout_us: Timeout in microseconds. 232 + * 233 + * Return: 0 on success, a negative error code otherwise. 234 + */ 235 + int panthor_gpu_block_power_off(struct panthor_device *ptdev, 236 + const char *blk_name, 237 + u32 pwroff_reg, u32 pwrtrans_reg, 238 + u64 mask, u32 timeout_us) 239 + { 240 + u32 val, i; 241 + int ret; 242 + 243 + for (i = 0; i < 2; i++) { 244 + u32 mask32 = mask >> (i * 32); 245 + 246 + if (!mask32) 247 + continue; 248 + 249 + ret = readl_relaxed_poll_timeout(ptdev->iomem + pwrtrans_reg + (i * 4), 250 + val, !(mask32 & val), 251 + 100, timeout_us); 252 + if (ret) { 253 + drm_err(&ptdev->base, "timeout waiting on %s:%llx power transition", 254 + blk_name, mask); 255 + return ret; 256 + } 257 + } 258 + 259 + if (mask & GENMASK(31, 0)) 260 + gpu_write(ptdev, pwroff_reg, mask); 261 + 262 + if (mask >> 32) 263 + gpu_write(ptdev, pwroff_reg + 4, mask >> 32); 264 + 265 + for (i = 0; i < 2; i++) { 266 + u32 mask32 = mask >> (i * 32); 267 + 268 + if (!mask32) 269 + continue; 270 + 271 + ret = readl_relaxed_poll_timeout(ptdev->iomem + pwrtrans_reg + (i * 4), 272 + val, !(mask32 & val), 273 + 100, timeout_us); 274 + if (ret) { 275 + drm_err(&ptdev->base, "timeout waiting on %s:%llx power transition", 276 + blk_name, mask); 277 + return ret; 278 + } 279 + } 280 + 281 + return 0; 282 + } 283 + 284 + /** 285 + * panthor_gpu_block_power_on() - Power-on a specific block of the GPU 286 + * @ptdev: Device. 287 + * @blk_name: Block name. 288 + * @pwron_reg: Power-on register for this block. 289 + * @pwrtrans_reg: Power transition register for this block. 290 + * @rdy_reg: Power transition ready register. 291 + * @mask: Sub-elements to power-on. 292 + * @timeout_us: Timeout in microseconds. 293 + * 294 + * Return: 0 on success, a negative error code otherwise. 295 + */ 296 + int panthor_gpu_block_power_on(struct panthor_device *ptdev, 297 + const char *blk_name, 298 + u32 pwron_reg, u32 pwrtrans_reg, 299 + u32 rdy_reg, u64 mask, u32 timeout_us) 300 + { 301 + u32 val, i; 302 + int ret; 303 + 304 + for (i = 0; i < 2; i++) { 305 + u32 mask32 = mask >> (i * 32); 306 + 307 + if (!mask32) 308 + continue; 309 + 310 + ret = readl_relaxed_poll_timeout(ptdev->iomem + pwrtrans_reg + (i * 4), 311 + val, !(mask32 & val), 312 + 100, timeout_us); 313 + if (ret) { 314 + drm_err(&ptdev->base, "timeout waiting on %s:%llx power transition", 315 + blk_name, mask); 316 + return ret; 317 + } 318 + } 319 + 320 + if (mask & GENMASK(31, 0)) 321 + gpu_write(ptdev, pwron_reg, mask); 322 + 323 + if (mask >> 32) 324 + gpu_write(ptdev, pwron_reg + 4, mask >> 32); 325 + 326 + for (i = 0; i < 2; i++) { 327 + u32 mask32 = mask >> (i * 32); 328 + 329 + if (!mask32) 330 + continue; 331 + 332 + ret = readl_relaxed_poll_timeout(ptdev->iomem + rdy_reg + (i * 4), 333 + val, (mask32 & val) == mask32, 334 + 100, timeout_us); 335 + if (ret) { 336 + drm_err(&ptdev->base, "timeout waiting on %s:%llx readiness", 337 + blk_name, mask); 338 + return ret; 339 + } 340 + } 341 + 342 + return 0; 343 + } 344 + 345 + /** 346 + * panthor_gpu_l2_power_on() - Power-on the L2-cache 347 + * @ptdev: Device. 348 + * 349 + * Return: 0 on success, a negative error code otherwise. 350 + */ 351 + int panthor_gpu_l2_power_on(struct panthor_device *ptdev) 352 + { 353 + if (ptdev->gpu_info.l2_present != 1) { 354 + /* 355 + * Only support one core group now. 356 + * ~(l2_present - 1) unsets all bits in l2_present except 357 + * the bottom bit. (l2_present - 2) has all the bits in 358 + * the first core group set. AND them together to generate 359 + * a mask of cores in the first core group. 360 + */ 361 + u64 core_mask = ~(ptdev->gpu_info.l2_present - 1) & 362 + (ptdev->gpu_info.l2_present - 2); 363 + drm_info_once(&ptdev->base, "using only 1st core group (%lu cores from %lu)\n", 364 + hweight64(core_mask), 365 + hweight64(ptdev->gpu_info.shader_present)); 366 + } 367 + 368 + return panthor_gpu_power_on(ptdev, L2, 1, 20000); 369 + } 370 + 371 + /** 372 + * panthor_gpu_flush_caches() - Flush caches 373 + * @ptdev: Device. 374 + * @l2: L2 flush type. 375 + * @lsc: LSC flush type. 376 + * @other: Other flush type. 377 + * 378 + * Return: 0 on success, a negative error code otherwise. 379 + */ 380 + int panthor_gpu_flush_caches(struct panthor_device *ptdev, 381 + u32 l2, u32 lsc, u32 other) 382 + { 383 + bool timedout = false; 384 + unsigned long flags; 385 + 386 + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); 387 + if (!drm_WARN_ON(&ptdev->base, 388 + ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) { 389 + ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED; 390 + gpu_write(ptdev, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other)); 391 + } 392 + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); 393 + 394 + if (!wait_event_timeout(ptdev->gpu->reqs_acked, 395 + !(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED), 396 + msecs_to_jiffies(100))) { 397 + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); 398 + if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 && 399 + !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED)) 400 + timedout = true; 401 + else 402 + ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED; 403 + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); 404 + } 405 + 406 + if (timedout) { 407 + drm_err(&ptdev->base, "Flush caches timeout"); 408 + return -ETIMEDOUT; 409 + } 410 + 411 + return 0; 412 + } 413 + 414 + /** 415 + * panthor_gpu_soft_reset() - Issue a soft-reset 416 + * @ptdev: Device. 417 + * 418 + * Return: 0 on success, a negative error code otherwise. 419 + */ 420 + int panthor_gpu_soft_reset(struct panthor_device *ptdev) 421 + { 422 + bool timedout = false; 423 + unsigned long flags; 424 + 425 + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); 426 + if (!drm_WARN_ON(&ptdev->base, 427 + ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) { 428 + ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED; 429 + gpu_write(ptdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); 430 + gpu_write(ptdev, GPU_CMD, GPU_SOFT_RESET); 431 + } 432 + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); 433 + 434 + if (!wait_event_timeout(ptdev->gpu->reqs_acked, 435 + !(ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED), 436 + msecs_to_jiffies(100))) { 437 + spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags); 438 + if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 && 439 + !(gpu_read(ptdev, GPU_INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED)) 440 + timedout = true; 441 + else 442 + ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED; 443 + spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags); 444 + } 445 + 446 + if (timedout) { 447 + drm_err(&ptdev->base, "Soft reset timeout"); 448 + return -ETIMEDOUT; 449 + } 450 + 451 + return 0; 452 + } 453 + 454 + /** 455 + * panthor_gpu_suspend() - Suspend the GPU block. 456 + * @ptdev: Device. 457 + * 458 + * Suspend the GPU irq. This should be called last in the suspend procedure, 459 + * after all other blocks have been suspented. 460 + */ 461 + void panthor_gpu_suspend(struct panthor_device *ptdev) 462 + { 463 + /* 464 + * It may be preferable to simply power down the L2, but for now just 465 + * soft-reset which will leave the L2 powered down. 466 + */ 467 + panthor_gpu_soft_reset(ptdev); 468 + panthor_gpu_irq_suspend(&ptdev->gpu->irq); 469 + } 470 + 471 + /** 472 + * panthor_gpu_resume() - Resume the GPU block. 473 + * @ptdev: Device. 474 + * 475 + * Resume the IRQ handler and power-on the L2-cache. 476 + * The FW takes care of powering the other blocks. 477 + */ 478 + void panthor_gpu_resume(struct panthor_device *ptdev) 479 + { 480 + panthor_gpu_irq_resume(&ptdev->gpu->irq, GPU_INTERRUPTS_MASK); 481 + panthor_gpu_l2_power_on(ptdev); 482 + }
+52
drivers/gpu/drm/panthor/panthor_gpu.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 3 + /* Copyright 2019 Collabora ltd. */ 4 + 5 + #ifndef __PANTHOR_GPU_H__ 6 + #define __PANTHOR_GPU_H__ 7 + 8 + struct panthor_device; 9 + 10 + int panthor_gpu_init(struct panthor_device *ptdev); 11 + void panthor_gpu_unplug(struct panthor_device *ptdev); 12 + void panthor_gpu_suspend(struct panthor_device *ptdev); 13 + void panthor_gpu_resume(struct panthor_device *ptdev); 14 + 15 + int panthor_gpu_block_power_on(struct panthor_device *ptdev, 16 + const char *blk_name, 17 + u32 pwron_reg, u32 pwrtrans_reg, 18 + u32 rdy_reg, u64 mask, u32 timeout_us); 19 + int panthor_gpu_block_power_off(struct panthor_device *ptdev, 20 + const char *blk_name, 21 + u32 pwroff_reg, u32 pwrtrans_reg, 22 + u64 mask, u32 timeout_us); 23 + 24 + /** 25 + * panthor_gpu_power_on() - Power on the GPU block. 26 + * 27 + * Return: 0 on success, a negative error code otherwise. 28 + */ 29 + #define panthor_gpu_power_on(ptdev, type, mask, timeout_us) \ 30 + panthor_gpu_block_power_on(ptdev, #type, \ 31 + type ## _PWRON_LO, \ 32 + type ## _PWRTRANS_LO, \ 33 + type ## _READY_LO, \ 34 + mask, timeout_us) 35 + 36 + /** 37 + * panthor_gpu_power_off() - Power off the GPU block. 38 + * 39 + * Return: 0 on success, a negative error code otherwise. 40 + */ 41 + #define panthor_gpu_power_off(ptdev, type, mask, timeout_us) \ 42 + panthor_gpu_block_power_off(ptdev, #type, \ 43 + type ## _PWROFF_LO, \ 44 + type ## _PWRTRANS_LO, \ 45 + mask, timeout_us) 46 + 47 + int panthor_gpu_l2_power_on(struct panthor_device *ptdev); 48 + int panthor_gpu_flush_caches(struct panthor_device *ptdev, 49 + u32 l2, u32 lsc, u32 other); 50 + int panthor_gpu_soft_reset(struct panthor_device *ptdev); 51 + 52 + #endif
+597
drivers/gpu/drm/panthor/panthor_heap.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2023 Collabora ltd. */ 3 + 4 + #include <linux/iosys-map.h> 5 + #include <linux/rwsem.h> 6 + 7 + #include <drm/panthor_drm.h> 8 + 9 + #include "panthor_device.h" 10 + #include "panthor_gem.h" 11 + #include "panthor_heap.h" 12 + #include "panthor_mmu.h" 13 + #include "panthor_regs.h" 14 + 15 + /* 16 + * The GPU heap context is an opaque structure used by the GPU to track the 17 + * heap allocations. The driver should only touch it to initialize it (zero all 18 + * fields). Because the CPU and GPU can both access this structure it is 19 + * required to be GPU cache line aligned. 20 + */ 21 + #define HEAP_CONTEXT_SIZE 32 22 + 23 + /** 24 + * struct panthor_heap_chunk_header - Heap chunk header 25 + */ 26 + struct panthor_heap_chunk_header { 27 + /** 28 + * @next: Next heap chunk in the list. 29 + * 30 + * This is a GPU VA. 31 + */ 32 + u64 next; 33 + 34 + /** @unknown: MBZ. */ 35 + u32 unknown[14]; 36 + }; 37 + 38 + /** 39 + * struct panthor_heap_chunk - Structure used to keep track of allocated heap chunks. 40 + */ 41 + struct panthor_heap_chunk { 42 + /** @node: Used to insert the heap chunk in panthor_heap::chunks. */ 43 + struct list_head node; 44 + 45 + /** @bo: Buffer object backing the heap chunk. */ 46 + struct panthor_kernel_bo *bo; 47 + }; 48 + 49 + /** 50 + * struct panthor_heap - Structure used to manage tiler heap contexts. 51 + */ 52 + struct panthor_heap { 53 + /** @chunks: List containing all heap chunks allocated so far. */ 54 + struct list_head chunks; 55 + 56 + /** @lock: Lock protecting insertion in the chunks list. */ 57 + struct mutex lock; 58 + 59 + /** @chunk_size: Size of each chunk. */ 60 + u32 chunk_size; 61 + 62 + /** @max_chunks: Maximum number of chunks. */ 63 + u32 max_chunks; 64 + 65 + /** 66 + * @target_in_flight: Number of in-flight render passes after which 67 + * we'd let the FW wait for fragment job to finish instead of allocating new chunks. 68 + */ 69 + u32 target_in_flight; 70 + 71 + /** @chunk_count: Number of heap chunks currently allocated. */ 72 + u32 chunk_count; 73 + }; 74 + 75 + #define MAX_HEAPS_PER_POOL 128 76 + 77 + /** 78 + * struct panthor_heap_pool - Pool of heap contexts 79 + * 80 + * The pool is attached to a panthor_file and can't be shared across processes. 81 + */ 82 + struct panthor_heap_pool { 83 + /** @refcount: Reference count. */ 84 + struct kref refcount; 85 + 86 + /** @ptdev: Device. */ 87 + struct panthor_device *ptdev; 88 + 89 + /** @vm: VM this pool is bound to. */ 90 + struct panthor_vm *vm; 91 + 92 + /** @lock: Lock protecting access to @xa. */ 93 + struct rw_semaphore lock; 94 + 95 + /** @xa: Array storing panthor_heap objects. */ 96 + struct xarray xa; 97 + 98 + /** @gpu_contexts: Buffer object containing the GPU heap contexts. */ 99 + struct panthor_kernel_bo *gpu_contexts; 100 + }; 101 + 102 + static int panthor_heap_ctx_stride(struct panthor_device *ptdev) 103 + { 104 + u32 l2_features = ptdev->gpu_info.l2_features; 105 + u32 gpu_cache_line_size = GPU_L2_FEATURES_LINE_SIZE(l2_features); 106 + 107 + return ALIGN(HEAP_CONTEXT_SIZE, gpu_cache_line_size); 108 + } 109 + 110 + static int panthor_get_heap_ctx_offset(struct panthor_heap_pool *pool, int id) 111 + { 112 + return panthor_heap_ctx_stride(pool->ptdev) * id; 113 + } 114 + 115 + static void *panthor_get_heap_ctx(struct panthor_heap_pool *pool, int id) 116 + { 117 + return pool->gpu_contexts->kmap + 118 + panthor_get_heap_ctx_offset(pool, id); 119 + } 120 + 121 + static void panthor_free_heap_chunk(struct panthor_vm *vm, 122 + struct panthor_heap *heap, 123 + struct panthor_heap_chunk *chunk) 124 + { 125 + mutex_lock(&heap->lock); 126 + list_del(&chunk->node); 127 + heap->chunk_count--; 128 + mutex_unlock(&heap->lock); 129 + 130 + panthor_kernel_bo_destroy(vm, chunk->bo); 131 + kfree(chunk); 132 + } 133 + 134 + static int panthor_alloc_heap_chunk(struct panthor_device *ptdev, 135 + struct panthor_vm *vm, 136 + struct panthor_heap *heap, 137 + bool initial_chunk) 138 + { 139 + struct panthor_heap_chunk *chunk; 140 + struct panthor_heap_chunk_header *hdr; 141 + int ret; 142 + 143 + chunk = kmalloc(sizeof(*chunk), GFP_KERNEL); 144 + if (!chunk) 145 + return -ENOMEM; 146 + 147 + chunk->bo = panthor_kernel_bo_create(ptdev, vm, heap->chunk_size, 148 + DRM_PANTHOR_BO_NO_MMAP, 149 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, 150 + PANTHOR_VM_KERNEL_AUTO_VA); 151 + if (IS_ERR(chunk->bo)) { 152 + ret = PTR_ERR(chunk->bo); 153 + goto err_free_chunk; 154 + } 155 + 156 + ret = panthor_kernel_bo_vmap(chunk->bo); 157 + if (ret) 158 + goto err_destroy_bo; 159 + 160 + hdr = chunk->bo->kmap; 161 + memset(hdr, 0, sizeof(*hdr)); 162 + 163 + if (initial_chunk && !list_empty(&heap->chunks)) { 164 + struct panthor_heap_chunk *prev_chunk; 165 + u64 prev_gpuva; 166 + 167 + prev_chunk = list_first_entry(&heap->chunks, 168 + struct panthor_heap_chunk, 169 + node); 170 + 171 + prev_gpuva = panthor_kernel_bo_gpuva(prev_chunk->bo); 172 + hdr->next = (prev_gpuva & GENMASK_ULL(63, 12)) | 173 + (heap->chunk_size >> 12); 174 + } 175 + 176 + panthor_kernel_bo_vunmap(chunk->bo); 177 + 178 + mutex_lock(&heap->lock); 179 + list_add(&chunk->node, &heap->chunks); 180 + heap->chunk_count++; 181 + mutex_unlock(&heap->lock); 182 + 183 + return 0; 184 + 185 + err_destroy_bo: 186 + panthor_kernel_bo_destroy(vm, chunk->bo); 187 + 188 + err_free_chunk: 189 + kfree(chunk); 190 + 191 + return ret; 192 + } 193 + 194 + static void panthor_free_heap_chunks(struct panthor_vm *vm, 195 + struct panthor_heap *heap) 196 + { 197 + struct panthor_heap_chunk *chunk, *tmp; 198 + 199 + list_for_each_entry_safe(chunk, tmp, &heap->chunks, node) 200 + panthor_free_heap_chunk(vm, heap, chunk); 201 + } 202 + 203 + static int panthor_alloc_heap_chunks(struct panthor_device *ptdev, 204 + struct panthor_vm *vm, 205 + struct panthor_heap *heap, 206 + u32 chunk_count) 207 + { 208 + int ret; 209 + u32 i; 210 + 211 + for (i = 0; i < chunk_count; i++) { 212 + ret = panthor_alloc_heap_chunk(ptdev, vm, heap, true); 213 + if (ret) 214 + return ret; 215 + } 216 + 217 + return 0; 218 + } 219 + 220 + static int 221 + panthor_heap_destroy_locked(struct panthor_heap_pool *pool, u32 handle) 222 + { 223 + struct panthor_heap *heap; 224 + 225 + heap = xa_erase(&pool->xa, handle); 226 + if (!heap) 227 + return -EINVAL; 228 + 229 + panthor_free_heap_chunks(pool->vm, heap); 230 + mutex_destroy(&heap->lock); 231 + kfree(heap); 232 + return 0; 233 + } 234 + 235 + /** 236 + * panthor_heap_destroy() - Destroy a heap context 237 + * @pool: Pool this context belongs to. 238 + * @handle: Handle returned by panthor_heap_create(). 239 + */ 240 + int panthor_heap_destroy(struct panthor_heap_pool *pool, u32 handle) 241 + { 242 + int ret; 243 + 244 + down_write(&pool->lock); 245 + ret = panthor_heap_destroy_locked(pool, handle); 246 + up_write(&pool->lock); 247 + 248 + return ret; 249 + } 250 + 251 + /** 252 + * panthor_heap_create() - Create a heap context 253 + * @pool: Pool to instantiate the heap context from. 254 + * @initial_chunk_count: Number of chunk allocated at initialization time. 255 + * Must be at least 1. 256 + * @chunk_size: The size of each chunk. Must be a power of two between 256k 257 + * and 2M. 258 + * @max_chunks: Maximum number of chunks that can be allocated. 259 + * @target_in_flight: Maximum number of in-flight render passes. 260 + * @heap_ctx_gpu_va: Pointer holding the GPU address of the allocated heap 261 + * context. 262 + * @first_chunk_gpu_va: Pointer holding the GPU address of the first chunk 263 + * assigned to the heap context. 264 + * 265 + * Return: a positive handle on success, a negative error otherwise. 266 + */ 267 + int panthor_heap_create(struct panthor_heap_pool *pool, 268 + u32 initial_chunk_count, 269 + u32 chunk_size, 270 + u32 max_chunks, 271 + u32 target_in_flight, 272 + u64 *heap_ctx_gpu_va, 273 + u64 *first_chunk_gpu_va) 274 + { 275 + struct panthor_heap *heap; 276 + struct panthor_heap_chunk *first_chunk; 277 + struct panthor_vm *vm; 278 + int ret = 0; 279 + u32 id; 280 + 281 + if (initial_chunk_count == 0) 282 + return -EINVAL; 283 + 284 + if (hweight32(chunk_size) != 1 || 285 + chunk_size < SZ_256K || chunk_size > SZ_2M) 286 + return -EINVAL; 287 + 288 + down_read(&pool->lock); 289 + vm = panthor_vm_get(pool->vm); 290 + up_read(&pool->lock); 291 + 292 + /* The pool has been destroyed, we can't create a new heap. */ 293 + if (!vm) 294 + return -EINVAL; 295 + 296 + heap = kzalloc(sizeof(*heap), GFP_KERNEL); 297 + if (!heap) { 298 + ret = -ENOMEM; 299 + goto err_put_vm; 300 + } 301 + 302 + mutex_init(&heap->lock); 303 + INIT_LIST_HEAD(&heap->chunks); 304 + heap->chunk_size = chunk_size; 305 + heap->max_chunks = max_chunks; 306 + heap->target_in_flight = target_in_flight; 307 + 308 + ret = panthor_alloc_heap_chunks(pool->ptdev, vm, heap, 309 + initial_chunk_count); 310 + if (ret) 311 + goto err_free_heap; 312 + 313 + first_chunk = list_first_entry(&heap->chunks, 314 + struct panthor_heap_chunk, 315 + node); 316 + *first_chunk_gpu_va = panthor_kernel_bo_gpuva(first_chunk->bo); 317 + 318 + down_write(&pool->lock); 319 + /* The pool has been destroyed, we can't create a new heap. */ 320 + if (!pool->vm) { 321 + ret = -EINVAL; 322 + } else { 323 + ret = xa_alloc(&pool->xa, &id, heap, XA_LIMIT(1, MAX_HEAPS_PER_POOL), GFP_KERNEL); 324 + if (!ret) { 325 + void *gpu_ctx = panthor_get_heap_ctx(pool, id); 326 + 327 + memset(gpu_ctx, 0, panthor_heap_ctx_stride(pool->ptdev)); 328 + *heap_ctx_gpu_va = panthor_kernel_bo_gpuva(pool->gpu_contexts) + 329 + panthor_get_heap_ctx_offset(pool, id); 330 + } 331 + } 332 + up_write(&pool->lock); 333 + 334 + if (ret) 335 + goto err_free_heap; 336 + 337 + panthor_vm_put(vm); 338 + return id; 339 + 340 + err_free_heap: 341 + panthor_free_heap_chunks(pool->vm, heap); 342 + mutex_destroy(&heap->lock); 343 + kfree(heap); 344 + 345 + err_put_vm: 346 + panthor_vm_put(vm); 347 + return ret; 348 + } 349 + 350 + /** 351 + * panthor_heap_return_chunk() - Return an unused heap chunk 352 + * @pool: The pool this heap belongs to. 353 + * @heap_gpu_va: The GPU address of the heap context. 354 + * @chunk_gpu_va: The chunk VA to return. 355 + * 356 + * This function is used when a chunk allocated with panthor_heap_grow() 357 + * couldn't be linked to the heap context through the FW interface because 358 + * the group requesting the allocation was scheduled out in the meantime. 359 + */ 360 + int panthor_heap_return_chunk(struct panthor_heap_pool *pool, 361 + u64 heap_gpu_va, 362 + u64 chunk_gpu_va) 363 + { 364 + u64 offset = heap_gpu_va - panthor_kernel_bo_gpuva(pool->gpu_contexts); 365 + u32 heap_id = (u32)offset / panthor_heap_ctx_stride(pool->ptdev); 366 + struct panthor_heap_chunk *chunk, *tmp, *removed = NULL; 367 + struct panthor_heap *heap; 368 + int ret; 369 + 370 + if (offset > U32_MAX || heap_id >= MAX_HEAPS_PER_POOL) 371 + return -EINVAL; 372 + 373 + down_read(&pool->lock); 374 + heap = xa_load(&pool->xa, heap_id); 375 + if (!heap) { 376 + ret = -EINVAL; 377 + goto out_unlock; 378 + } 379 + 380 + chunk_gpu_va &= GENMASK_ULL(63, 12); 381 + 382 + mutex_lock(&heap->lock); 383 + list_for_each_entry_safe(chunk, tmp, &heap->chunks, node) { 384 + if (panthor_kernel_bo_gpuva(chunk->bo) == chunk_gpu_va) { 385 + removed = chunk; 386 + list_del(&chunk->node); 387 + heap->chunk_count--; 388 + break; 389 + } 390 + } 391 + mutex_unlock(&heap->lock); 392 + 393 + if (removed) { 394 + panthor_kernel_bo_destroy(pool->vm, chunk->bo); 395 + kfree(chunk); 396 + ret = 0; 397 + } else { 398 + ret = -EINVAL; 399 + } 400 + 401 + out_unlock: 402 + up_read(&pool->lock); 403 + return ret; 404 + } 405 + 406 + /** 407 + * panthor_heap_grow() - Make a heap context grow. 408 + * @pool: The pool this heap belongs to. 409 + * @heap_gpu_va: The GPU address of the heap context. 410 + * @renderpasses_in_flight: Number of render passes currently in-flight. 411 + * @pending_frag_count: Number of fragment jobs waiting for execution/completion. 412 + * @new_chunk_gpu_va: Pointer used to return the chunk VA. 413 + */ 414 + int panthor_heap_grow(struct panthor_heap_pool *pool, 415 + u64 heap_gpu_va, 416 + u32 renderpasses_in_flight, 417 + u32 pending_frag_count, 418 + u64 *new_chunk_gpu_va) 419 + { 420 + u64 offset = heap_gpu_va - panthor_kernel_bo_gpuva(pool->gpu_contexts); 421 + u32 heap_id = (u32)offset / panthor_heap_ctx_stride(pool->ptdev); 422 + struct panthor_heap_chunk *chunk; 423 + struct panthor_heap *heap; 424 + int ret; 425 + 426 + if (offset > U32_MAX || heap_id >= MAX_HEAPS_PER_POOL) 427 + return -EINVAL; 428 + 429 + down_read(&pool->lock); 430 + heap = xa_load(&pool->xa, heap_id); 431 + if (!heap) { 432 + ret = -EINVAL; 433 + goto out_unlock; 434 + } 435 + 436 + /* If we reached the target in-flight render passes, or if we 437 + * reached the maximum number of chunks, let the FW figure another way to 438 + * find some memory (wait for render passes to finish, or call the exception 439 + * handler provided by the userspace driver, if any). 440 + */ 441 + if (renderpasses_in_flight > heap->target_in_flight || 442 + (pending_frag_count > 0 && heap->chunk_count >= heap->max_chunks)) { 443 + ret = -EBUSY; 444 + goto out_unlock; 445 + } else if (heap->chunk_count >= heap->max_chunks) { 446 + ret = -ENOMEM; 447 + goto out_unlock; 448 + } 449 + 450 + /* FIXME: panthor_alloc_heap_chunk() triggers a kernel BO creation, 451 + * which goes through the blocking allocation path. Ultimately, we 452 + * want a non-blocking allocation, so we can immediately report to the 453 + * FW when the system is running out of memory. In that case, the FW 454 + * can call a user-provided exception handler, which might try to free 455 + * some tiler memory by issuing an intermediate fragment job. If the 456 + * exception handler can't do anything, it will flag the queue as 457 + * faulty so the job that triggered this tiler chunk allocation and all 458 + * further jobs in this queue fail immediately instead of having to 459 + * wait for the job timeout. 460 + */ 461 + ret = panthor_alloc_heap_chunk(pool->ptdev, pool->vm, heap, false); 462 + if (ret) 463 + goto out_unlock; 464 + 465 + chunk = list_first_entry(&heap->chunks, 466 + struct panthor_heap_chunk, 467 + node); 468 + *new_chunk_gpu_va = (panthor_kernel_bo_gpuva(chunk->bo) & GENMASK_ULL(63, 12)) | 469 + (heap->chunk_size >> 12); 470 + ret = 0; 471 + 472 + out_unlock: 473 + up_read(&pool->lock); 474 + return ret; 475 + } 476 + 477 + static void panthor_heap_pool_release(struct kref *refcount) 478 + { 479 + struct panthor_heap_pool *pool = 480 + container_of(refcount, struct panthor_heap_pool, refcount); 481 + 482 + xa_destroy(&pool->xa); 483 + kfree(pool); 484 + } 485 + 486 + /** 487 + * panthor_heap_pool_put() - Release a heap pool reference 488 + * @pool: Pool to release the reference on. Can be NULL. 489 + */ 490 + void panthor_heap_pool_put(struct panthor_heap_pool *pool) 491 + { 492 + if (pool) 493 + kref_put(&pool->refcount, panthor_heap_pool_release); 494 + } 495 + 496 + /** 497 + * panthor_heap_pool_get() - Get a heap pool reference 498 + * @pool: Pool to get the reference on. Can be NULL. 499 + * 500 + * Return: @pool. 501 + */ 502 + struct panthor_heap_pool * 503 + panthor_heap_pool_get(struct panthor_heap_pool *pool) 504 + { 505 + if (pool) 506 + kref_get(&pool->refcount); 507 + 508 + return pool; 509 + } 510 + 511 + /** 512 + * panthor_heap_pool_create() - Create a heap pool 513 + * @ptdev: Device. 514 + * @vm: The VM this heap pool will be attached to. 515 + * 516 + * Heap pools might contain up to 128 heap contexts, and are per-VM. 517 + * 518 + * Return: A valid pointer on success, a negative error code otherwise. 519 + */ 520 + struct panthor_heap_pool * 521 + panthor_heap_pool_create(struct panthor_device *ptdev, struct panthor_vm *vm) 522 + { 523 + size_t bosize = ALIGN(MAX_HEAPS_PER_POOL * 524 + panthor_heap_ctx_stride(ptdev), 525 + 4096); 526 + struct panthor_heap_pool *pool; 527 + int ret = 0; 528 + 529 + pool = kzalloc(sizeof(*pool), GFP_KERNEL); 530 + if (!pool) 531 + return ERR_PTR(-ENOMEM); 532 + 533 + /* We want a weak ref here: the heap pool belongs to the VM, so we're 534 + * sure that, as long as the heap pool exists, the VM exists too. 535 + */ 536 + pool->vm = vm; 537 + pool->ptdev = ptdev; 538 + init_rwsem(&pool->lock); 539 + xa_init_flags(&pool->xa, XA_FLAGS_ALLOC1); 540 + kref_init(&pool->refcount); 541 + 542 + pool->gpu_contexts = panthor_kernel_bo_create(ptdev, vm, bosize, 543 + DRM_PANTHOR_BO_NO_MMAP, 544 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, 545 + PANTHOR_VM_KERNEL_AUTO_VA); 546 + if (IS_ERR(pool->gpu_contexts)) { 547 + ret = PTR_ERR(pool->gpu_contexts); 548 + goto err_destroy_pool; 549 + } 550 + 551 + ret = panthor_kernel_bo_vmap(pool->gpu_contexts); 552 + if (ret) 553 + goto err_destroy_pool; 554 + 555 + return pool; 556 + 557 + err_destroy_pool: 558 + panthor_heap_pool_destroy(pool); 559 + return ERR_PTR(ret); 560 + } 561 + 562 + /** 563 + * panthor_heap_pool_destroy() - Destroy a heap pool. 564 + * @pool: Pool to destroy. 565 + * 566 + * This function destroys all heap contexts and their resources. Thus 567 + * preventing any use of the heap context or the chunk attached to them 568 + * after that point. 569 + * 570 + * If the GPU still has access to some heap contexts, a fault should be 571 + * triggered, which should flag the command stream groups using these 572 + * context as faulty. 573 + * 574 + * The heap pool object is only released when all references to this pool 575 + * are released. 576 + */ 577 + void panthor_heap_pool_destroy(struct panthor_heap_pool *pool) 578 + { 579 + struct panthor_heap *heap; 580 + unsigned long i; 581 + 582 + if (!pool) 583 + return; 584 + 585 + down_write(&pool->lock); 586 + xa_for_each(&pool->xa, i, heap) 587 + drm_WARN_ON(&pool->ptdev->base, panthor_heap_destroy_locked(pool, i)); 588 + 589 + if (!IS_ERR_OR_NULL(pool->gpu_contexts)) 590 + panthor_kernel_bo_destroy(pool->vm, pool->gpu_contexts); 591 + 592 + /* Reflects the fact the pool has been destroyed. */ 593 + pool->vm = NULL; 594 + up_write(&pool->lock); 595 + 596 + panthor_heap_pool_put(pool); 597 + }
+39
drivers/gpu/drm/panthor/panthor_heap.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2023 Collabora ltd. */ 3 + 4 + #ifndef __PANTHOR_HEAP_H__ 5 + #define __PANTHOR_HEAP_H__ 6 + 7 + #include <linux/types.h> 8 + 9 + struct panthor_device; 10 + struct panthor_heap_pool; 11 + struct panthor_vm; 12 + 13 + int panthor_heap_create(struct panthor_heap_pool *pool, 14 + u32 initial_chunk_count, 15 + u32 chunk_size, 16 + u32 max_chunks, 17 + u32 target_in_flight, 18 + u64 *heap_ctx_gpu_va, 19 + u64 *first_chunk_gpu_va); 20 + int panthor_heap_destroy(struct panthor_heap_pool *pool, u32 handle); 21 + 22 + struct panthor_heap_pool * 23 + panthor_heap_pool_create(struct panthor_device *ptdev, struct panthor_vm *vm); 24 + void panthor_heap_pool_destroy(struct panthor_heap_pool *pool); 25 + 26 + struct panthor_heap_pool * 27 + panthor_heap_pool_get(struct panthor_heap_pool *pool); 28 + void panthor_heap_pool_put(struct panthor_heap_pool *pool); 29 + 30 + int panthor_heap_grow(struct panthor_heap_pool *pool, 31 + u64 heap_gpu_va, 32 + u32 renderpasses_in_flight, 33 + u32 pending_frag_count, 34 + u64 *new_chunk_gpu_va); 35 + int panthor_heap_return_chunk(struct panthor_heap_pool *pool, 36 + u64 heap_gpu_va, 37 + u64 chunk_gpu_va); 38 + 39 + #endif
+2768
drivers/gpu/drm/panthor/panthor_mmu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 3 + /* Copyright 2023 Collabora ltd. */ 4 + 5 + #include <drm/drm_debugfs.h> 6 + #include <drm/drm_drv.h> 7 + #include <drm/drm_exec.h> 8 + #include <drm/drm_gpuvm.h> 9 + #include <drm/drm_managed.h> 10 + #include <drm/gpu_scheduler.h> 11 + #include <drm/panthor_drm.h> 12 + 13 + #include <linux/atomic.h> 14 + #include <linux/bitfield.h> 15 + #include <linux/delay.h> 16 + #include <linux/dma-mapping.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/io.h> 19 + #include <linux/iopoll.h> 20 + #include <linux/io-pgtable.h> 21 + #include <linux/iommu.h> 22 + #include <linux/kmemleak.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/pm_runtime.h> 25 + #include <linux/rwsem.h> 26 + #include <linux/sched.h> 27 + #include <linux/shmem_fs.h> 28 + #include <linux/sizes.h> 29 + 30 + #include "panthor_device.h" 31 + #include "panthor_gem.h" 32 + #include "panthor_heap.h" 33 + #include "panthor_mmu.h" 34 + #include "panthor_regs.h" 35 + #include "panthor_sched.h" 36 + 37 + #define MAX_AS_SLOTS 32 38 + 39 + struct panthor_vm; 40 + 41 + /** 42 + * struct panthor_as_slot - Address space slot 43 + */ 44 + struct panthor_as_slot { 45 + /** @vm: VM bound to this slot. NULL is no VM is bound. */ 46 + struct panthor_vm *vm; 47 + }; 48 + 49 + /** 50 + * struct panthor_mmu - MMU related data 51 + */ 52 + struct panthor_mmu { 53 + /** @irq: The MMU irq. */ 54 + struct panthor_irq irq; 55 + 56 + /** @as: Address space related fields. 57 + * 58 + * The GPU has a limited number of address spaces (AS) slots, forcing 59 + * us to re-assign them to re-assign slots on-demand. 60 + */ 61 + struct { 62 + /** @slots_lock: Lock protecting access to all other AS fields. */ 63 + struct mutex slots_lock; 64 + 65 + /** @alloc_mask: Bitmask encoding the allocated slots. */ 66 + unsigned long alloc_mask; 67 + 68 + /** @faulty_mask: Bitmask encoding the faulty slots. */ 69 + unsigned long faulty_mask; 70 + 71 + /** @slots: VMs currently bound to the AS slots. */ 72 + struct panthor_as_slot slots[MAX_AS_SLOTS]; 73 + 74 + /** 75 + * @lru_list: List of least recently used VMs. 76 + * 77 + * We use this list to pick a VM to evict when all slots are 78 + * used. 79 + * 80 + * There should be no more active VMs than there are AS slots, 81 + * so this LRU is just here to keep VMs bound until there's 82 + * a need to release a slot, thus avoid unnecessary TLB/cache 83 + * flushes. 84 + */ 85 + struct list_head lru_list; 86 + } as; 87 + 88 + /** @vm: VMs management fields */ 89 + struct { 90 + /** @lock: Lock protecting access to list. */ 91 + struct mutex lock; 92 + 93 + /** @list: List containing all VMs. */ 94 + struct list_head list; 95 + 96 + /** @reset_in_progress: True if a reset is in progress. */ 97 + bool reset_in_progress; 98 + 99 + /** @wq: Workqueue used for the VM_BIND queues. */ 100 + struct workqueue_struct *wq; 101 + } vm; 102 + }; 103 + 104 + /** 105 + * struct panthor_vm_pool - VM pool object 106 + */ 107 + struct panthor_vm_pool { 108 + /** @xa: Array used for VM handle tracking. */ 109 + struct xarray xa; 110 + }; 111 + 112 + /** 113 + * struct panthor_vma - GPU mapping object 114 + * 115 + * This is used to track GEM mappings in GPU space. 116 + */ 117 + struct panthor_vma { 118 + /** @base: Inherits from drm_gpuva. */ 119 + struct drm_gpuva base; 120 + 121 + /** @node: Used to implement deferred release of VMAs. */ 122 + struct list_head node; 123 + 124 + /** 125 + * @flags: Combination of drm_panthor_vm_bind_op_flags. 126 + * 127 + * Only map related flags are accepted. 128 + */ 129 + u32 flags; 130 + }; 131 + 132 + /** 133 + * struct panthor_vm_op_ctx - VM operation context 134 + * 135 + * With VM operations potentially taking place in a dma-signaling path, we 136 + * need to make sure everything that might require resource allocation is 137 + * pre-allocated upfront. This is what this operation context is far. 138 + * 139 + * We also collect resources that have been freed, so we can release them 140 + * asynchronously, and let the VM_BIND scheduler process the next VM_BIND 141 + * request. 142 + */ 143 + struct panthor_vm_op_ctx { 144 + /** @rsvd_page_tables: Pages reserved for the MMU page table update. */ 145 + struct { 146 + /** @count: Number of pages reserved. */ 147 + u32 count; 148 + 149 + /** @ptr: Point to the first unused page in the @pages table. */ 150 + u32 ptr; 151 + 152 + /** 153 + * @page: Array of pages that can be used for an MMU page table update. 154 + * 155 + * After an VM operation, there might be free pages left in this array. 156 + * They should be returned to the pt_cache as part of the op_ctx cleanup. 157 + */ 158 + void **pages; 159 + } rsvd_page_tables; 160 + 161 + /** 162 + * @preallocated_vmas: Pre-allocated VMAs to handle the remap case. 163 + * 164 + * Partial unmap requests or map requests overlapping existing mappings will 165 + * trigger a remap call, which need to register up to three panthor_vma objects 166 + * (one for the new mapping, and two for the previous and next mappings). 167 + */ 168 + struct panthor_vma *preallocated_vmas[3]; 169 + 170 + /** @flags: Combination of drm_panthor_vm_bind_op_flags. */ 171 + u32 flags; 172 + 173 + /** @va: Virtual range targeted by the VM operation. */ 174 + struct { 175 + /** @addr: Start address. */ 176 + u64 addr; 177 + 178 + /** @range: Range size. */ 179 + u64 range; 180 + } va; 181 + 182 + /** 183 + * @returned_vmas: List of panthor_vma objects returned after a VM operation. 184 + * 185 + * For unmap operations, this will contain all VMAs that were covered by the 186 + * specified VA range. 187 + * 188 + * For map operations, this will contain all VMAs that previously mapped to 189 + * the specified VA range. 190 + * 191 + * Those VMAs, and the resources they point to will be released as part of 192 + * the op_ctx cleanup operation. 193 + */ 194 + struct list_head returned_vmas; 195 + 196 + /** @map: Fields specific to a map operation. */ 197 + struct { 198 + /** @vm_bo: Buffer object to map. */ 199 + struct drm_gpuvm_bo *vm_bo; 200 + 201 + /** @bo_offset: Offset in the buffer object. */ 202 + u64 bo_offset; 203 + 204 + /** 205 + * @sgt: sg-table pointing to pages backing the GEM object. 206 + * 207 + * This is gathered at job creation time, such that we don't have 208 + * to allocate in ::run_job(). 209 + */ 210 + struct sg_table *sgt; 211 + 212 + /** 213 + * @new_vma: The new VMA object that will be inserted to the VA tree. 214 + */ 215 + struct panthor_vma *new_vma; 216 + } map; 217 + }; 218 + 219 + /** 220 + * struct panthor_vm - VM object 221 + * 222 + * A VM is an object representing a GPU (or MCU) virtual address space. 223 + * It embeds the MMU page table for this address space, a tree containing 224 + * all the virtual mappings of GEM objects, and other things needed to manage 225 + * the VM. 226 + * 227 + * Except for the MCU VM, which is managed by the kernel, all other VMs are 228 + * created by userspace and mostly managed by userspace, using the 229 + * %DRM_IOCTL_PANTHOR_VM_BIND ioctl. 230 + * 231 + * A portion of the virtual address space is reserved for kernel objects, 232 + * like heap chunks, and userspace gets to decide how much of the virtual 233 + * address space is left to the kernel (half of the virtual address space 234 + * by default). 235 + */ 236 + struct panthor_vm { 237 + /** 238 + * @base: Inherit from drm_gpuvm. 239 + * 240 + * We delegate all the VA management to the common drm_gpuvm framework 241 + * and only implement hooks to update the MMU page table. 242 + */ 243 + struct drm_gpuvm base; 244 + 245 + /** 246 + * @sched: Scheduler used for asynchronous VM_BIND request. 247 + * 248 + * We use a 1:1 scheduler here. 249 + */ 250 + struct drm_gpu_scheduler sched; 251 + 252 + /** 253 + * @entity: Scheduling entity representing the VM_BIND queue. 254 + * 255 + * There's currently one bind queue per VM. It doesn't make sense to 256 + * allow more given the VM operations are serialized anyway. 257 + */ 258 + struct drm_sched_entity entity; 259 + 260 + /** @ptdev: Device. */ 261 + struct panthor_device *ptdev; 262 + 263 + /** @memattr: Value to program to the AS_MEMATTR register. */ 264 + u64 memattr; 265 + 266 + /** @pgtbl_ops: Page table operations. */ 267 + struct io_pgtable_ops *pgtbl_ops; 268 + 269 + /** @root_page_table: Stores the root page table pointer. */ 270 + void *root_page_table; 271 + 272 + /** 273 + * @op_lock: Lock used to serialize operations on a VM. 274 + * 275 + * The serialization of jobs queued to the VM_BIND queue is already 276 + * taken care of by drm_sched, but we need to serialize synchronous 277 + * and asynchronous VM_BIND request. This is what this lock is for. 278 + */ 279 + struct mutex op_lock; 280 + 281 + /** 282 + * @op_ctx: The context attached to the currently executing VM operation. 283 + * 284 + * NULL when no operation is in progress. 285 + */ 286 + struct panthor_vm_op_ctx *op_ctx; 287 + 288 + /** 289 + * @mm: Memory management object representing the auto-VA/kernel-VA. 290 + * 291 + * Used to auto-allocate VA space for kernel-managed objects (tiler 292 + * heaps, ...). 293 + * 294 + * For the MCU VM, this is managing the VA range that's used to map 295 + * all shared interfaces. 296 + * 297 + * For user VMs, the range is specified by userspace, and must not 298 + * exceed half of the VA space addressable. 299 + */ 300 + struct drm_mm mm; 301 + 302 + /** @mm_lock: Lock protecting the @mm field. */ 303 + struct mutex mm_lock; 304 + 305 + /** @kernel_auto_va: Automatic VA-range for kernel BOs. */ 306 + struct { 307 + /** @start: Start of the automatic VA-range for kernel BOs. */ 308 + u64 start; 309 + 310 + /** @size: Size of the automatic VA-range for kernel BOs. */ 311 + u64 end; 312 + } kernel_auto_va; 313 + 314 + /** @as: Address space related fields. */ 315 + struct { 316 + /** 317 + * @id: ID of the address space this VM is bound to. 318 + * 319 + * A value of -1 means the VM is inactive/not bound. 320 + */ 321 + int id; 322 + 323 + /** @active_cnt: Number of active users of this VM. */ 324 + refcount_t active_cnt; 325 + 326 + /** 327 + * @lru_node: Used to instead the VM in the panthor_mmu::as::lru_list. 328 + * 329 + * Active VMs should not be inserted in the LRU list. 330 + */ 331 + struct list_head lru_node; 332 + } as; 333 + 334 + /** 335 + * @heaps: Tiler heap related fields. 336 + */ 337 + struct { 338 + /** 339 + * @pool: The heap pool attached to this VM. 340 + * 341 + * Will stay NULL until someone creates a heap context on this VM. 342 + */ 343 + struct panthor_heap_pool *pool; 344 + 345 + /** @lock: Lock used to protect access to @pool. */ 346 + struct mutex lock; 347 + } heaps; 348 + 349 + /** @node: Used to insert the VM in the panthor_mmu::vm::list. */ 350 + struct list_head node; 351 + 352 + /** @for_mcu: True if this is the MCU VM. */ 353 + bool for_mcu; 354 + 355 + /** 356 + * @destroyed: True if the VM was destroyed. 357 + * 358 + * No further bind requests should be queued to a destroyed VM. 359 + */ 360 + bool destroyed; 361 + 362 + /** 363 + * @unusable: True if the VM has turned unusable because something 364 + * bad happened during an asynchronous request. 365 + * 366 + * We don't try to recover from such failures, because this implies 367 + * informing userspace about the specific operation that failed, and 368 + * hoping the userspace driver can replay things from there. This all 369 + * sounds very complicated for little gain. 370 + * 371 + * Instead, we should just flag the VM as unusable, and fail any 372 + * further request targeting this VM. 373 + * 374 + * We also provide a way to query a VM state, so userspace can destroy 375 + * it and create a new one. 376 + * 377 + * As an analogy, this would be mapped to a VK_ERROR_DEVICE_LOST 378 + * situation, where the logical device needs to be re-created. 379 + */ 380 + bool unusable; 381 + 382 + /** 383 + * @unhandled_fault: Unhandled fault happened. 384 + * 385 + * This should be reported to the scheduler, and the queue/group be 386 + * flagged as faulty as a result. 387 + */ 388 + bool unhandled_fault; 389 + }; 390 + 391 + /** 392 + * struct panthor_vm_bind_job - VM bind job 393 + */ 394 + struct panthor_vm_bind_job { 395 + /** @base: Inherit from drm_sched_job. */ 396 + struct drm_sched_job base; 397 + 398 + /** @refcount: Reference count. */ 399 + struct kref refcount; 400 + 401 + /** @cleanup_op_ctx_work: Work used to cleanup the VM operation context. */ 402 + struct work_struct cleanup_op_ctx_work; 403 + 404 + /** @vm: VM targeted by the VM operation. */ 405 + struct panthor_vm *vm; 406 + 407 + /** @ctx: Operation context. */ 408 + struct panthor_vm_op_ctx ctx; 409 + }; 410 + 411 + /** 412 + * @pt_cache: Cache used to allocate MMU page tables. 413 + * 414 + * The pre-allocation pattern forces us to over-allocate to plan for 415 + * the worst case scenario, and return the pages we didn't use. 416 + * 417 + * Having a kmem_cache allows us to speed allocations. 418 + */ 419 + static struct kmem_cache *pt_cache; 420 + 421 + /** 422 + * alloc_pt() - Custom page table allocator 423 + * @cookie: Cookie passed at page table allocation time. 424 + * @size: Size of the page table. This size should be fixed, 425 + * and determined at creation time based on the granule size. 426 + * @gfp: GFP flags. 427 + * 428 + * We want a custom allocator so we can use a cache for page table 429 + * allocations and amortize the cost of the over-reservation that's 430 + * done to allow asynchronous VM operations. 431 + * 432 + * Return: non-NULL on success, NULL if the allocation failed for any 433 + * reason. 434 + */ 435 + static void *alloc_pt(void *cookie, size_t size, gfp_t gfp) 436 + { 437 + struct panthor_vm *vm = cookie; 438 + void *page; 439 + 440 + /* Allocation of the root page table happening during init. */ 441 + if (unlikely(!vm->root_page_table)) { 442 + struct page *p; 443 + 444 + drm_WARN_ON(&vm->ptdev->base, vm->op_ctx); 445 + p = alloc_pages_node(dev_to_node(vm->ptdev->base.dev), 446 + gfp | __GFP_ZERO, get_order(size)); 447 + page = p ? page_address(p) : NULL; 448 + vm->root_page_table = page; 449 + return page; 450 + } 451 + 452 + /* We're not supposed to have anything bigger than 4k here, because we picked a 453 + * 4k granule size at init time. 454 + */ 455 + if (drm_WARN_ON(&vm->ptdev->base, size != SZ_4K)) 456 + return NULL; 457 + 458 + /* We must have some op_ctx attached to the VM and it must have at least one 459 + * free page. 460 + */ 461 + if (drm_WARN_ON(&vm->ptdev->base, !vm->op_ctx) || 462 + drm_WARN_ON(&vm->ptdev->base, 463 + vm->op_ctx->rsvd_page_tables.ptr >= vm->op_ctx->rsvd_page_tables.count)) 464 + return NULL; 465 + 466 + page = vm->op_ctx->rsvd_page_tables.pages[vm->op_ctx->rsvd_page_tables.ptr++]; 467 + memset(page, 0, SZ_4K); 468 + 469 + /* Page table entries don't use virtual addresses, which trips out 470 + * kmemleak. kmemleak_alloc_phys() might work, but physical addresses 471 + * are mixed with other fields, and I fear kmemleak won't detect that 472 + * either. 473 + * 474 + * Let's just ignore memory passed to the page-table driver for now. 475 + */ 476 + kmemleak_ignore(page); 477 + return page; 478 + } 479 + 480 + /** 481 + * @free_pt() - Custom page table free function 482 + * @cookie: Cookie passed at page table allocation time. 483 + * @data: Page table to free. 484 + * @size: Size of the page table. This size should be fixed, 485 + * and determined at creation time based on the granule size. 486 + */ 487 + static void free_pt(void *cookie, void *data, size_t size) 488 + { 489 + struct panthor_vm *vm = cookie; 490 + 491 + if (unlikely(vm->root_page_table == data)) { 492 + free_pages((unsigned long)data, get_order(size)); 493 + vm->root_page_table = NULL; 494 + return; 495 + } 496 + 497 + if (drm_WARN_ON(&vm->ptdev->base, size != SZ_4K)) 498 + return; 499 + 500 + /* Return the page to the pt_cache. */ 501 + kmem_cache_free(pt_cache, data); 502 + } 503 + 504 + static int wait_ready(struct panthor_device *ptdev, u32 as_nr) 505 + { 506 + int ret; 507 + u32 val; 508 + 509 + /* Wait for the MMU status to indicate there is no active command, in 510 + * case one is pending. 511 + */ 512 + ret = readl_relaxed_poll_timeout_atomic(ptdev->iomem + AS_STATUS(as_nr), 513 + val, !(val & AS_STATUS_AS_ACTIVE), 514 + 10, 100000); 515 + 516 + if (ret) { 517 + panthor_device_schedule_reset(ptdev); 518 + drm_err(&ptdev->base, "AS_ACTIVE bit stuck\n"); 519 + } 520 + 521 + return ret; 522 + } 523 + 524 + static int write_cmd(struct panthor_device *ptdev, u32 as_nr, u32 cmd) 525 + { 526 + int status; 527 + 528 + /* write AS_COMMAND when MMU is ready to accept another command */ 529 + status = wait_ready(ptdev, as_nr); 530 + if (!status) 531 + gpu_write(ptdev, AS_COMMAND(as_nr), cmd); 532 + 533 + return status; 534 + } 535 + 536 + static void lock_region(struct panthor_device *ptdev, u32 as_nr, 537 + u64 region_start, u64 size) 538 + { 539 + u8 region_width; 540 + u64 region; 541 + u64 region_end = region_start + size; 542 + 543 + if (!size) 544 + return; 545 + 546 + /* 547 + * The locked region is a naturally aligned power of 2 block encoded as 548 + * log2 minus(1). 549 + * Calculate the desired start/end and look for the highest bit which 550 + * differs. The smallest naturally aligned block must include this bit 551 + * change, the desired region starts with this bit (and subsequent bits) 552 + * zeroed and ends with the bit (and subsequent bits) set to one. 553 + */ 554 + region_width = max(fls64(region_start ^ (region_end - 1)), 555 + const_ilog2(AS_LOCK_REGION_MIN_SIZE)) - 1; 556 + 557 + /* 558 + * Mask off the low bits of region_start (which would be ignored by 559 + * the hardware anyway) 560 + */ 561 + region_start &= GENMASK_ULL(63, region_width); 562 + 563 + region = region_width | region_start; 564 + 565 + /* Lock the region that needs to be updated */ 566 + gpu_write(ptdev, AS_LOCKADDR_LO(as_nr), lower_32_bits(region)); 567 + gpu_write(ptdev, AS_LOCKADDR_HI(as_nr), upper_32_bits(region)); 568 + write_cmd(ptdev, as_nr, AS_COMMAND_LOCK); 569 + } 570 + 571 + static int mmu_hw_do_operation_locked(struct panthor_device *ptdev, int as_nr, 572 + u64 iova, u64 size, u32 op) 573 + { 574 + lockdep_assert_held(&ptdev->mmu->as.slots_lock); 575 + 576 + if (as_nr < 0) 577 + return 0; 578 + 579 + if (op != AS_COMMAND_UNLOCK) 580 + lock_region(ptdev, as_nr, iova, size); 581 + 582 + /* Run the MMU operation */ 583 + write_cmd(ptdev, as_nr, op); 584 + 585 + /* Wait for the flush to complete */ 586 + return wait_ready(ptdev, as_nr); 587 + } 588 + 589 + static int mmu_hw_do_operation(struct panthor_vm *vm, 590 + u64 iova, u64 size, u32 op) 591 + { 592 + struct panthor_device *ptdev = vm->ptdev; 593 + int ret; 594 + 595 + mutex_lock(&ptdev->mmu->as.slots_lock); 596 + ret = mmu_hw_do_operation_locked(ptdev, vm->as.id, iova, size, op); 597 + mutex_unlock(&ptdev->mmu->as.slots_lock); 598 + 599 + return ret; 600 + } 601 + 602 + static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, 603 + u64 transtab, u64 transcfg, u64 memattr) 604 + { 605 + int ret; 606 + 607 + ret = mmu_hw_do_operation_locked(ptdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM); 608 + if (ret) 609 + return ret; 610 + 611 + gpu_write(ptdev, AS_TRANSTAB_LO(as_nr), lower_32_bits(transtab)); 612 + gpu_write(ptdev, AS_TRANSTAB_HI(as_nr), upper_32_bits(transtab)); 613 + 614 + gpu_write(ptdev, AS_MEMATTR_LO(as_nr), lower_32_bits(memattr)); 615 + gpu_write(ptdev, AS_MEMATTR_HI(as_nr), upper_32_bits(memattr)); 616 + 617 + gpu_write(ptdev, AS_TRANSCFG_LO(as_nr), lower_32_bits(transcfg)); 618 + gpu_write(ptdev, AS_TRANSCFG_HI(as_nr), upper_32_bits(transcfg)); 619 + 620 + return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE); 621 + } 622 + 623 + static int panthor_mmu_as_disable(struct panthor_device *ptdev, u32 as_nr) 624 + { 625 + int ret; 626 + 627 + ret = mmu_hw_do_operation_locked(ptdev, as_nr, 0, ~0ULL, AS_COMMAND_FLUSH_MEM); 628 + if (ret) 629 + return ret; 630 + 631 + gpu_write(ptdev, AS_TRANSTAB_LO(as_nr), 0); 632 + gpu_write(ptdev, AS_TRANSTAB_HI(as_nr), 0); 633 + 634 + gpu_write(ptdev, AS_MEMATTR_LO(as_nr), 0); 635 + gpu_write(ptdev, AS_MEMATTR_HI(as_nr), 0); 636 + 637 + gpu_write(ptdev, AS_TRANSCFG_LO(as_nr), AS_TRANSCFG_ADRMODE_UNMAPPED); 638 + gpu_write(ptdev, AS_TRANSCFG_HI(as_nr), 0); 639 + 640 + return write_cmd(ptdev, as_nr, AS_COMMAND_UPDATE); 641 + } 642 + 643 + static u32 panthor_mmu_fault_mask(struct panthor_device *ptdev, u32 value) 644 + { 645 + /* Bits 16 to 31 mean REQ_COMPLETE. */ 646 + return value & GENMASK(15, 0); 647 + } 648 + 649 + static u32 panthor_mmu_as_fault_mask(struct panthor_device *ptdev, u32 as) 650 + { 651 + return BIT(as); 652 + } 653 + 654 + /** 655 + * panthor_vm_has_unhandled_faults() - Check if a VM has unhandled faults 656 + * @vm: VM to check. 657 + * 658 + * Return: true if the VM has unhandled faults, false otherwise. 659 + */ 660 + bool panthor_vm_has_unhandled_faults(struct panthor_vm *vm) 661 + { 662 + return vm->unhandled_fault; 663 + } 664 + 665 + /** 666 + * panthor_vm_is_unusable() - Check if the VM is still usable 667 + * @vm: VM to check. 668 + * 669 + * Return: true if the VM is unusable, false otherwise. 670 + */ 671 + bool panthor_vm_is_unusable(struct panthor_vm *vm) 672 + { 673 + return vm->unusable; 674 + } 675 + 676 + static void panthor_vm_release_as_locked(struct panthor_vm *vm) 677 + { 678 + struct panthor_device *ptdev = vm->ptdev; 679 + 680 + lockdep_assert_held(&ptdev->mmu->as.slots_lock); 681 + 682 + if (drm_WARN_ON(&ptdev->base, vm->as.id < 0)) 683 + return; 684 + 685 + ptdev->mmu->as.slots[vm->as.id].vm = NULL; 686 + clear_bit(vm->as.id, &ptdev->mmu->as.alloc_mask); 687 + refcount_set(&vm->as.active_cnt, 0); 688 + list_del_init(&vm->as.lru_node); 689 + vm->as.id = -1; 690 + } 691 + 692 + /** 693 + * panthor_vm_active() - Flag a VM as active 694 + * @VM: VM to flag as active. 695 + * 696 + * Assigns an address space to a VM so it can be used by the GPU/MCU. 697 + * 698 + * Return: 0 on success, a negative error code otherwise. 699 + */ 700 + int panthor_vm_active(struct panthor_vm *vm) 701 + { 702 + struct panthor_device *ptdev = vm->ptdev; 703 + u32 va_bits = GPU_MMU_FEATURES_VA_BITS(ptdev->gpu_info.mmu_features); 704 + struct io_pgtable_cfg *cfg = &io_pgtable_ops_to_pgtable(vm->pgtbl_ops)->cfg; 705 + int ret = 0, as, cookie; 706 + u64 transtab, transcfg; 707 + 708 + if (!drm_dev_enter(&ptdev->base, &cookie)) 709 + return -ENODEV; 710 + 711 + if (refcount_inc_not_zero(&vm->as.active_cnt)) 712 + goto out_dev_exit; 713 + 714 + mutex_lock(&ptdev->mmu->as.slots_lock); 715 + 716 + if (refcount_inc_not_zero(&vm->as.active_cnt)) 717 + goto out_unlock; 718 + 719 + as = vm->as.id; 720 + if (as >= 0) { 721 + /* Unhandled pagefault on this AS, the MMU was disabled. We need to 722 + * re-enable the MMU after clearing+unmasking the AS interrupts. 723 + */ 724 + if (ptdev->mmu->as.faulty_mask & panthor_mmu_as_fault_mask(ptdev, as)) 725 + goto out_enable_as; 726 + 727 + goto out_make_active; 728 + } 729 + 730 + /* Check for a free AS */ 731 + if (vm->for_mcu) { 732 + drm_WARN_ON(&ptdev->base, ptdev->mmu->as.alloc_mask & BIT(0)); 733 + as = 0; 734 + } else { 735 + as = ffz(ptdev->mmu->as.alloc_mask | BIT(0)); 736 + } 737 + 738 + if (!(BIT(as) & ptdev->gpu_info.as_present)) { 739 + struct panthor_vm *lru_vm; 740 + 741 + lru_vm = list_first_entry_or_null(&ptdev->mmu->as.lru_list, 742 + struct panthor_vm, 743 + as.lru_node); 744 + if (drm_WARN_ON(&ptdev->base, !lru_vm)) { 745 + ret = -EBUSY; 746 + goto out_unlock; 747 + } 748 + 749 + drm_WARN_ON(&ptdev->base, refcount_read(&lru_vm->as.active_cnt)); 750 + as = lru_vm->as.id; 751 + panthor_vm_release_as_locked(lru_vm); 752 + } 753 + 754 + /* Assign the free or reclaimed AS to the FD */ 755 + vm->as.id = as; 756 + set_bit(as, &ptdev->mmu->as.alloc_mask); 757 + ptdev->mmu->as.slots[as].vm = vm; 758 + 759 + out_enable_as: 760 + transtab = cfg->arm_lpae_s1_cfg.ttbr; 761 + transcfg = AS_TRANSCFG_PTW_MEMATTR_WB | 762 + AS_TRANSCFG_PTW_RA | 763 + AS_TRANSCFG_ADRMODE_AARCH64_4K | 764 + AS_TRANSCFG_INA_BITS(55 - va_bits); 765 + if (ptdev->coherent) 766 + transcfg |= AS_TRANSCFG_PTW_SH_OS; 767 + 768 + /* If the VM is re-activated, we clear the fault. */ 769 + vm->unhandled_fault = false; 770 + 771 + /* Unhandled pagefault on this AS, clear the fault and re-enable interrupts 772 + * before enabling the AS. 773 + */ 774 + if (ptdev->mmu->as.faulty_mask & panthor_mmu_as_fault_mask(ptdev, as)) { 775 + gpu_write(ptdev, MMU_INT_CLEAR, panthor_mmu_as_fault_mask(ptdev, as)); 776 + ptdev->mmu->as.faulty_mask &= ~panthor_mmu_as_fault_mask(ptdev, as); 777 + gpu_write(ptdev, MMU_INT_MASK, ~ptdev->mmu->as.faulty_mask); 778 + } 779 + 780 + ret = panthor_mmu_as_enable(vm->ptdev, vm->as.id, transtab, transcfg, vm->memattr); 781 + 782 + out_make_active: 783 + if (!ret) { 784 + refcount_set(&vm->as.active_cnt, 1); 785 + list_del_init(&vm->as.lru_node); 786 + } 787 + 788 + out_unlock: 789 + mutex_unlock(&ptdev->mmu->as.slots_lock); 790 + 791 + out_dev_exit: 792 + drm_dev_exit(cookie); 793 + return ret; 794 + } 795 + 796 + /** 797 + * panthor_vm_idle() - Flag a VM idle 798 + * @VM: VM to flag as idle. 799 + * 800 + * When we know the GPU is done with the VM (no more jobs to process), 801 + * we can relinquish the AS slot attached to this VM, if any. 802 + * 803 + * We don't release the slot immediately, but instead place the VM in 804 + * the LRU list, so it can be evicted if another VM needs an AS slot. 805 + * This way, VMs keep attached to the AS they were given until we run 806 + * out of free slot, limiting the number of MMU operations (TLB flush 807 + * and other AS updates). 808 + */ 809 + void panthor_vm_idle(struct panthor_vm *vm) 810 + { 811 + struct panthor_device *ptdev = vm->ptdev; 812 + 813 + if (!refcount_dec_and_mutex_lock(&vm->as.active_cnt, &ptdev->mmu->as.slots_lock)) 814 + return; 815 + 816 + if (!drm_WARN_ON(&ptdev->base, vm->as.id == -1 || !list_empty(&vm->as.lru_node))) 817 + list_add_tail(&vm->as.lru_node, &ptdev->mmu->as.lru_list); 818 + 819 + refcount_set(&vm->as.active_cnt, 0); 820 + mutex_unlock(&ptdev->mmu->as.slots_lock); 821 + } 822 + 823 + static void panthor_vm_stop(struct panthor_vm *vm) 824 + { 825 + drm_sched_stop(&vm->sched, NULL); 826 + } 827 + 828 + static void panthor_vm_start(struct panthor_vm *vm) 829 + { 830 + drm_sched_start(&vm->sched, true); 831 + } 832 + 833 + /** 834 + * panthor_vm_as() - Get the AS slot attached to a VM 835 + * @vm: VM to get the AS slot of. 836 + * 837 + * Return: -1 if the VM is not assigned an AS slot yet, >= 0 otherwise. 838 + */ 839 + int panthor_vm_as(struct panthor_vm *vm) 840 + { 841 + return vm->as.id; 842 + } 843 + 844 + static size_t get_pgsize(u64 addr, size_t size, size_t *count) 845 + { 846 + /* 847 + * io-pgtable only operates on multiple pages within a single table 848 + * entry, so we need to split at boundaries of the table size, i.e. 849 + * the next block size up. The distance from address A to the next 850 + * boundary of block size B is logically B - A % B, but in unsigned 851 + * two's complement where B is a power of two we get the equivalence 852 + * B - A % B == (B - A) % B == (n * B - A) % B, and choose n = 0 :) 853 + */ 854 + size_t blk_offset = -addr % SZ_2M; 855 + 856 + if (blk_offset || size < SZ_2M) { 857 + *count = min_not_zero(blk_offset, size) / SZ_4K; 858 + return SZ_4K; 859 + } 860 + blk_offset = -addr % SZ_1G ?: SZ_1G; 861 + *count = min(blk_offset, size) / SZ_2M; 862 + return SZ_2M; 863 + } 864 + 865 + static int panthor_vm_flush_range(struct panthor_vm *vm, u64 iova, u64 size) 866 + { 867 + struct panthor_device *ptdev = vm->ptdev; 868 + int ret = 0, cookie; 869 + 870 + if (vm->as.id < 0) 871 + return 0; 872 + 873 + /* If the device is unplugged, we just silently skip the flush. */ 874 + if (!drm_dev_enter(&ptdev->base, &cookie)) 875 + return 0; 876 + 877 + /* Flush the PTs only if we're already awake */ 878 + if (pm_runtime_active(ptdev->base.dev)) 879 + ret = mmu_hw_do_operation(vm, iova, size, AS_COMMAND_FLUSH_PT); 880 + 881 + drm_dev_exit(cookie); 882 + return ret; 883 + } 884 + 885 + static int panthor_vm_unmap_pages(struct panthor_vm *vm, u64 iova, u64 size) 886 + { 887 + struct panthor_device *ptdev = vm->ptdev; 888 + struct io_pgtable_ops *ops = vm->pgtbl_ops; 889 + u64 offset = 0; 890 + 891 + drm_dbg(&ptdev->base, "unmap: as=%d, iova=%llx, len=%llx", vm->as.id, iova, size); 892 + 893 + while (offset < size) { 894 + size_t unmapped_sz = 0, pgcount; 895 + size_t pgsize = get_pgsize(iova + offset, size - offset, &pgcount); 896 + 897 + unmapped_sz = ops->unmap_pages(ops, iova + offset, pgsize, pgcount, NULL); 898 + 899 + if (drm_WARN_ON(&ptdev->base, unmapped_sz != pgsize * pgcount)) { 900 + drm_err(&ptdev->base, "failed to unmap range %llx-%llx (requested range %llx-%llx)\n", 901 + iova + offset + unmapped_sz, 902 + iova + offset + pgsize * pgcount, 903 + iova, iova + size); 904 + panthor_vm_flush_range(vm, iova, offset + unmapped_sz); 905 + return -EINVAL; 906 + } 907 + offset += unmapped_sz; 908 + } 909 + 910 + return panthor_vm_flush_range(vm, iova, size); 911 + } 912 + 913 + static int 914 + panthor_vm_map_pages(struct panthor_vm *vm, u64 iova, int prot, 915 + struct sg_table *sgt, u64 offset, u64 size) 916 + { 917 + struct panthor_device *ptdev = vm->ptdev; 918 + unsigned int count; 919 + struct scatterlist *sgl; 920 + struct io_pgtable_ops *ops = vm->pgtbl_ops; 921 + u64 start_iova = iova; 922 + int ret; 923 + 924 + if (!size) 925 + return 0; 926 + 927 + for_each_sgtable_dma_sg(sgt, sgl, count) { 928 + dma_addr_t paddr = sg_dma_address(sgl); 929 + size_t len = sg_dma_len(sgl); 930 + 931 + if (len <= offset) { 932 + offset -= len; 933 + continue; 934 + } 935 + 936 + paddr += offset; 937 + len -= offset; 938 + len = min_t(size_t, len, size); 939 + size -= len; 940 + 941 + drm_dbg(&ptdev->base, "map: as=%d, iova=%llx, paddr=%pad, len=%zx", 942 + vm->as.id, iova, &paddr, len); 943 + 944 + while (len) { 945 + size_t pgcount, mapped = 0; 946 + size_t pgsize = get_pgsize(iova | paddr, len, &pgcount); 947 + 948 + ret = ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, 949 + GFP_KERNEL, &mapped); 950 + iova += mapped; 951 + paddr += mapped; 952 + len -= mapped; 953 + 954 + if (drm_WARN_ON(&ptdev->base, !ret && !mapped)) 955 + ret = -ENOMEM; 956 + 957 + if (ret) { 958 + /* If something failed, unmap what we've already mapped before 959 + * returning. The unmap call is not supposed to fail. 960 + */ 961 + drm_WARN_ON(&ptdev->base, 962 + panthor_vm_unmap_pages(vm, start_iova, 963 + iova - start_iova)); 964 + return ret; 965 + } 966 + } 967 + 968 + if (!size) 969 + break; 970 + } 971 + 972 + return panthor_vm_flush_range(vm, start_iova, iova - start_iova); 973 + } 974 + 975 + static int flags_to_prot(u32 flags) 976 + { 977 + int prot = 0; 978 + 979 + if (flags & DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC) 980 + prot |= IOMMU_NOEXEC; 981 + 982 + if (!(flags & DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED)) 983 + prot |= IOMMU_CACHE; 984 + 985 + if (flags & DRM_PANTHOR_VM_BIND_OP_MAP_READONLY) 986 + prot |= IOMMU_READ; 987 + else 988 + prot |= IOMMU_READ | IOMMU_WRITE; 989 + 990 + return prot; 991 + } 992 + 993 + /** 994 + * panthor_vm_alloc_va() - Allocate a region in the auto-va space 995 + * @VM: VM to allocate a region on. 996 + * @va: start of the VA range. Can be PANTHOR_VM_KERNEL_AUTO_VA if the user 997 + * wants the VA to be automatically allocated from the auto-VA range. 998 + * @size: size of the VA range. 999 + * @va_node: drm_mm_node to initialize. Must be zero-initialized. 1000 + * 1001 + * Some GPU objects, like heap chunks, are fully managed by the kernel and 1002 + * need to be mapped to the userspace VM, in the region reserved for kernel 1003 + * objects. 1004 + * 1005 + * This function takes care of allocating a region in the kernel auto-VA space. 1006 + * 1007 + * Return: 0 on success, an error code otherwise. 1008 + */ 1009 + int 1010 + panthor_vm_alloc_va(struct panthor_vm *vm, u64 va, u64 size, 1011 + struct drm_mm_node *va_node) 1012 + { 1013 + int ret; 1014 + 1015 + if (!size || (size & ~PAGE_MASK)) 1016 + return -EINVAL; 1017 + 1018 + if (va != PANTHOR_VM_KERNEL_AUTO_VA && (va & ~PAGE_MASK)) 1019 + return -EINVAL; 1020 + 1021 + mutex_lock(&vm->mm_lock); 1022 + if (va != PANTHOR_VM_KERNEL_AUTO_VA) { 1023 + va_node->start = va; 1024 + va_node->size = size; 1025 + ret = drm_mm_reserve_node(&vm->mm, va_node); 1026 + } else { 1027 + ret = drm_mm_insert_node_in_range(&vm->mm, va_node, size, 1028 + size >= SZ_2M ? SZ_2M : SZ_4K, 1029 + 0, vm->kernel_auto_va.start, 1030 + vm->kernel_auto_va.end, 1031 + DRM_MM_INSERT_BEST); 1032 + } 1033 + mutex_unlock(&vm->mm_lock); 1034 + 1035 + return ret; 1036 + } 1037 + 1038 + /** 1039 + * panthor_vm_free_va() - Free a region allocated with panthor_vm_alloc_va() 1040 + * @VM: VM to free the region on. 1041 + * @va_node: Memory node representing the region to free. 1042 + */ 1043 + void panthor_vm_free_va(struct panthor_vm *vm, struct drm_mm_node *va_node) 1044 + { 1045 + mutex_lock(&vm->mm_lock); 1046 + drm_mm_remove_node(va_node); 1047 + mutex_unlock(&vm->mm_lock); 1048 + } 1049 + 1050 + static void panthor_vm_bo_put(struct drm_gpuvm_bo *vm_bo) 1051 + { 1052 + struct panthor_gem_object *bo = to_panthor_bo(vm_bo->obj); 1053 + struct drm_gpuvm *vm = vm_bo->vm; 1054 + bool unpin; 1055 + 1056 + /* We must retain the GEM before calling drm_gpuvm_bo_put(), 1057 + * otherwise the mutex might be destroyed while we hold it. 1058 + * Same goes for the VM, since we take the VM resv lock. 1059 + */ 1060 + drm_gem_object_get(&bo->base.base); 1061 + drm_gpuvm_get(vm); 1062 + 1063 + /* We take the resv lock to protect against concurrent accesses to the 1064 + * gpuvm evicted/extobj lists that are modified in 1065 + * drm_gpuvm_bo_destroy(), which is called if drm_gpuvm_bo_put() 1066 + * releases sthe last vm_bo reference. 1067 + * We take the BO GPUVA list lock to protect the vm_bo removal from the 1068 + * GEM vm_bo list. 1069 + */ 1070 + dma_resv_lock(drm_gpuvm_resv(vm), NULL); 1071 + mutex_lock(&bo->gpuva_list_lock); 1072 + unpin = drm_gpuvm_bo_put(vm_bo); 1073 + mutex_unlock(&bo->gpuva_list_lock); 1074 + dma_resv_unlock(drm_gpuvm_resv(vm)); 1075 + 1076 + /* If the vm_bo object was destroyed, release the pin reference that 1077 + * was hold by this object. 1078 + */ 1079 + if (unpin && !bo->base.base.import_attach) 1080 + drm_gem_shmem_unpin(&bo->base); 1081 + 1082 + drm_gpuvm_put(vm); 1083 + drm_gem_object_put(&bo->base.base); 1084 + } 1085 + 1086 + static void panthor_vm_cleanup_op_ctx(struct panthor_vm_op_ctx *op_ctx, 1087 + struct panthor_vm *vm) 1088 + { 1089 + struct panthor_vma *vma, *tmp_vma; 1090 + 1091 + u32 remaining_pt_count = op_ctx->rsvd_page_tables.count - 1092 + op_ctx->rsvd_page_tables.ptr; 1093 + 1094 + if (remaining_pt_count) { 1095 + kmem_cache_free_bulk(pt_cache, remaining_pt_count, 1096 + op_ctx->rsvd_page_tables.pages + 1097 + op_ctx->rsvd_page_tables.ptr); 1098 + } 1099 + 1100 + kfree(op_ctx->rsvd_page_tables.pages); 1101 + 1102 + if (op_ctx->map.vm_bo) 1103 + panthor_vm_bo_put(op_ctx->map.vm_bo); 1104 + 1105 + for (u32 i = 0; i < ARRAY_SIZE(op_ctx->preallocated_vmas); i++) 1106 + kfree(op_ctx->preallocated_vmas[i]); 1107 + 1108 + list_for_each_entry_safe(vma, tmp_vma, &op_ctx->returned_vmas, node) { 1109 + list_del(&vma->node); 1110 + panthor_vm_bo_put(vma->base.vm_bo); 1111 + kfree(vma); 1112 + } 1113 + } 1114 + 1115 + static struct panthor_vma * 1116 + panthor_vm_op_ctx_get_vma(struct panthor_vm_op_ctx *op_ctx) 1117 + { 1118 + for (u32 i = 0; i < ARRAY_SIZE(op_ctx->preallocated_vmas); i++) { 1119 + struct panthor_vma *vma = op_ctx->preallocated_vmas[i]; 1120 + 1121 + if (vma) { 1122 + op_ctx->preallocated_vmas[i] = NULL; 1123 + return vma; 1124 + } 1125 + } 1126 + 1127 + return NULL; 1128 + } 1129 + 1130 + static int 1131 + panthor_vm_op_ctx_prealloc_vmas(struct panthor_vm_op_ctx *op_ctx) 1132 + { 1133 + u32 vma_count; 1134 + 1135 + switch (op_ctx->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) { 1136 + case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP: 1137 + /* One VMA for the new mapping, and two more VMAs for the remap case 1138 + * which might contain both a prev and next VA. 1139 + */ 1140 + vma_count = 3; 1141 + break; 1142 + 1143 + case DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP: 1144 + /* Partial unmaps might trigger a remap with either a prev or a next VA, 1145 + * but not both. 1146 + */ 1147 + vma_count = 1; 1148 + break; 1149 + 1150 + default: 1151 + return 0; 1152 + } 1153 + 1154 + for (u32 i = 0; i < vma_count; i++) { 1155 + struct panthor_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL); 1156 + 1157 + if (!vma) 1158 + return -ENOMEM; 1159 + 1160 + op_ctx->preallocated_vmas[i] = vma; 1161 + } 1162 + 1163 + return 0; 1164 + } 1165 + 1166 + #define PANTHOR_VM_BIND_OP_MAP_FLAGS \ 1167 + (DRM_PANTHOR_VM_BIND_OP_MAP_READONLY | \ 1168 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | \ 1169 + DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED | \ 1170 + DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) 1171 + 1172 + static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, 1173 + struct panthor_vm *vm, 1174 + struct panthor_gem_object *bo, 1175 + u64 offset, 1176 + u64 size, u64 va, 1177 + u32 flags) 1178 + { 1179 + struct drm_gpuvm_bo *preallocated_vm_bo; 1180 + struct sg_table *sgt = NULL; 1181 + u64 pt_count; 1182 + int ret; 1183 + 1184 + if (!bo) 1185 + return -EINVAL; 1186 + 1187 + if ((flags & ~PANTHOR_VM_BIND_OP_MAP_FLAGS) || 1188 + (flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) != DRM_PANTHOR_VM_BIND_OP_TYPE_MAP) 1189 + return -EINVAL; 1190 + 1191 + /* Make sure the VA and size are aligned and in-bounds. */ 1192 + if (size > bo->base.base.size || offset > bo->base.base.size - size) 1193 + return -EINVAL; 1194 + 1195 + /* If the BO has an exclusive VM attached, it can't be mapped to other VMs. */ 1196 + if (bo->exclusive_vm_root_gem && 1197 + bo->exclusive_vm_root_gem != panthor_vm_root_gem(vm)) 1198 + return -EINVAL; 1199 + 1200 + memset(op_ctx, 0, sizeof(*op_ctx)); 1201 + INIT_LIST_HEAD(&op_ctx->returned_vmas); 1202 + op_ctx->flags = flags; 1203 + op_ctx->va.range = size; 1204 + op_ctx->va.addr = va; 1205 + 1206 + ret = panthor_vm_op_ctx_prealloc_vmas(op_ctx); 1207 + if (ret) 1208 + goto err_cleanup; 1209 + 1210 + if (!bo->base.base.import_attach) { 1211 + /* Pre-reserve the BO pages, so the map operation doesn't have to 1212 + * allocate. 1213 + */ 1214 + ret = drm_gem_shmem_pin(&bo->base); 1215 + if (ret) 1216 + goto err_cleanup; 1217 + } 1218 + 1219 + sgt = drm_gem_shmem_get_pages_sgt(&bo->base); 1220 + if (IS_ERR(sgt)) { 1221 + if (!bo->base.base.import_attach) 1222 + drm_gem_shmem_unpin(&bo->base); 1223 + 1224 + ret = PTR_ERR(sgt); 1225 + goto err_cleanup; 1226 + } 1227 + 1228 + op_ctx->map.sgt = sgt; 1229 + 1230 + preallocated_vm_bo = drm_gpuvm_bo_create(&vm->base, &bo->base.base); 1231 + if (!preallocated_vm_bo) { 1232 + if (!bo->base.base.import_attach) 1233 + drm_gem_shmem_unpin(&bo->base); 1234 + 1235 + ret = -ENOMEM; 1236 + goto err_cleanup; 1237 + } 1238 + 1239 + mutex_lock(&bo->gpuva_list_lock); 1240 + op_ctx->map.vm_bo = drm_gpuvm_bo_obtain_prealloc(preallocated_vm_bo); 1241 + mutex_unlock(&bo->gpuva_list_lock); 1242 + 1243 + /* If the a vm_bo for this <VM,BO> combination exists, it already 1244 + * retains a pin ref, and we can release the one we took earlier. 1245 + * 1246 + * If our pre-allocated vm_bo is picked, it now retains the pin ref, 1247 + * which will be released in panthor_vm_bo_put(). 1248 + */ 1249 + if (preallocated_vm_bo != op_ctx->map.vm_bo && 1250 + !bo->base.base.import_attach) 1251 + drm_gem_shmem_unpin(&bo->base); 1252 + 1253 + op_ctx->map.bo_offset = offset; 1254 + 1255 + /* L1, L2 and L3 page tables. 1256 + * We could optimize L3 allocation by iterating over the sgt and merging 1257 + * 2M contiguous blocks, but it's simpler to over-provision and return 1258 + * the pages if they're not used. 1259 + */ 1260 + pt_count = ((ALIGN(va + size, 1ull << 39) - ALIGN_DOWN(va, 1ull << 39)) >> 39) + 1261 + ((ALIGN(va + size, 1ull << 30) - ALIGN_DOWN(va, 1ull << 30)) >> 30) + 1262 + ((ALIGN(va + size, 1ull << 21) - ALIGN_DOWN(va, 1ull << 21)) >> 21); 1263 + 1264 + op_ctx->rsvd_page_tables.pages = kcalloc(pt_count, 1265 + sizeof(*op_ctx->rsvd_page_tables.pages), 1266 + GFP_KERNEL); 1267 + if (!op_ctx->rsvd_page_tables.pages) 1268 + goto err_cleanup; 1269 + 1270 + ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, 1271 + op_ctx->rsvd_page_tables.pages); 1272 + op_ctx->rsvd_page_tables.count = ret; 1273 + if (ret != pt_count) { 1274 + ret = -ENOMEM; 1275 + goto err_cleanup; 1276 + } 1277 + 1278 + /* Insert BO into the extobj list last, when we know nothing can fail. */ 1279 + dma_resv_lock(panthor_vm_resv(vm), NULL); 1280 + drm_gpuvm_bo_extobj_add(op_ctx->map.vm_bo); 1281 + dma_resv_unlock(panthor_vm_resv(vm)); 1282 + 1283 + return 0; 1284 + 1285 + err_cleanup: 1286 + panthor_vm_cleanup_op_ctx(op_ctx, vm); 1287 + return ret; 1288 + } 1289 + 1290 + static int panthor_vm_prepare_unmap_op_ctx(struct panthor_vm_op_ctx *op_ctx, 1291 + struct panthor_vm *vm, 1292 + u64 va, u64 size) 1293 + { 1294 + u32 pt_count = 0; 1295 + int ret; 1296 + 1297 + memset(op_ctx, 0, sizeof(*op_ctx)); 1298 + INIT_LIST_HEAD(&op_ctx->returned_vmas); 1299 + op_ctx->va.range = size; 1300 + op_ctx->va.addr = va; 1301 + op_ctx->flags = DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP; 1302 + 1303 + /* Pre-allocate L3 page tables to account for the split-2M-block 1304 + * situation on unmap. 1305 + */ 1306 + if (va != ALIGN(va, SZ_2M)) 1307 + pt_count++; 1308 + 1309 + if (va + size != ALIGN(va + size, SZ_2M) && 1310 + ALIGN(va + size, SZ_2M) != ALIGN(va, SZ_2M)) 1311 + pt_count++; 1312 + 1313 + ret = panthor_vm_op_ctx_prealloc_vmas(op_ctx); 1314 + if (ret) 1315 + goto err_cleanup; 1316 + 1317 + if (pt_count) { 1318 + op_ctx->rsvd_page_tables.pages = kcalloc(pt_count, 1319 + sizeof(*op_ctx->rsvd_page_tables.pages), 1320 + GFP_KERNEL); 1321 + if (!op_ctx->rsvd_page_tables.pages) 1322 + goto err_cleanup; 1323 + 1324 + ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count, 1325 + op_ctx->rsvd_page_tables.pages); 1326 + if (ret != pt_count) { 1327 + ret = -ENOMEM; 1328 + goto err_cleanup; 1329 + } 1330 + op_ctx->rsvd_page_tables.count = pt_count; 1331 + } 1332 + 1333 + return 0; 1334 + 1335 + err_cleanup: 1336 + panthor_vm_cleanup_op_ctx(op_ctx, vm); 1337 + return ret; 1338 + } 1339 + 1340 + static void panthor_vm_prepare_sync_only_op_ctx(struct panthor_vm_op_ctx *op_ctx, 1341 + struct panthor_vm *vm) 1342 + { 1343 + memset(op_ctx, 0, sizeof(*op_ctx)); 1344 + INIT_LIST_HEAD(&op_ctx->returned_vmas); 1345 + op_ctx->flags = DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY; 1346 + } 1347 + 1348 + /** 1349 + * panthor_vm_get_bo_for_va() - Get the GEM object mapped at a virtual address 1350 + * @vm: VM to look into. 1351 + * @va: Virtual address to search for. 1352 + * @bo_offset: Offset of the GEM object mapped at this virtual address. 1353 + * Only valid on success. 1354 + * 1355 + * The object returned by this function might no longer be mapped when the 1356 + * function returns. It's the caller responsibility to ensure there's no 1357 + * concurrent map/unmap operations making the returned value invalid, or 1358 + * make sure it doesn't matter if the object is no longer mapped. 1359 + * 1360 + * Return: A valid pointer on success, an ERR_PTR() otherwise. 1361 + */ 1362 + struct panthor_gem_object * 1363 + panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 va, u64 *bo_offset) 1364 + { 1365 + struct panthor_gem_object *bo = ERR_PTR(-ENOENT); 1366 + struct drm_gpuva *gpuva; 1367 + struct panthor_vma *vma; 1368 + 1369 + /* Take the VM lock to prevent concurrent map/unmap operations. */ 1370 + mutex_lock(&vm->op_lock); 1371 + gpuva = drm_gpuva_find_first(&vm->base, va, 1); 1372 + vma = gpuva ? container_of(gpuva, struct panthor_vma, base) : NULL; 1373 + if (vma && vma->base.gem.obj) { 1374 + drm_gem_object_get(vma->base.gem.obj); 1375 + bo = to_panthor_bo(vma->base.gem.obj); 1376 + *bo_offset = vma->base.gem.offset + (va - vma->base.va.addr); 1377 + } 1378 + mutex_unlock(&vm->op_lock); 1379 + 1380 + return bo; 1381 + } 1382 + 1383 + #define PANTHOR_VM_MIN_KERNEL_VA_SIZE SZ_256M 1384 + 1385 + static u64 1386 + panthor_vm_create_get_user_va_range(const struct drm_panthor_vm_create *args, 1387 + u64 full_va_range) 1388 + { 1389 + u64 user_va_range; 1390 + 1391 + /* Make sure we have a minimum amount of VA space for kernel objects. */ 1392 + if (full_va_range < PANTHOR_VM_MIN_KERNEL_VA_SIZE) 1393 + return 0; 1394 + 1395 + if (args->user_va_range) { 1396 + /* Use the user provided value if != 0. */ 1397 + user_va_range = args->user_va_range; 1398 + } else if (TASK_SIZE_OF(current) < full_va_range) { 1399 + /* If the task VM size is smaller than the GPU VA range, pick this 1400 + * as our default user VA range, so userspace can CPU/GPU map buffers 1401 + * at the same address. 1402 + */ 1403 + user_va_range = TASK_SIZE_OF(current); 1404 + } else { 1405 + /* If the GPU VA range is smaller than the task VM size, we 1406 + * just have to live with the fact we won't be able to map 1407 + * all buffers at the same GPU/CPU address. 1408 + * 1409 + * If the GPU VA range is bigger than 4G (more than 32-bit of 1410 + * VA), we split the range in two, and assign half of it to 1411 + * the user and the other half to the kernel, if it's not, we 1412 + * keep the kernel VA space as small as possible. 1413 + */ 1414 + user_va_range = full_va_range > SZ_4G ? 1415 + full_va_range / 2 : 1416 + full_va_range - PANTHOR_VM_MIN_KERNEL_VA_SIZE; 1417 + } 1418 + 1419 + if (full_va_range - PANTHOR_VM_MIN_KERNEL_VA_SIZE < user_va_range) 1420 + user_va_range = full_va_range - PANTHOR_VM_MIN_KERNEL_VA_SIZE; 1421 + 1422 + return user_va_range; 1423 + } 1424 + 1425 + #define PANTHOR_VM_CREATE_FLAGS 0 1426 + 1427 + static int 1428 + panthor_vm_create_check_args(const struct panthor_device *ptdev, 1429 + const struct drm_panthor_vm_create *args, 1430 + u64 *kernel_va_start, u64 *kernel_va_range) 1431 + { 1432 + u32 va_bits = GPU_MMU_FEATURES_VA_BITS(ptdev->gpu_info.mmu_features); 1433 + u64 full_va_range = 1ull << va_bits; 1434 + u64 user_va_range; 1435 + 1436 + if (args->flags & ~PANTHOR_VM_CREATE_FLAGS) 1437 + return -EINVAL; 1438 + 1439 + user_va_range = panthor_vm_create_get_user_va_range(args, full_va_range); 1440 + if (!user_va_range || (args->user_va_range && args->user_va_range > user_va_range)) 1441 + return -EINVAL; 1442 + 1443 + /* Pick a kernel VA range that's a power of two, to have a clear split. */ 1444 + *kernel_va_range = rounddown_pow_of_two(full_va_range - user_va_range); 1445 + *kernel_va_start = full_va_range - *kernel_va_range; 1446 + return 0; 1447 + } 1448 + 1449 + /* 1450 + * Only 32 VMs per open file. If that becomes a limiting factor, we can 1451 + * increase this number. 1452 + */ 1453 + #define PANTHOR_MAX_VMS_PER_FILE 32 1454 + 1455 + /** 1456 + * panthor_vm_pool_create_vm() - Create a VM 1457 + * @pool: The VM to create this VM on. 1458 + * @kernel_va_start: Start of the region reserved for kernel objects. 1459 + * @kernel_va_range: Size of the region reserved for kernel objects. 1460 + * 1461 + * Return: a positive VM ID on success, a negative error code otherwise. 1462 + */ 1463 + int panthor_vm_pool_create_vm(struct panthor_device *ptdev, 1464 + struct panthor_vm_pool *pool, 1465 + struct drm_panthor_vm_create *args) 1466 + { 1467 + u64 kernel_va_start, kernel_va_range; 1468 + struct panthor_vm *vm; 1469 + int ret; 1470 + u32 id; 1471 + 1472 + ret = panthor_vm_create_check_args(ptdev, args, &kernel_va_start, &kernel_va_range); 1473 + if (ret) 1474 + return ret; 1475 + 1476 + vm = panthor_vm_create(ptdev, false, kernel_va_start, kernel_va_range, 1477 + kernel_va_start, kernel_va_range); 1478 + if (IS_ERR(vm)) 1479 + return PTR_ERR(vm); 1480 + 1481 + ret = xa_alloc(&pool->xa, &id, vm, 1482 + XA_LIMIT(1, PANTHOR_MAX_VMS_PER_FILE), GFP_KERNEL); 1483 + 1484 + if (ret) { 1485 + panthor_vm_put(vm); 1486 + return ret; 1487 + } 1488 + 1489 + args->user_va_range = kernel_va_start; 1490 + return id; 1491 + } 1492 + 1493 + static void panthor_vm_destroy(struct panthor_vm *vm) 1494 + { 1495 + if (!vm) 1496 + return; 1497 + 1498 + vm->destroyed = true; 1499 + 1500 + mutex_lock(&vm->heaps.lock); 1501 + panthor_heap_pool_destroy(vm->heaps.pool); 1502 + vm->heaps.pool = NULL; 1503 + mutex_unlock(&vm->heaps.lock); 1504 + 1505 + drm_WARN_ON(&vm->ptdev->base, 1506 + panthor_vm_unmap_range(vm, vm->base.mm_start, vm->base.mm_range)); 1507 + panthor_vm_put(vm); 1508 + } 1509 + 1510 + /** 1511 + * panthor_vm_pool_destroy_vm() - Destroy a VM. 1512 + * @pool: VM pool. 1513 + * @handle: VM handle. 1514 + * 1515 + * This function doesn't free the VM object or its resources, it just kills 1516 + * all mappings, and makes sure nothing can be mapped after that point. 1517 + * 1518 + * If there was any active jobs at the time this function is called, these 1519 + * jobs should experience page faults and be killed as a result. 1520 + * 1521 + * The VM resources are freed when the last reference on the VM object is 1522 + * dropped. 1523 + */ 1524 + int panthor_vm_pool_destroy_vm(struct panthor_vm_pool *pool, u32 handle) 1525 + { 1526 + struct panthor_vm *vm; 1527 + 1528 + vm = xa_erase(&pool->xa, handle); 1529 + 1530 + panthor_vm_destroy(vm); 1531 + 1532 + return vm ? 0 : -EINVAL; 1533 + } 1534 + 1535 + /** 1536 + * panthor_vm_pool_get_vm() - Retrieve VM object bound to a VM handle 1537 + * @pool: VM pool to check. 1538 + * @handle: Handle of the VM to retrieve. 1539 + * 1540 + * Return: A valid pointer if the VM exists, NULL otherwise. 1541 + */ 1542 + struct panthor_vm * 1543 + panthor_vm_pool_get_vm(struct panthor_vm_pool *pool, u32 handle) 1544 + { 1545 + struct panthor_vm *vm; 1546 + 1547 + vm = panthor_vm_get(xa_load(&pool->xa, handle)); 1548 + 1549 + return vm; 1550 + } 1551 + 1552 + /** 1553 + * panthor_vm_pool_destroy() - Destroy a VM pool. 1554 + * @pfile: File. 1555 + * 1556 + * Destroy all VMs in the pool, and release the pool resources. 1557 + * 1558 + * Note that VMs can outlive the pool they were created from if other 1559 + * objects hold a reference to there VMs. 1560 + */ 1561 + void panthor_vm_pool_destroy(struct panthor_file *pfile) 1562 + { 1563 + struct panthor_vm *vm; 1564 + unsigned long i; 1565 + 1566 + if (!pfile->vms) 1567 + return; 1568 + 1569 + xa_for_each(&pfile->vms->xa, i, vm) 1570 + panthor_vm_destroy(vm); 1571 + 1572 + xa_destroy(&pfile->vms->xa); 1573 + kfree(pfile->vms); 1574 + } 1575 + 1576 + /** 1577 + * panthor_vm_pool_create() - Create a VM pool 1578 + * @pfile: File. 1579 + * 1580 + * Return: 0 on success, a negative error code otherwise. 1581 + */ 1582 + int panthor_vm_pool_create(struct panthor_file *pfile) 1583 + { 1584 + pfile->vms = kzalloc(sizeof(*pfile->vms), GFP_KERNEL); 1585 + if (!pfile->vms) 1586 + return -ENOMEM; 1587 + 1588 + xa_init_flags(&pfile->vms->xa, XA_FLAGS_ALLOC1); 1589 + return 0; 1590 + } 1591 + 1592 + /* dummy TLB ops, the real TLB flush happens in panthor_vm_flush_range() */ 1593 + static void mmu_tlb_flush_all(void *cookie) 1594 + { 1595 + } 1596 + 1597 + static void mmu_tlb_flush_walk(unsigned long iova, size_t size, size_t granule, void *cookie) 1598 + { 1599 + } 1600 + 1601 + static const struct iommu_flush_ops mmu_tlb_ops = { 1602 + .tlb_flush_all = mmu_tlb_flush_all, 1603 + .tlb_flush_walk = mmu_tlb_flush_walk, 1604 + }; 1605 + 1606 + static const char *access_type_name(struct panthor_device *ptdev, 1607 + u32 fault_status) 1608 + { 1609 + switch (fault_status & AS_FAULTSTATUS_ACCESS_TYPE_MASK) { 1610 + case AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC: 1611 + return "ATOMIC"; 1612 + case AS_FAULTSTATUS_ACCESS_TYPE_READ: 1613 + return "READ"; 1614 + case AS_FAULTSTATUS_ACCESS_TYPE_WRITE: 1615 + return "WRITE"; 1616 + case AS_FAULTSTATUS_ACCESS_TYPE_EX: 1617 + return "EXECUTE"; 1618 + default: 1619 + drm_WARN_ON(&ptdev->base, 1); 1620 + return NULL; 1621 + } 1622 + } 1623 + 1624 + static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) 1625 + { 1626 + bool has_unhandled_faults = false; 1627 + 1628 + status = panthor_mmu_fault_mask(ptdev, status); 1629 + while (status) { 1630 + u32 as = ffs(status | (status >> 16)) - 1; 1631 + u32 mask = panthor_mmu_as_fault_mask(ptdev, as); 1632 + u32 new_int_mask; 1633 + u64 addr; 1634 + u32 fault_status; 1635 + u32 exception_type; 1636 + u32 access_type; 1637 + u32 source_id; 1638 + 1639 + fault_status = gpu_read(ptdev, AS_FAULTSTATUS(as)); 1640 + addr = gpu_read(ptdev, AS_FAULTADDRESS_LO(as)); 1641 + addr |= (u64)gpu_read(ptdev, AS_FAULTADDRESS_HI(as)) << 32; 1642 + 1643 + /* decode the fault status */ 1644 + exception_type = fault_status & 0xFF; 1645 + access_type = (fault_status >> 8) & 0x3; 1646 + source_id = (fault_status >> 16); 1647 + 1648 + mutex_lock(&ptdev->mmu->as.slots_lock); 1649 + 1650 + ptdev->mmu->as.faulty_mask |= mask; 1651 + new_int_mask = 1652 + panthor_mmu_fault_mask(ptdev, ~ptdev->mmu->as.faulty_mask); 1653 + 1654 + /* terminal fault, print info about the fault */ 1655 + drm_err(&ptdev->base, 1656 + "Unhandled Page fault in AS%d at VA 0x%016llX\n" 1657 + "raw fault status: 0x%X\n" 1658 + "decoded fault status: %s\n" 1659 + "exception type 0x%X: %s\n" 1660 + "access type 0x%X: %s\n" 1661 + "source id 0x%X\n", 1662 + as, addr, 1663 + fault_status, 1664 + (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"), 1665 + exception_type, panthor_exception_name(ptdev, exception_type), 1666 + access_type, access_type_name(ptdev, fault_status), 1667 + source_id); 1668 + 1669 + /* Ignore MMU interrupts on this AS until it's been 1670 + * re-enabled. 1671 + */ 1672 + ptdev->mmu->irq.mask = new_int_mask; 1673 + gpu_write(ptdev, MMU_INT_MASK, new_int_mask); 1674 + 1675 + if (ptdev->mmu->as.slots[as].vm) 1676 + ptdev->mmu->as.slots[as].vm->unhandled_fault = true; 1677 + 1678 + /* Disable the MMU to kill jobs on this AS. */ 1679 + panthor_mmu_as_disable(ptdev, as); 1680 + mutex_unlock(&ptdev->mmu->as.slots_lock); 1681 + 1682 + status &= ~mask; 1683 + has_unhandled_faults = true; 1684 + } 1685 + 1686 + if (has_unhandled_faults) 1687 + panthor_sched_report_mmu_fault(ptdev); 1688 + } 1689 + PANTHOR_IRQ_HANDLER(mmu, MMU, panthor_mmu_irq_handler); 1690 + 1691 + /** 1692 + * panthor_mmu_suspend() - Suspend the MMU logic 1693 + * @ptdev: Device. 1694 + * 1695 + * All we do here is de-assign the AS slots on all active VMs, so things 1696 + * get flushed to the main memory, and no further access to these VMs are 1697 + * possible. 1698 + * 1699 + * We also suspend the MMU IRQ. 1700 + */ 1701 + void panthor_mmu_suspend(struct panthor_device *ptdev) 1702 + { 1703 + mutex_lock(&ptdev->mmu->as.slots_lock); 1704 + for (u32 i = 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { 1705 + struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm; 1706 + 1707 + if (vm) { 1708 + drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i)); 1709 + panthor_vm_release_as_locked(vm); 1710 + } 1711 + } 1712 + mutex_unlock(&ptdev->mmu->as.slots_lock); 1713 + 1714 + panthor_mmu_irq_suspend(&ptdev->mmu->irq); 1715 + } 1716 + 1717 + /** 1718 + * panthor_mmu_resume() - Resume the MMU logic 1719 + * @ptdev: Device. 1720 + * 1721 + * Resume the IRQ. 1722 + * 1723 + * We don't re-enable previously active VMs. We assume other parts of the 1724 + * driver will call panthor_vm_active() on the VMs they intend to use. 1725 + */ 1726 + void panthor_mmu_resume(struct panthor_device *ptdev) 1727 + { 1728 + mutex_lock(&ptdev->mmu->as.slots_lock); 1729 + ptdev->mmu->as.alloc_mask = 0; 1730 + ptdev->mmu->as.faulty_mask = 0; 1731 + mutex_unlock(&ptdev->mmu->as.slots_lock); 1732 + 1733 + panthor_mmu_irq_resume(&ptdev->mmu->irq, panthor_mmu_fault_mask(ptdev, ~0)); 1734 + } 1735 + 1736 + /** 1737 + * panthor_mmu_pre_reset() - Prepare for a reset 1738 + * @ptdev: Device. 1739 + * 1740 + * Suspend the IRQ, and make sure all VM_BIND queues are stopped, so we 1741 + * don't get asked to do a VM operation while the GPU is down. 1742 + * 1743 + * We don't cleanly shutdown the AS slots here, because the reset might 1744 + * come from an AS_ACTIVE_BIT stuck situation. 1745 + */ 1746 + void panthor_mmu_pre_reset(struct panthor_device *ptdev) 1747 + { 1748 + struct panthor_vm *vm; 1749 + 1750 + panthor_mmu_irq_suspend(&ptdev->mmu->irq); 1751 + 1752 + mutex_lock(&ptdev->mmu->vm.lock); 1753 + ptdev->mmu->vm.reset_in_progress = true; 1754 + list_for_each_entry(vm, &ptdev->mmu->vm.list, node) 1755 + panthor_vm_stop(vm); 1756 + mutex_unlock(&ptdev->mmu->vm.lock); 1757 + } 1758 + 1759 + /** 1760 + * panthor_mmu_post_reset() - Restore things after a reset 1761 + * @ptdev: Device. 1762 + * 1763 + * Put the MMU logic back in action after a reset. That implies resuming the 1764 + * IRQ and re-enabling the VM_BIND queues. 1765 + */ 1766 + void panthor_mmu_post_reset(struct panthor_device *ptdev) 1767 + { 1768 + struct panthor_vm *vm; 1769 + 1770 + mutex_lock(&ptdev->mmu->as.slots_lock); 1771 + 1772 + /* Now that the reset is effective, we can assume that none of the 1773 + * AS slots are setup, and clear the faulty flags too. 1774 + */ 1775 + ptdev->mmu->as.alloc_mask = 0; 1776 + ptdev->mmu->as.faulty_mask = 0; 1777 + 1778 + for (u32 i = 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { 1779 + struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm; 1780 + 1781 + if (vm) 1782 + panthor_vm_release_as_locked(vm); 1783 + } 1784 + 1785 + mutex_unlock(&ptdev->mmu->as.slots_lock); 1786 + 1787 + panthor_mmu_irq_resume(&ptdev->mmu->irq, panthor_mmu_fault_mask(ptdev, ~0)); 1788 + 1789 + /* Restart the VM_BIND queues. */ 1790 + mutex_lock(&ptdev->mmu->vm.lock); 1791 + list_for_each_entry(vm, &ptdev->mmu->vm.list, node) { 1792 + panthor_vm_start(vm); 1793 + } 1794 + ptdev->mmu->vm.reset_in_progress = false; 1795 + mutex_unlock(&ptdev->mmu->vm.lock); 1796 + } 1797 + 1798 + static void panthor_vm_free(struct drm_gpuvm *gpuvm) 1799 + { 1800 + struct panthor_vm *vm = container_of(gpuvm, struct panthor_vm, base); 1801 + struct panthor_device *ptdev = vm->ptdev; 1802 + 1803 + mutex_lock(&vm->heaps.lock); 1804 + if (drm_WARN_ON(&ptdev->base, vm->heaps.pool)) 1805 + panthor_heap_pool_destroy(vm->heaps.pool); 1806 + mutex_unlock(&vm->heaps.lock); 1807 + mutex_destroy(&vm->heaps.lock); 1808 + 1809 + mutex_lock(&ptdev->mmu->vm.lock); 1810 + list_del(&vm->node); 1811 + /* Restore the scheduler state so we can call drm_sched_entity_destroy() 1812 + * and drm_sched_fini(). If get there, that means we have no job left 1813 + * and no new jobs can be queued, so we can start the scheduler without 1814 + * risking interfering with the reset. 1815 + */ 1816 + if (ptdev->mmu->vm.reset_in_progress) 1817 + panthor_vm_start(vm); 1818 + mutex_unlock(&ptdev->mmu->vm.lock); 1819 + 1820 + drm_sched_entity_destroy(&vm->entity); 1821 + drm_sched_fini(&vm->sched); 1822 + 1823 + mutex_lock(&ptdev->mmu->as.slots_lock); 1824 + if (vm->as.id >= 0) { 1825 + int cookie; 1826 + 1827 + if (drm_dev_enter(&ptdev->base, &cookie)) { 1828 + panthor_mmu_as_disable(ptdev, vm->as.id); 1829 + drm_dev_exit(cookie); 1830 + } 1831 + 1832 + ptdev->mmu->as.slots[vm->as.id].vm = NULL; 1833 + clear_bit(vm->as.id, &ptdev->mmu->as.alloc_mask); 1834 + list_del(&vm->as.lru_node); 1835 + } 1836 + mutex_unlock(&ptdev->mmu->as.slots_lock); 1837 + 1838 + free_io_pgtable_ops(vm->pgtbl_ops); 1839 + 1840 + drm_mm_takedown(&vm->mm); 1841 + kfree(vm); 1842 + } 1843 + 1844 + /** 1845 + * panthor_vm_put() - Release a reference on a VM 1846 + * @vm: VM to release the reference on. Can be NULL. 1847 + */ 1848 + void panthor_vm_put(struct panthor_vm *vm) 1849 + { 1850 + drm_gpuvm_put(vm ? &vm->base : NULL); 1851 + } 1852 + 1853 + /** 1854 + * panthor_vm_get() - Get a VM reference 1855 + * @vm: VM to get the reference on. Can be NULL. 1856 + * 1857 + * Return: @vm value. 1858 + */ 1859 + struct panthor_vm *panthor_vm_get(struct panthor_vm *vm) 1860 + { 1861 + if (vm) 1862 + drm_gpuvm_get(&vm->base); 1863 + 1864 + return vm; 1865 + } 1866 + 1867 + /** 1868 + * panthor_vm_get_heap_pool() - Get the heap pool attached to a VM 1869 + * @vm: VM to query the heap pool on. 1870 + * @create: True if the heap pool should be created when it doesn't exist. 1871 + * 1872 + * Heap pools are per-VM. This function allows one to retrieve the heap pool 1873 + * attached to a VM. 1874 + * 1875 + * If no heap pool exists yet, and @create is true, we create one. 1876 + * 1877 + * The returned panthor_heap_pool should be released with panthor_heap_pool_put(). 1878 + * 1879 + * Return: A valid pointer on success, an ERR_PTR() otherwise. 1880 + */ 1881 + struct panthor_heap_pool *panthor_vm_get_heap_pool(struct panthor_vm *vm, bool create) 1882 + { 1883 + struct panthor_heap_pool *pool; 1884 + 1885 + mutex_lock(&vm->heaps.lock); 1886 + if (!vm->heaps.pool && create) { 1887 + if (vm->destroyed) 1888 + pool = ERR_PTR(-EINVAL); 1889 + else 1890 + pool = panthor_heap_pool_create(vm->ptdev, vm); 1891 + 1892 + if (!IS_ERR(pool)) 1893 + vm->heaps.pool = panthor_heap_pool_get(pool); 1894 + } else { 1895 + pool = panthor_heap_pool_get(vm->heaps.pool); 1896 + } 1897 + mutex_unlock(&vm->heaps.lock); 1898 + 1899 + return pool; 1900 + } 1901 + 1902 + static u64 mair_to_memattr(u64 mair) 1903 + { 1904 + u64 memattr = 0; 1905 + u32 i; 1906 + 1907 + for (i = 0; i < 8; i++) { 1908 + u8 in_attr = mair >> (8 * i), out_attr; 1909 + u8 outer = in_attr >> 4, inner = in_attr & 0xf; 1910 + 1911 + /* For caching to be enabled, inner and outer caching policy 1912 + * have to be both write-back, if one of them is write-through 1913 + * or non-cacheable, we just choose non-cacheable. Device 1914 + * memory is also translated to non-cacheable. 1915 + */ 1916 + if (!(outer & 3) || !(outer & 4) || !(inner & 4)) { 1917 + out_attr = AS_MEMATTR_AARCH64_INNER_OUTER_NC | 1918 + AS_MEMATTR_AARCH64_SH_MIDGARD_INNER | 1919 + AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(false, false); 1920 + } else { 1921 + /* Use SH_CPU_INNER mode so SH_IS, which is used when 1922 + * IOMMU_CACHE is set, actually maps to the standard 1923 + * definition of inner-shareable and not Mali's 1924 + * internal-shareable mode. 1925 + */ 1926 + out_attr = AS_MEMATTR_AARCH64_INNER_OUTER_WB | 1927 + AS_MEMATTR_AARCH64_SH_CPU_INNER | 1928 + AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(inner & 1, inner & 2); 1929 + } 1930 + 1931 + memattr |= (u64)out_attr << (8 * i); 1932 + } 1933 + 1934 + return memattr; 1935 + } 1936 + 1937 + static void panthor_vma_link(struct panthor_vm *vm, 1938 + struct panthor_vma *vma, 1939 + struct drm_gpuvm_bo *vm_bo) 1940 + { 1941 + struct panthor_gem_object *bo = to_panthor_bo(vma->base.gem.obj); 1942 + 1943 + mutex_lock(&bo->gpuva_list_lock); 1944 + drm_gpuva_link(&vma->base, vm_bo); 1945 + drm_WARN_ON(&vm->ptdev->base, drm_gpuvm_bo_put(vm_bo)); 1946 + mutex_unlock(&bo->gpuva_list_lock); 1947 + } 1948 + 1949 + static void panthor_vma_unlink(struct panthor_vm *vm, 1950 + struct panthor_vma *vma) 1951 + { 1952 + struct panthor_gem_object *bo = to_panthor_bo(vma->base.gem.obj); 1953 + struct drm_gpuvm_bo *vm_bo = drm_gpuvm_bo_get(vma->base.vm_bo); 1954 + 1955 + mutex_lock(&bo->gpuva_list_lock); 1956 + drm_gpuva_unlink(&vma->base); 1957 + mutex_unlock(&bo->gpuva_list_lock); 1958 + 1959 + /* drm_gpuva_unlink() release the vm_bo, but we manually retained it 1960 + * when entering this function, so we can implement deferred VMA 1961 + * destruction. Re-assign it here. 1962 + */ 1963 + vma->base.vm_bo = vm_bo; 1964 + list_add_tail(&vma->node, &vm->op_ctx->returned_vmas); 1965 + } 1966 + 1967 + static void panthor_vma_init(struct panthor_vma *vma, u32 flags) 1968 + { 1969 + INIT_LIST_HEAD(&vma->node); 1970 + vma->flags = flags; 1971 + } 1972 + 1973 + #define PANTHOR_VM_MAP_FLAGS \ 1974 + (DRM_PANTHOR_VM_BIND_OP_MAP_READONLY | \ 1975 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | \ 1976 + DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED) 1977 + 1978 + static int panthor_gpuva_sm_step_map(struct drm_gpuva_op *op, void *priv) 1979 + { 1980 + struct panthor_vm *vm = priv; 1981 + struct panthor_vm_op_ctx *op_ctx = vm->op_ctx; 1982 + struct panthor_vma *vma = panthor_vm_op_ctx_get_vma(op_ctx); 1983 + int ret; 1984 + 1985 + if (!vma) 1986 + return -EINVAL; 1987 + 1988 + panthor_vma_init(vma, op_ctx->flags & PANTHOR_VM_MAP_FLAGS); 1989 + 1990 + ret = panthor_vm_map_pages(vm, op->map.va.addr, flags_to_prot(vma->flags), 1991 + op_ctx->map.sgt, op->map.gem.offset, 1992 + op->map.va.range); 1993 + if (ret) 1994 + return ret; 1995 + 1996 + /* Ref owned by the mapping now, clear the obj field so we don't release the 1997 + * pinning/obj ref behind GPUVA's back. 1998 + */ 1999 + drm_gpuva_map(&vm->base, &vma->base, &op->map); 2000 + panthor_vma_link(vm, vma, op_ctx->map.vm_bo); 2001 + op_ctx->map.vm_bo = NULL; 2002 + return 0; 2003 + } 2004 + 2005 + static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op, 2006 + void *priv) 2007 + { 2008 + struct panthor_vma *unmap_vma = container_of(op->remap.unmap->va, struct panthor_vma, base); 2009 + struct panthor_vm *vm = priv; 2010 + struct panthor_vm_op_ctx *op_ctx = vm->op_ctx; 2011 + struct panthor_vma *prev_vma = NULL, *next_vma = NULL; 2012 + u64 unmap_start, unmap_range; 2013 + int ret; 2014 + 2015 + drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range); 2016 + ret = panthor_vm_unmap_pages(vm, unmap_start, unmap_range); 2017 + if (ret) 2018 + return ret; 2019 + 2020 + if (op->remap.prev) { 2021 + prev_vma = panthor_vm_op_ctx_get_vma(op_ctx); 2022 + panthor_vma_init(prev_vma, unmap_vma->flags); 2023 + } 2024 + 2025 + if (op->remap.next) { 2026 + next_vma = panthor_vm_op_ctx_get_vma(op_ctx); 2027 + panthor_vma_init(next_vma, unmap_vma->flags); 2028 + } 2029 + 2030 + drm_gpuva_remap(prev_vma ? &prev_vma->base : NULL, 2031 + next_vma ? &next_vma->base : NULL, 2032 + &op->remap); 2033 + 2034 + if (prev_vma) { 2035 + /* panthor_vma_link() transfers the vm_bo ownership to 2036 + * the VMA object. Since the vm_bo we're passing is still 2037 + * owned by the old mapping which will be released when this 2038 + * mapping is destroyed, we need to grab a ref here. 2039 + */ 2040 + panthor_vma_link(vm, prev_vma, 2041 + drm_gpuvm_bo_get(op->remap.unmap->va->vm_bo)); 2042 + } 2043 + 2044 + if (next_vma) { 2045 + panthor_vma_link(vm, next_vma, 2046 + drm_gpuvm_bo_get(op->remap.unmap->va->vm_bo)); 2047 + } 2048 + 2049 + panthor_vma_unlink(vm, unmap_vma); 2050 + return 0; 2051 + } 2052 + 2053 + static int panthor_gpuva_sm_step_unmap(struct drm_gpuva_op *op, 2054 + void *priv) 2055 + { 2056 + struct panthor_vma *unmap_vma = container_of(op->unmap.va, struct panthor_vma, base); 2057 + struct panthor_vm *vm = priv; 2058 + int ret; 2059 + 2060 + ret = panthor_vm_unmap_pages(vm, unmap_vma->base.va.addr, 2061 + unmap_vma->base.va.range); 2062 + if (drm_WARN_ON(&vm->ptdev->base, ret)) 2063 + return ret; 2064 + 2065 + drm_gpuva_unmap(&op->unmap); 2066 + panthor_vma_unlink(vm, unmap_vma); 2067 + return 0; 2068 + } 2069 + 2070 + static const struct drm_gpuvm_ops panthor_gpuvm_ops = { 2071 + .vm_free = panthor_vm_free, 2072 + .sm_step_map = panthor_gpuva_sm_step_map, 2073 + .sm_step_remap = panthor_gpuva_sm_step_remap, 2074 + .sm_step_unmap = panthor_gpuva_sm_step_unmap, 2075 + }; 2076 + 2077 + /** 2078 + * panthor_vm_resv() - Get the dma_resv object attached to a VM. 2079 + * @vm: VM to get the dma_resv of. 2080 + * 2081 + * Return: A dma_resv object. 2082 + */ 2083 + struct dma_resv *panthor_vm_resv(struct panthor_vm *vm) 2084 + { 2085 + return drm_gpuvm_resv(&vm->base); 2086 + } 2087 + 2088 + struct drm_gem_object *panthor_vm_root_gem(struct panthor_vm *vm) 2089 + { 2090 + if (!vm) 2091 + return NULL; 2092 + 2093 + return vm->base.r_obj; 2094 + } 2095 + 2096 + static int 2097 + panthor_vm_exec_op(struct panthor_vm *vm, struct panthor_vm_op_ctx *op, 2098 + bool flag_vm_unusable_on_failure) 2099 + { 2100 + u32 op_type = op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK; 2101 + int ret; 2102 + 2103 + if (op_type == DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY) 2104 + return 0; 2105 + 2106 + mutex_lock(&vm->op_lock); 2107 + vm->op_ctx = op; 2108 + switch (op_type) { 2109 + case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP: 2110 + if (vm->unusable) { 2111 + ret = -EINVAL; 2112 + break; 2113 + } 2114 + 2115 + ret = drm_gpuvm_sm_map(&vm->base, vm, op->va.addr, op->va.range, 2116 + op->map.vm_bo->obj, op->map.bo_offset); 2117 + break; 2118 + 2119 + case DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP: 2120 + ret = drm_gpuvm_sm_unmap(&vm->base, vm, op->va.addr, op->va.range); 2121 + break; 2122 + 2123 + default: 2124 + ret = -EINVAL; 2125 + break; 2126 + } 2127 + 2128 + if (ret && flag_vm_unusable_on_failure) 2129 + vm->unusable = true; 2130 + 2131 + vm->op_ctx = NULL; 2132 + mutex_unlock(&vm->op_lock); 2133 + 2134 + return ret; 2135 + } 2136 + 2137 + static struct dma_fence * 2138 + panthor_vm_bind_run_job(struct drm_sched_job *sched_job) 2139 + { 2140 + struct panthor_vm_bind_job *job = container_of(sched_job, struct panthor_vm_bind_job, base); 2141 + bool cookie; 2142 + int ret; 2143 + 2144 + /* Not only we report an error whose result is propagated to the 2145 + * drm_sched finished fence, but we also flag the VM as unusable, because 2146 + * a failure in the async VM_BIND results in an inconsistent state. VM needs 2147 + * to be destroyed and recreated. 2148 + */ 2149 + cookie = dma_fence_begin_signalling(); 2150 + ret = panthor_vm_exec_op(job->vm, &job->ctx, true); 2151 + dma_fence_end_signalling(cookie); 2152 + 2153 + return ret ? ERR_PTR(ret) : NULL; 2154 + } 2155 + 2156 + static void panthor_vm_bind_job_release(struct kref *kref) 2157 + { 2158 + struct panthor_vm_bind_job *job = container_of(kref, struct panthor_vm_bind_job, refcount); 2159 + 2160 + if (job->base.s_fence) 2161 + drm_sched_job_cleanup(&job->base); 2162 + 2163 + panthor_vm_cleanup_op_ctx(&job->ctx, job->vm); 2164 + panthor_vm_put(job->vm); 2165 + kfree(job); 2166 + } 2167 + 2168 + /** 2169 + * panthor_vm_bind_job_put() - Release a VM_BIND job reference 2170 + * @sched_job: Job to release the reference on. 2171 + */ 2172 + void panthor_vm_bind_job_put(struct drm_sched_job *sched_job) 2173 + { 2174 + struct panthor_vm_bind_job *job = 2175 + container_of(sched_job, struct panthor_vm_bind_job, base); 2176 + 2177 + if (sched_job) 2178 + kref_put(&job->refcount, panthor_vm_bind_job_release); 2179 + } 2180 + 2181 + static void 2182 + panthor_vm_bind_free_job(struct drm_sched_job *sched_job) 2183 + { 2184 + struct panthor_vm_bind_job *job = 2185 + container_of(sched_job, struct panthor_vm_bind_job, base); 2186 + 2187 + drm_sched_job_cleanup(sched_job); 2188 + 2189 + /* Do the heavy cleanups asynchronously, so we're out of the 2190 + * dma-signaling path and can acquire dma-resv locks safely. 2191 + */ 2192 + queue_work(panthor_cleanup_wq, &job->cleanup_op_ctx_work); 2193 + } 2194 + 2195 + static enum drm_gpu_sched_stat 2196 + panthor_vm_bind_timedout_job(struct drm_sched_job *sched_job) 2197 + { 2198 + WARN(1, "VM_BIND ops are synchronous for now, there should be no timeout!"); 2199 + return DRM_GPU_SCHED_STAT_NOMINAL; 2200 + } 2201 + 2202 + static const struct drm_sched_backend_ops panthor_vm_bind_ops = { 2203 + .run_job = panthor_vm_bind_run_job, 2204 + .free_job = panthor_vm_bind_free_job, 2205 + .timedout_job = panthor_vm_bind_timedout_job, 2206 + }; 2207 + 2208 + /** 2209 + * panthor_vm_create() - Create a VM 2210 + * @ptdev: Device. 2211 + * @for_mcu: True if this is the FW MCU VM. 2212 + * @kernel_va_start: Start of the range reserved for kernel BO mapping. 2213 + * @kernel_va_size: Size of the range reserved for kernel BO mapping. 2214 + * @auto_kernel_va_start: Start of the auto-VA kernel range. 2215 + * @auto_kernel_va_size: Size of the auto-VA kernel range. 2216 + * 2217 + * Return: A valid pointer on success, an ERR_PTR() otherwise. 2218 + */ 2219 + struct panthor_vm * 2220 + panthor_vm_create(struct panthor_device *ptdev, bool for_mcu, 2221 + u64 kernel_va_start, u64 kernel_va_size, 2222 + u64 auto_kernel_va_start, u64 auto_kernel_va_size) 2223 + { 2224 + u32 va_bits = GPU_MMU_FEATURES_VA_BITS(ptdev->gpu_info.mmu_features); 2225 + u32 pa_bits = GPU_MMU_FEATURES_PA_BITS(ptdev->gpu_info.mmu_features); 2226 + u64 full_va_range = 1ull << va_bits; 2227 + struct drm_gem_object *dummy_gem; 2228 + struct drm_gpu_scheduler *sched; 2229 + struct io_pgtable_cfg pgtbl_cfg; 2230 + u64 mair, min_va, va_range; 2231 + struct panthor_vm *vm; 2232 + int ret; 2233 + 2234 + vm = kzalloc(sizeof(*vm), GFP_KERNEL); 2235 + if (!vm) 2236 + return ERR_PTR(-ENOMEM); 2237 + 2238 + /* We allocate a dummy GEM for the VM. */ 2239 + dummy_gem = drm_gpuvm_resv_object_alloc(&ptdev->base); 2240 + if (!dummy_gem) { 2241 + ret = -ENOMEM; 2242 + goto err_free_vm; 2243 + } 2244 + 2245 + mutex_init(&vm->heaps.lock); 2246 + vm->for_mcu = for_mcu; 2247 + vm->ptdev = ptdev; 2248 + mutex_init(&vm->op_lock); 2249 + 2250 + if (for_mcu) { 2251 + /* CSF MCU is a cortex M7, and can only address 4G */ 2252 + min_va = 0; 2253 + va_range = SZ_4G; 2254 + } else { 2255 + min_va = 0; 2256 + va_range = full_va_range; 2257 + } 2258 + 2259 + mutex_init(&vm->mm_lock); 2260 + drm_mm_init(&vm->mm, kernel_va_start, kernel_va_size); 2261 + vm->kernel_auto_va.start = auto_kernel_va_start; 2262 + vm->kernel_auto_va.end = vm->kernel_auto_va.start + auto_kernel_va_size - 1; 2263 + 2264 + INIT_LIST_HEAD(&vm->node); 2265 + INIT_LIST_HEAD(&vm->as.lru_node); 2266 + vm->as.id = -1; 2267 + refcount_set(&vm->as.active_cnt, 0); 2268 + 2269 + pgtbl_cfg = (struct io_pgtable_cfg) { 2270 + .pgsize_bitmap = SZ_4K | SZ_2M, 2271 + .ias = va_bits, 2272 + .oas = pa_bits, 2273 + .coherent_walk = ptdev->coherent, 2274 + .tlb = &mmu_tlb_ops, 2275 + .iommu_dev = ptdev->base.dev, 2276 + .alloc = alloc_pt, 2277 + .free = free_pt, 2278 + }; 2279 + 2280 + vm->pgtbl_ops = alloc_io_pgtable_ops(ARM_64_LPAE_S1, &pgtbl_cfg, vm); 2281 + if (!vm->pgtbl_ops) { 2282 + ret = -EINVAL; 2283 + goto err_mm_takedown; 2284 + } 2285 + 2286 + /* Bind operations are synchronous for now, no timeout needed. */ 2287 + ret = drm_sched_init(&vm->sched, &panthor_vm_bind_ops, ptdev->mmu->vm.wq, 2288 + 1, 1, 0, 2289 + MAX_SCHEDULE_TIMEOUT, NULL, NULL, 2290 + "panthor-vm-bind", ptdev->base.dev); 2291 + if (ret) 2292 + goto err_free_io_pgtable; 2293 + 2294 + sched = &vm->sched; 2295 + ret = drm_sched_entity_init(&vm->entity, 0, &sched, 1, NULL); 2296 + if (ret) 2297 + goto err_sched_fini; 2298 + 2299 + mair = io_pgtable_ops_to_pgtable(vm->pgtbl_ops)->cfg.arm_lpae_s1_cfg.mair; 2300 + vm->memattr = mair_to_memattr(mair); 2301 + 2302 + mutex_lock(&ptdev->mmu->vm.lock); 2303 + list_add_tail(&vm->node, &ptdev->mmu->vm.list); 2304 + 2305 + /* If a reset is in progress, stop the scheduler. */ 2306 + if (ptdev->mmu->vm.reset_in_progress) 2307 + panthor_vm_stop(vm); 2308 + mutex_unlock(&ptdev->mmu->vm.lock); 2309 + 2310 + /* We intentionally leave the reserved range to zero, because we want kernel VMAs 2311 + * to be handled the same way user VMAs are. 2312 + */ 2313 + drm_gpuvm_init(&vm->base, for_mcu ? "panthor-MCU-VM" : "panthor-GPU-VM", 2314 + DRM_GPUVM_RESV_PROTECTED, &ptdev->base, dummy_gem, 2315 + min_va, va_range, 0, 0, &panthor_gpuvm_ops); 2316 + drm_gem_object_put(dummy_gem); 2317 + return vm; 2318 + 2319 + err_sched_fini: 2320 + drm_sched_fini(&vm->sched); 2321 + 2322 + err_free_io_pgtable: 2323 + free_io_pgtable_ops(vm->pgtbl_ops); 2324 + 2325 + err_mm_takedown: 2326 + drm_mm_takedown(&vm->mm); 2327 + drm_gem_object_put(dummy_gem); 2328 + 2329 + err_free_vm: 2330 + kfree(vm); 2331 + return ERR_PTR(ret); 2332 + } 2333 + 2334 + static int 2335 + panthor_vm_bind_prepare_op_ctx(struct drm_file *file, 2336 + struct panthor_vm *vm, 2337 + const struct drm_panthor_vm_bind_op *op, 2338 + struct panthor_vm_op_ctx *op_ctx) 2339 + { 2340 + struct drm_gem_object *gem; 2341 + int ret; 2342 + 2343 + /* Aligned on page size. */ 2344 + if ((op->va | op->size) & ~PAGE_MASK) 2345 + return -EINVAL; 2346 + 2347 + switch (op->flags & DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) { 2348 + case DRM_PANTHOR_VM_BIND_OP_TYPE_MAP: 2349 + gem = drm_gem_object_lookup(file, op->bo_handle); 2350 + ret = panthor_vm_prepare_map_op_ctx(op_ctx, vm, 2351 + gem ? to_panthor_bo(gem) : NULL, 2352 + op->bo_offset, 2353 + op->size, 2354 + op->va, 2355 + op->flags); 2356 + drm_gem_object_put(gem); 2357 + return ret; 2358 + 2359 + case DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP: 2360 + if (op->flags & ~DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) 2361 + return -EINVAL; 2362 + 2363 + if (op->bo_handle || op->bo_offset) 2364 + return -EINVAL; 2365 + 2366 + return panthor_vm_prepare_unmap_op_ctx(op_ctx, vm, op->va, op->size); 2367 + 2368 + case DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY: 2369 + if (op->flags & ~DRM_PANTHOR_VM_BIND_OP_TYPE_MASK) 2370 + return -EINVAL; 2371 + 2372 + if (op->bo_handle || op->bo_offset) 2373 + return -EINVAL; 2374 + 2375 + if (op->va || op->size) 2376 + return -EINVAL; 2377 + 2378 + if (!op->syncs.count) 2379 + return -EINVAL; 2380 + 2381 + panthor_vm_prepare_sync_only_op_ctx(op_ctx, vm); 2382 + return 0; 2383 + 2384 + default: 2385 + return -EINVAL; 2386 + } 2387 + } 2388 + 2389 + static void panthor_vm_bind_job_cleanup_op_ctx_work(struct work_struct *work) 2390 + { 2391 + struct panthor_vm_bind_job *job = 2392 + container_of(work, struct panthor_vm_bind_job, cleanup_op_ctx_work); 2393 + 2394 + panthor_vm_bind_job_put(&job->base); 2395 + } 2396 + 2397 + /** 2398 + * panthor_vm_bind_job_create() - Create a VM_BIND job 2399 + * @file: File. 2400 + * @vm: VM targeted by the VM_BIND job. 2401 + * @op: VM operation data. 2402 + * 2403 + * Return: A valid pointer on success, an ERR_PTR() otherwise. 2404 + */ 2405 + struct drm_sched_job * 2406 + panthor_vm_bind_job_create(struct drm_file *file, 2407 + struct panthor_vm *vm, 2408 + const struct drm_panthor_vm_bind_op *op) 2409 + { 2410 + struct panthor_vm_bind_job *job; 2411 + int ret; 2412 + 2413 + if (!vm) 2414 + return ERR_PTR(-EINVAL); 2415 + 2416 + if (vm->destroyed || vm->unusable) 2417 + return ERR_PTR(-EINVAL); 2418 + 2419 + job = kzalloc(sizeof(*job), GFP_KERNEL); 2420 + if (!job) 2421 + return ERR_PTR(-ENOMEM); 2422 + 2423 + ret = panthor_vm_bind_prepare_op_ctx(file, vm, op, &job->ctx); 2424 + if (ret) { 2425 + kfree(job); 2426 + return ERR_PTR(ret); 2427 + } 2428 + 2429 + INIT_WORK(&job->cleanup_op_ctx_work, panthor_vm_bind_job_cleanup_op_ctx_work); 2430 + kref_init(&job->refcount); 2431 + job->vm = panthor_vm_get(vm); 2432 + 2433 + ret = drm_sched_job_init(&job->base, &vm->entity, 1, vm); 2434 + if (ret) 2435 + goto err_put_job; 2436 + 2437 + return &job->base; 2438 + 2439 + err_put_job: 2440 + panthor_vm_bind_job_put(&job->base); 2441 + return ERR_PTR(ret); 2442 + } 2443 + 2444 + /** 2445 + * panthor_vm_bind_job_prepare_resvs() - Prepare VM_BIND job dma_resvs 2446 + * @exec: The locking/preparation context. 2447 + * @sched_job: The job to prepare resvs on. 2448 + * 2449 + * Locks and prepare the VM resv. 2450 + * 2451 + * If this is a map operation, locks and prepares the GEM resv. 2452 + * 2453 + * Return: 0 on success, a negative error code otherwise. 2454 + */ 2455 + int panthor_vm_bind_job_prepare_resvs(struct drm_exec *exec, 2456 + struct drm_sched_job *sched_job) 2457 + { 2458 + struct panthor_vm_bind_job *job = container_of(sched_job, struct panthor_vm_bind_job, base); 2459 + int ret; 2460 + 2461 + /* Acquire the VM lock an reserve a slot for this VM bind job. */ 2462 + ret = drm_gpuvm_prepare_vm(&job->vm->base, exec, 1); 2463 + if (ret) 2464 + return ret; 2465 + 2466 + if (job->ctx.map.vm_bo) { 2467 + /* Lock/prepare the GEM being mapped. */ 2468 + ret = drm_exec_prepare_obj(exec, job->ctx.map.vm_bo->obj, 1); 2469 + if (ret) 2470 + return ret; 2471 + } 2472 + 2473 + return 0; 2474 + } 2475 + 2476 + /** 2477 + * panthor_vm_bind_job_update_resvs() - Update the resv objects touched by a job 2478 + * @exec: drm_exec context. 2479 + * @sched_job: Job to update the resvs on. 2480 + */ 2481 + void panthor_vm_bind_job_update_resvs(struct drm_exec *exec, 2482 + struct drm_sched_job *sched_job) 2483 + { 2484 + struct panthor_vm_bind_job *job = container_of(sched_job, struct panthor_vm_bind_job, base); 2485 + 2486 + /* Explicit sync => we just register our job finished fence as bookkeep. */ 2487 + drm_gpuvm_resv_add_fence(&job->vm->base, exec, 2488 + &sched_job->s_fence->finished, 2489 + DMA_RESV_USAGE_BOOKKEEP, 2490 + DMA_RESV_USAGE_BOOKKEEP); 2491 + } 2492 + 2493 + void panthor_vm_update_resvs(struct panthor_vm *vm, struct drm_exec *exec, 2494 + struct dma_fence *fence, 2495 + enum dma_resv_usage private_usage, 2496 + enum dma_resv_usage extobj_usage) 2497 + { 2498 + drm_gpuvm_resv_add_fence(&vm->base, exec, fence, private_usage, extobj_usage); 2499 + } 2500 + 2501 + /** 2502 + * panthor_vm_bind_exec_sync_op() - Execute a VM_BIND operation synchronously. 2503 + * @file: File. 2504 + * @vm: VM targeted by the VM operation. 2505 + * @op: Data describing the VM operation. 2506 + * 2507 + * Return: 0 on success, a negative error code otherwise. 2508 + */ 2509 + int panthor_vm_bind_exec_sync_op(struct drm_file *file, 2510 + struct panthor_vm *vm, 2511 + struct drm_panthor_vm_bind_op *op) 2512 + { 2513 + struct panthor_vm_op_ctx op_ctx; 2514 + int ret; 2515 + 2516 + /* No sync objects allowed on synchronous operations. */ 2517 + if (op->syncs.count) 2518 + return -EINVAL; 2519 + 2520 + if (!op->size) 2521 + return 0; 2522 + 2523 + ret = panthor_vm_bind_prepare_op_ctx(file, vm, op, &op_ctx); 2524 + if (ret) 2525 + return ret; 2526 + 2527 + ret = panthor_vm_exec_op(vm, &op_ctx, false); 2528 + panthor_vm_cleanup_op_ctx(&op_ctx, vm); 2529 + 2530 + return ret; 2531 + } 2532 + 2533 + /** 2534 + * panthor_vm_map_bo_range() - Map a GEM object range to a VM 2535 + * @vm: VM to map the GEM to. 2536 + * @bo: GEM object to map. 2537 + * @offset: Offset in the GEM object. 2538 + * @size: Size to map. 2539 + * @va: Virtual address to map the object to. 2540 + * @flags: Combination of drm_panthor_vm_bind_op_flags flags. 2541 + * Only map-related flags are valid. 2542 + * 2543 + * Internal use only. For userspace requests, use 2544 + * panthor_vm_bind_exec_sync_op() instead. 2545 + * 2546 + * Return: 0 on success, a negative error code otherwise. 2547 + */ 2548 + int panthor_vm_map_bo_range(struct panthor_vm *vm, struct panthor_gem_object *bo, 2549 + u64 offset, u64 size, u64 va, u32 flags) 2550 + { 2551 + struct panthor_vm_op_ctx op_ctx; 2552 + int ret; 2553 + 2554 + ret = panthor_vm_prepare_map_op_ctx(&op_ctx, vm, bo, offset, size, va, flags); 2555 + if (ret) 2556 + return ret; 2557 + 2558 + ret = panthor_vm_exec_op(vm, &op_ctx, false); 2559 + panthor_vm_cleanup_op_ctx(&op_ctx, vm); 2560 + 2561 + return ret; 2562 + } 2563 + 2564 + /** 2565 + * panthor_vm_unmap_range() - Unmap a portion of the VA space 2566 + * @vm: VM to unmap the region from. 2567 + * @va: Virtual address to unmap. Must be 4k aligned. 2568 + * @size: Size of the region to unmap. Must be 4k aligned. 2569 + * 2570 + * Internal use only. For userspace requests, use 2571 + * panthor_vm_bind_exec_sync_op() instead. 2572 + * 2573 + * Return: 0 on success, a negative error code otherwise. 2574 + */ 2575 + int panthor_vm_unmap_range(struct panthor_vm *vm, u64 va, u64 size) 2576 + { 2577 + struct panthor_vm_op_ctx op_ctx; 2578 + int ret; 2579 + 2580 + ret = panthor_vm_prepare_unmap_op_ctx(&op_ctx, vm, va, size); 2581 + if (ret) 2582 + return ret; 2583 + 2584 + ret = panthor_vm_exec_op(vm, &op_ctx, false); 2585 + panthor_vm_cleanup_op_ctx(&op_ctx, vm); 2586 + 2587 + return ret; 2588 + } 2589 + 2590 + /** 2591 + * panthor_vm_prepare_mapped_bos_resvs() - Prepare resvs on VM BOs. 2592 + * @exec: Locking/preparation context. 2593 + * @vm: VM targeted by the GPU job. 2594 + * @slot_count: Number of slots to reserve. 2595 + * 2596 + * GPU jobs assume all BOs bound to the VM at the time the job is submitted 2597 + * are available when the job is executed. In order to guarantee that, we 2598 + * need to reserve a slot on all BOs mapped to a VM and update this slot with 2599 + * the job fence after its submission. 2600 + * 2601 + * Return: 0 on success, a negative error code otherwise. 2602 + */ 2603 + int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec, struct panthor_vm *vm, 2604 + u32 slot_count) 2605 + { 2606 + int ret; 2607 + 2608 + /* Acquire the VM lock and reserve a slot for this GPU job. */ 2609 + ret = drm_gpuvm_prepare_vm(&vm->base, exec, slot_count); 2610 + if (ret) 2611 + return ret; 2612 + 2613 + return drm_gpuvm_prepare_objects(&vm->base, exec, slot_count); 2614 + } 2615 + 2616 + /** 2617 + * panthor_mmu_unplug() - Unplug the MMU logic 2618 + * @ptdev: Device. 2619 + * 2620 + * No access to the MMU regs should be done after this function is called. 2621 + * We suspend the IRQ and disable all VMs to guarantee that. 2622 + */ 2623 + void panthor_mmu_unplug(struct panthor_device *ptdev) 2624 + { 2625 + panthor_mmu_irq_suspend(&ptdev->mmu->irq); 2626 + 2627 + mutex_lock(&ptdev->mmu->as.slots_lock); 2628 + for (u32 i = 0; i < ARRAY_SIZE(ptdev->mmu->as.slots); i++) { 2629 + struct panthor_vm *vm = ptdev->mmu->as.slots[i].vm; 2630 + 2631 + if (vm) { 2632 + drm_WARN_ON(&ptdev->base, panthor_mmu_as_disable(ptdev, i)); 2633 + panthor_vm_release_as_locked(vm); 2634 + } 2635 + } 2636 + mutex_unlock(&ptdev->mmu->as.slots_lock); 2637 + } 2638 + 2639 + static void panthor_mmu_release_wq(struct drm_device *ddev, void *res) 2640 + { 2641 + destroy_workqueue(res); 2642 + } 2643 + 2644 + /** 2645 + * panthor_mmu_init() - Initialize the MMU logic. 2646 + * @ptdev: Device. 2647 + * 2648 + * Return: 0 on success, a negative error code otherwise. 2649 + */ 2650 + int panthor_mmu_init(struct panthor_device *ptdev) 2651 + { 2652 + u32 va_bits = GPU_MMU_FEATURES_VA_BITS(ptdev->gpu_info.mmu_features); 2653 + struct panthor_mmu *mmu; 2654 + int ret, irq; 2655 + 2656 + mmu = drmm_kzalloc(&ptdev->base, sizeof(*mmu), GFP_KERNEL); 2657 + if (!mmu) 2658 + return -ENOMEM; 2659 + 2660 + INIT_LIST_HEAD(&mmu->as.lru_list); 2661 + 2662 + ret = drmm_mutex_init(&ptdev->base, &mmu->as.slots_lock); 2663 + if (ret) 2664 + return ret; 2665 + 2666 + INIT_LIST_HEAD(&mmu->vm.list); 2667 + ret = drmm_mutex_init(&ptdev->base, &mmu->vm.lock); 2668 + if (ret) 2669 + return ret; 2670 + 2671 + ptdev->mmu = mmu; 2672 + 2673 + irq = platform_get_irq_byname(to_platform_device(ptdev->base.dev), "mmu"); 2674 + if (irq <= 0) 2675 + return -ENODEV; 2676 + 2677 + ret = panthor_request_mmu_irq(ptdev, &mmu->irq, irq, 2678 + panthor_mmu_fault_mask(ptdev, ~0)); 2679 + if (ret) 2680 + return ret; 2681 + 2682 + mmu->vm.wq = alloc_workqueue("panthor-vm-bind", WQ_UNBOUND, 0); 2683 + if (!mmu->vm.wq) 2684 + return -ENOMEM; 2685 + 2686 + /* On 32-bit kernels, the VA space is limited by the io_pgtable_ops abstraction, 2687 + * which passes iova as an unsigned long. Patch the mmu_features to reflect this 2688 + * limitation. 2689 + */ 2690 + if (sizeof(unsigned long) * 8 < va_bits) { 2691 + ptdev->gpu_info.mmu_features &= ~GENMASK(7, 0); 2692 + ptdev->gpu_info.mmu_features |= sizeof(unsigned long) * 8; 2693 + } 2694 + 2695 + return drmm_add_action_or_reset(&ptdev->base, panthor_mmu_release_wq, mmu->vm.wq); 2696 + } 2697 + 2698 + #ifdef CONFIG_DEBUG_FS 2699 + static int show_vm_gpuvas(struct panthor_vm *vm, struct seq_file *m) 2700 + { 2701 + int ret; 2702 + 2703 + mutex_lock(&vm->op_lock); 2704 + ret = drm_debugfs_gpuva_info(m, &vm->base); 2705 + mutex_unlock(&vm->op_lock); 2706 + 2707 + return ret; 2708 + } 2709 + 2710 + static int show_each_vm(struct seq_file *m, void *arg) 2711 + { 2712 + struct drm_info_node *node = (struct drm_info_node *)m->private; 2713 + struct drm_device *ddev = node->minor->dev; 2714 + struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base); 2715 + int (*show)(struct panthor_vm *, struct seq_file *) = node->info_ent->data; 2716 + struct panthor_vm *vm; 2717 + int ret = 0; 2718 + 2719 + mutex_lock(&ptdev->mmu->vm.lock); 2720 + list_for_each_entry(vm, &ptdev->mmu->vm.list, node) { 2721 + ret = show(vm, m); 2722 + if (ret < 0) 2723 + break; 2724 + 2725 + seq_puts(m, "\n"); 2726 + } 2727 + mutex_unlock(&ptdev->mmu->vm.lock); 2728 + 2729 + return ret; 2730 + } 2731 + 2732 + static struct drm_info_list panthor_mmu_debugfs_list[] = { 2733 + DRM_DEBUGFS_GPUVA_INFO(show_each_vm, show_vm_gpuvas), 2734 + }; 2735 + 2736 + /** 2737 + * panthor_mmu_debugfs_init() - Initialize MMU debugfs entries 2738 + * @minor: Minor. 2739 + */ 2740 + void panthor_mmu_debugfs_init(struct drm_minor *minor) 2741 + { 2742 + drm_debugfs_create_files(panthor_mmu_debugfs_list, 2743 + ARRAY_SIZE(panthor_mmu_debugfs_list), 2744 + minor->debugfs_root, minor); 2745 + } 2746 + #endif /* CONFIG_DEBUG_FS */ 2747 + 2748 + /** 2749 + * panthor_mmu_pt_cache_init() - Initialize the page table cache. 2750 + * 2751 + * Return: 0 on success, a negative error code otherwise. 2752 + */ 2753 + int panthor_mmu_pt_cache_init(void) 2754 + { 2755 + pt_cache = kmem_cache_create("panthor-mmu-pt", SZ_4K, SZ_4K, 0, NULL); 2756 + if (!pt_cache) 2757 + return -ENOMEM; 2758 + 2759 + return 0; 2760 + } 2761 + 2762 + /** 2763 + * panthor_mmu_pt_cache_fini() - Destroy the page table cache. 2764 + */ 2765 + void panthor_mmu_pt_cache_fini(void) 2766 + { 2767 + kmem_cache_destroy(pt_cache); 2768 + }
+102
drivers/gpu/drm/panthor/panthor_mmu.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 3 + /* Copyright 2023 Collabora ltd. */ 4 + 5 + #ifndef __PANTHOR_MMU_H__ 6 + #define __PANTHOR_MMU_H__ 7 + 8 + #include <linux/dma-resv.h> 9 + 10 + struct drm_exec; 11 + struct drm_sched_job; 12 + struct panthor_gem_object; 13 + struct panthor_heap_pool; 14 + struct panthor_vm; 15 + struct panthor_vma; 16 + struct panthor_mmu; 17 + 18 + int panthor_mmu_init(struct panthor_device *ptdev); 19 + void panthor_mmu_unplug(struct panthor_device *ptdev); 20 + void panthor_mmu_pre_reset(struct panthor_device *ptdev); 21 + void panthor_mmu_post_reset(struct panthor_device *ptdev); 22 + void panthor_mmu_suspend(struct panthor_device *ptdev); 23 + void panthor_mmu_resume(struct panthor_device *ptdev); 24 + 25 + int panthor_vm_map_bo_range(struct panthor_vm *vm, struct panthor_gem_object *bo, 26 + u64 offset, u64 size, u64 va, u32 flags); 27 + int panthor_vm_unmap_range(struct panthor_vm *vm, u64 va, u64 size); 28 + struct panthor_gem_object * 29 + panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 va, u64 *bo_offset); 30 + 31 + int panthor_vm_active(struct panthor_vm *vm); 32 + void panthor_vm_idle(struct panthor_vm *vm); 33 + int panthor_vm_as(struct panthor_vm *vm); 34 + 35 + struct panthor_heap_pool * 36 + panthor_vm_get_heap_pool(struct panthor_vm *vm, bool create); 37 + 38 + struct panthor_vm *panthor_vm_get(struct panthor_vm *vm); 39 + void panthor_vm_put(struct panthor_vm *vm); 40 + struct panthor_vm *panthor_vm_create(struct panthor_device *ptdev, bool for_mcu, 41 + u64 kernel_va_start, u64 kernel_va_size, 42 + u64 kernel_auto_va_start, 43 + u64 kernel_auto_va_size); 44 + 45 + int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec, 46 + struct panthor_vm *vm, 47 + u32 slot_count); 48 + int panthor_vm_add_bos_resvs_deps_to_job(struct panthor_vm *vm, 49 + struct drm_sched_job *job); 50 + void panthor_vm_add_job_fence_to_bos_resvs(struct panthor_vm *vm, 51 + struct drm_sched_job *job); 52 + 53 + struct dma_resv *panthor_vm_resv(struct panthor_vm *vm); 54 + struct drm_gem_object *panthor_vm_root_gem(struct panthor_vm *vm); 55 + 56 + void panthor_vm_pool_destroy(struct panthor_file *pfile); 57 + int panthor_vm_pool_create(struct panthor_file *pfile); 58 + int panthor_vm_pool_create_vm(struct panthor_device *ptdev, 59 + struct panthor_vm_pool *pool, 60 + struct drm_panthor_vm_create *args); 61 + int panthor_vm_pool_destroy_vm(struct panthor_vm_pool *pool, u32 handle); 62 + struct panthor_vm *panthor_vm_pool_get_vm(struct panthor_vm_pool *pool, u32 handle); 63 + 64 + bool panthor_vm_has_unhandled_faults(struct panthor_vm *vm); 65 + bool panthor_vm_is_unusable(struct panthor_vm *vm); 66 + 67 + /* 68 + * PANTHOR_VM_KERNEL_AUTO_VA: Use this magic address when you want the GEM 69 + * logic to auto-allocate the virtual address in the reserved kernel VA range. 70 + */ 71 + #define PANTHOR_VM_KERNEL_AUTO_VA ~0ull 72 + 73 + int panthor_vm_alloc_va(struct panthor_vm *vm, u64 va, u64 size, 74 + struct drm_mm_node *va_node); 75 + void panthor_vm_free_va(struct panthor_vm *vm, struct drm_mm_node *va_node); 76 + 77 + int panthor_vm_bind_exec_sync_op(struct drm_file *file, 78 + struct panthor_vm *vm, 79 + struct drm_panthor_vm_bind_op *op); 80 + 81 + struct drm_sched_job * 82 + panthor_vm_bind_job_create(struct drm_file *file, 83 + struct panthor_vm *vm, 84 + const struct drm_panthor_vm_bind_op *op); 85 + void panthor_vm_bind_job_put(struct drm_sched_job *job); 86 + int panthor_vm_bind_job_prepare_resvs(struct drm_exec *exec, 87 + struct drm_sched_job *job); 88 + void panthor_vm_bind_job_update_resvs(struct drm_exec *exec, struct drm_sched_job *job); 89 + 90 + void panthor_vm_update_resvs(struct panthor_vm *vm, struct drm_exec *exec, 91 + struct dma_fence *fence, 92 + enum dma_resv_usage private_usage, 93 + enum dma_resv_usage extobj_usage); 94 + 95 + int panthor_mmu_pt_cache_init(void); 96 + void panthor_mmu_pt_cache_fini(void); 97 + 98 + #ifdef CONFIG_DEBUG_FS 99 + void panthor_mmu_debugfs_init(struct drm_minor *minor); 100 + #endif 101 + 102 + #endif
+239
drivers/gpu/drm/panthor/panthor_regs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */ 3 + /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */ 4 + /* Copyright 2023 Collabora ltd. */ 5 + /* 6 + * Register definitions based on mali_kbase_gpu_regmap.h and 7 + * mali_kbase_gpu_regmap_csf.h 8 + * (C) COPYRIGHT 2010-2022 ARM Limited. All rights reserved. 9 + */ 10 + #ifndef __PANTHOR_REGS_H__ 11 + #define __PANTHOR_REGS_H__ 12 + 13 + #define GPU_ID 0x0 14 + #define GPU_ARCH_MAJOR(x) ((x) >> 28) 15 + #define GPU_ARCH_MINOR(x) (((x) & GENMASK(27, 24)) >> 24) 16 + #define GPU_ARCH_REV(x) (((x) & GENMASK(23, 20)) >> 20) 17 + #define GPU_PROD_MAJOR(x) (((x) & GENMASK(19, 16)) >> 16) 18 + #define GPU_VER_MAJOR(x) (((x) & GENMASK(15, 12)) >> 12) 19 + #define GPU_VER_MINOR(x) (((x) & GENMASK(11, 4)) >> 4) 20 + #define GPU_VER_STATUS(x) ((x) & GENMASK(3, 0)) 21 + 22 + #define GPU_L2_FEATURES 0x4 23 + #define GPU_L2_FEATURES_LINE_SIZE(x) (1 << ((x) & GENMASK(7, 0))) 24 + 25 + #define GPU_CORE_FEATURES 0x8 26 + 27 + #define GPU_TILER_FEATURES 0xC 28 + #define GPU_MEM_FEATURES 0x10 29 + #define GROUPS_L2_COHERENT BIT(0) 30 + 31 + #define GPU_MMU_FEATURES 0x14 32 + #define GPU_MMU_FEATURES_VA_BITS(x) ((x) & GENMASK(7, 0)) 33 + #define GPU_MMU_FEATURES_PA_BITS(x) (((x) >> 8) & GENMASK(7, 0)) 34 + #define GPU_AS_PRESENT 0x18 35 + #define GPU_CSF_ID 0x1C 36 + 37 + #define GPU_INT_RAWSTAT 0x20 38 + #define GPU_INT_CLEAR 0x24 39 + #define GPU_INT_MASK 0x28 40 + #define GPU_INT_STAT 0x2c 41 + #define GPU_IRQ_FAULT BIT(0) 42 + #define GPU_IRQ_PROTM_FAULT BIT(1) 43 + #define GPU_IRQ_RESET_COMPLETED BIT(8) 44 + #define GPU_IRQ_POWER_CHANGED BIT(9) 45 + #define GPU_IRQ_POWER_CHANGED_ALL BIT(10) 46 + #define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17) 47 + #define GPU_IRQ_DOORBELL_MIRROR BIT(18) 48 + #define GPU_IRQ_MCU_STATUS_CHANGED BIT(19) 49 + #define GPU_CMD 0x30 50 + #define GPU_CMD_DEF(type, payload) ((type) | ((payload) << 8)) 51 + #define GPU_SOFT_RESET GPU_CMD_DEF(1, 1) 52 + #define GPU_HARD_RESET GPU_CMD_DEF(1, 2) 53 + #define CACHE_CLEAN BIT(0) 54 + #define CACHE_INV BIT(1) 55 + #define GPU_FLUSH_CACHES(l2, lsc, oth) \ 56 + GPU_CMD_DEF(4, ((l2) << 0) | ((lsc) << 4) | ((oth) << 8)) 57 + 58 + #define GPU_STATUS 0x34 59 + #define GPU_STATUS_ACTIVE BIT(0) 60 + #define GPU_STATUS_PWR_ACTIVE BIT(1) 61 + #define GPU_STATUS_PAGE_FAULT BIT(4) 62 + #define GPU_STATUS_PROTM_ACTIVE BIT(7) 63 + #define GPU_STATUS_DBG_ENABLED BIT(8) 64 + 65 + #define GPU_FAULT_STATUS 0x3C 66 + #define GPU_FAULT_ADDR_LO 0x40 67 + #define GPU_FAULT_ADDR_HI 0x44 68 + 69 + #define GPU_PWR_KEY 0x50 70 + #define GPU_PWR_KEY_UNLOCK 0x2968A819 71 + #define GPU_PWR_OVERRIDE0 0x54 72 + #define GPU_PWR_OVERRIDE1 0x58 73 + 74 + #define GPU_TIMESTAMP_OFFSET_LO 0x88 75 + #define GPU_TIMESTAMP_OFFSET_HI 0x8C 76 + #define GPU_CYCLE_COUNT_LO 0x90 77 + #define GPU_CYCLE_COUNT_HI 0x94 78 + #define GPU_TIMESTAMP_LO 0x98 79 + #define GPU_TIMESTAMP_HI 0x9C 80 + 81 + #define GPU_THREAD_MAX_THREADS 0xA0 82 + #define GPU_THREAD_MAX_WORKGROUP_SIZE 0xA4 83 + #define GPU_THREAD_MAX_BARRIER_SIZE 0xA8 84 + #define GPU_THREAD_FEATURES 0xAC 85 + 86 + #define GPU_TEXTURE_FEATURES(n) (0xB0 + ((n) * 4)) 87 + 88 + #define GPU_SHADER_PRESENT_LO 0x100 89 + #define GPU_SHADER_PRESENT_HI 0x104 90 + #define GPU_TILER_PRESENT_LO 0x110 91 + #define GPU_TILER_PRESENT_HI 0x114 92 + #define GPU_L2_PRESENT_LO 0x120 93 + #define GPU_L2_PRESENT_HI 0x124 94 + 95 + #define SHADER_READY_LO 0x140 96 + #define SHADER_READY_HI 0x144 97 + #define TILER_READY_LO 0x150 98 + #define TILER_READY_HI 0x154 99 + #define L2_READY_LO 0x160 100 + #define L2_READY_HI 0x164 101 + 102 + #define SHADER_PWRON_LO 0x180 103 + #define SHADER_PWRON_HI 0x184 104 + #define TILER_PWRON_LO 0x190 105 + #define TILER_PWRON_HI 0x194 106 + #define L2_PWRON_LO 0x1A0 107 + #define L2_PWRON_HI 0x1A4 108 + 109 + #define SHADER_PWROFF_LO 0x1C0 110 + #define SHADER_PWROFF_HI 0x1C4 111 + #define TILER_PWROFF_LO 0x1D0 112 + #define TILER_PWROFF_HI 0x1D4 113 + #define L2_PWROFF_LO 0x1E0 114 + #define L2_PWROFF_HI 0x1E4 115 + 116 + #define SHADER_PWRTRANS_LO 0x200 117 + #define SHADER_PWRTRANS_HI 0x204 118 + #define TILER_PWRTRANS_LO 0x210 119 + #define TILER_PWRTRANS_HI 0x214 120 + #define L2_PWRTRANS_LO 0x220 121 + #define L2_PWRTRANS_HI 0x224 122 + 123 + #define SHADER_PWRACTIVE_LO 0x240 124 + #define SHADER_PWRACTIVE_HI 0x244 125 + #define TILER_PWRACTIVE_LO 0x250 126 + #define TILER_PWRACTIVE_HI 0x254 127 + #define L2_PWRACTIVE_LO 0x260 128 + #define L2_PWRACTIVE_HI 0x264 129 + 130 + #define GPU_REVID 0x280 131 + 132 + #define GPU_COHERENCY_FEATURES 0x300 133 + #define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name) 134 + 135 + #define GPU_COHERENCY_PROTOCOL 0x304 136 + #define GPU_COHERENCY_ACE 0 137 + #define GPU_COHERENCY_ACE_LITE 1 138 + #define GPU_COHERENCY_NONE 31 139 + 140 + #define MCU_CONTROL 0x700 141 + #define MCU_CONTROL_ENABLE 1 142 + #define MCU_CONTROL_AUTO 2 143 + #define MCU_CONTROL_DISABLE 0 144 + 145 + #define MCU_STATUS 0x704 146 + #define MCU_STATUS_DISABLED 0 147 + #define MCU_STATUS_ENABLED 1 148 + #define MCU_STATUS_HALT 2 149 + #define MCU_STATUS_FATAL 3 150 + 151 + /* Job Control regs */ 152 + #define JOB_INT_RAWSTAT 0x1000 153 + #define JOB_INT_CLEAR 0x1004 154 + #define JOB_INT_MASK 0x1008 155 + #define JOB_INT_STAT 0x100c 156 + #define JOB_INT_GLOBAL_IF BIT(31) 157 + #define JOB_INT_CSG_IF(x) BIT(x) 158 + 159 + /* MMU regs */ 160 + #define MMU_INT_RAWSTAT 0x2000 161 + #define MMU_INT_CLEAR 0x2004 162 + #define MMU_INT_MASK 0x2008 163 + #define MMU_INT_STAT 0x200c 164 + 165 + /* AS_COMMAND register commands */ 166 + 167 + #define MMU_BASE 0x2400 168 + #define MMU_AS_SHIFT 6 169 + #define MMU_AS(as) (MMU_BASE + ((as) << MMU_AS_SHIFT)) 170 + 171 + #define AS_TRANSTAB_LO(as) (MMU_AS(as) + 0x0) 172 + #define AS_TRANSTAB_HI(as) (MMU_AS(as) + 0x4) 173 + #define AS_MEMATTR_LO(as) (MMU_AS(as) + 0x8) 174 + #define AS_MEMATTR_HI(as) (MMU_AS(as) + 0xC) 175 + #define AS_MEMATTR_AARCH64_INNER_ALLOC_IMPL (2 << 2) 176 + #define AS_MEMATTR_AARCH64_INNER_ALLOC_EXPL(w, r) ((3 << 2) | \ 177 + ((w) ? BIT(0) : 0) | \ 178 + ((r) ? BIT(1) : 0)) 179 + #define AS_MEMATTR_AARCH64_SH_MIDGARD_INNER (0 << 4) 180 + #define AS_MEMATTR_AARCH64_SH_CPU_INNER (1 << 4) 181 + #define AS_MEMATTR_AARCH64_SH_CPU_INNER_SHADER_COH (2 << 4) 182 + #define AS_MEMATTR_AARCH64_SHARED (0 << 6) 183 + #define AS_MEMATTR_AARCH64_INNER_OUTER_NC (1 << 6) 184 + #define AS_MEMATTR_AARCH64_INNER_OUTER_WB (2 << 6) 185 + #define AS_MEMATTR_AARCH64_FAULT (3 << 6) 186 + #define AS_LOCKADDR_LO(as) (MMU_AS(as) + 0x10) 187 + #define AS_LOCKADDR_HI(as) (MMU_AS(as) + 0x14) 188 + #define AS_COMMAND(as) (MMU_AS(as) + 0x18) 189 + #define AS_COMMAND_NOP 0 190 + #define AS_COMMAND_UPDATE 1 191 + #define AS_COMMAND_LOCK 2 192 + #define AS_COMMAND_UNLOCK 3 193 + #define AS_COMMAND_FLUSH_PT 4 194 + #define AS_COMMAND_FLUSH_MEM 5 195 + #define AS_LOCK_REGION_MIN_SIZE (1ULL << 15) 196 + #define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C) 197 + #define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8) 198 + #define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8) 199 + #define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8) 200 + #define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8) 201 + #define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) 202 + #define AS_FAULTADDRESS_LO(as) (MMU_AS(as) + 0x20) 203 + #define AS_FAULTADDRESS_HI(as) (MMU_AS(as) + 0x24) 204 + #define AS_STATUS(as) (MMU_AS(as) + 0x28) 205 + #define AS_STATUS_AS_ACTIVE BIT(0) 206 + #define AS_TRANSCFG_LO(as) (MMU_AS(as) + 0x30) 207 + #define AS_TRANSCFG_HI(as) (MMU_AS(as) + 0x34) 208 + #define AS_TRANSCFG_ADRMODE_UNMAPPED (1 << 0) 209 + #define AS_TRANSCFG_ADRMODE_IDENTITY (2 << 0) 210 + #define AS_TRANSCFG_ADRMODE_AARCH64_4K (6 << 0) 211 + #define AS_TRANSCFG_ADRMODE_AARCH64_64K (8 << 0) 212 + #define AS_TRANSCFG_INA_BITS(x) ((x) << 6) 213 + #define AS_TRANSCFG_OUTA_BITS(x) ((x) << 14) 214 + #define AS_TRANSCFG_SL_CONCAT BIT(22) 215 + #define AS_TRANSCFG_PTW_MEMATTR_NC (1 << 24) 216 + #define AS_TRANSCFG_PTW_MEMATTR_WB (2 << 24) 217 + #define AS_TRANSCFG_PTW_SH_NS (0 << 28) 218 + #define AS_TRANSCFG_PTW_SH_OS (2 << 28) 219 + #define AS_TRANSCFG_PTW_SH_IS (3 << 28) 220 + #define AS_TRANSCFG_PTW_RA BIT(30) 221 + #define AS_TRANSCFG_DISABLE_HIER_AP BIT(33) 222 + #define AS_TRANSCFG_DISABLE_AF_FAULT BIT(34) 223 + #define AS_TRANSCFG_WXN BIT(35) 224 + #define AS_TRANSCFG_XREADABLE BIT(36) 225 + #define AS_FAULTEXTRA_LO(as) (MMU_AS(as) + 0x38) 226 + #define AS_FAULTEXTRA_HI(as) (MMU_AS(as) + 0x3C) 227 + 228 + #define CSF_GPU_LATEST_FLUSH_ID 0x10000 229 + 230 + #define CSF_DOORBELL(i) (0x80000 + ((i) * 0x10000)) 231 + #define CSF_GLB_DOORBELL_ID 0 232 + 233 + #define gpu_write(dev, reg, data) \ 234 + writel(data, (dev)->iomem + (reg)) 235 + 236 + #define gpu_read(dev, reg) \ 237 + readl((dev)->iomem + (reg)) 238 + 239 + #endif
+3502
drivers/gpu/drm/panthor/panthor_sched.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* Copyright 2023 Collabora ltd. */ 3 + 4 + #include <drm/drm_drv.h> 5 + #include <drm/drm_exec.h> 6 + #include <drm/drm_gem_shmem_helper.h> 7 + #include <drm/drm_managed.h> 8 + #include <drm/gpu_scheduler.h> 9 + #include <drm/panthor_drm.h> 10 + 11 + #include <linux/build_bug.h> 12 + #include <linux/clk.h> 13 + #include <linux/delay.h> 14 + #include <linux/dma-mapping.h> 15 + #include <linux/dma-resv.h> 16 + #include <linux/firmware.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/io.h> 19 + #include <linux/iopoll.h> 20 + #include <linux/iosys-map.h> 21 + #include <linux/module.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/pm_runtime.h> 24 + 25 + #include "panthor_devfreq.h" 26 + #include "panthor_device.h" 27 + #include "panthor_fw.h" 28 + #include "panthor_gem.h" 29 + #include "panthor_gpu.h" 30 + #include "panthor_heap.h" 31 + #include "panthor_mmu.h" 32 + #include "panthor_regs.h" 33 + #include "panthor_sched.h" 34 + 35 + /** 36 + * DOC: Scheduler 37 + * 38 + * Mali CSF hardware adopts a firmware-assisted scheduling model, where 39 + * the firmware takes care of scheduling aspects, to some extent. 40 + * 41 + * The scheduling happens at the scheduling group level, each group 42 + * contains 1 to N queues (N is FW/hardware dependent, and exposed 43 + * through the firmware interface). Each queue is assigned a command 44 + * stream ring buffer, which serves as a way to get jobs submitted to 45 + * the GPU, among other things. 46 + * 47 + * The firmware can schedule a maximum of M groups (M is FW/hardware 48 + * dependent, and exposed through the firmware interface). Passed 49 + * this maximum number of groups, the kernel must take care of 50 + * rotating the groups passed to the firmware so every group gets 51 + * a chance to have his queues scheduled for execution. 52 + * 53 + * The current implementation only supports with kernel-mode queues. 54 + * In other terms, userspace doesn't have access to the ring-buffer. 55 + * Instead, userspace passes indirect command stream buffers that are 56 + * called from the queue ring-buffer by the kernel using a pre-defined 57 + * sequence of command stream instructions to ensure the userspace driver 58 + * always gets consistent results (cache maintenance, 59 + * synchronization, ...). 60 + * 61 + * We rely on the drm_gpu_scheduler framework to deal with job 62 + * dependencies and submission. As any other driver dealing with a 63 + * FW-scheduler, we use the 1:1 entity:scheduler mode, such that each 64 + * entity has its own job scheduler. When a job is ready to be executed 65 + * (all its dependencies are met), it is pushed to the appropriate 66 + * queue ring-buffer, and the group is scheduled for execution if it 67 + * wasn't already active. 68 + * 69 + * Kernel-side group scheduling is timeslice-based. When we have less 70 + * groups than there are slots, the periodic tick is disabled and we 71 + * just let the FW schedule the active groups. When there are more 72 + * groups than slots, we let each group a chance to execute stuff for 73 + * a given amount of time, and then re-evaluate and pick new groups 74 + * to schedule. The group selection algorithm is based on 75 + * priority+round-robin. 76 + * 77 + * Even though user-mode queues is out of the scope right now, the 78 + * current design takes them into account by avoiding any guess on the 79 + * group/queue state that would be based on information we wouldn't have 80 + * if userspace was in charge of the ring-buffer. That's also one of the 81 + * reason we don't do 'cooperative' scheduling (encoding FW group slot 82 + * reservation as dma_fence that would be returned from the 83 + * drm_gpu_scheduler::prepare_job() hook, and treating group rotation as 84 + * a queue of waiters, ordered by job submission order). This approach 85 + * would work for kernel-mode queues, but would make user-mode queues a 86 + * lot more complicated to retrofit. 87 + */ 88 + 89 + #define JOB_TIMEOUT_MS 5000 90 + 91 + #define MIN_CS_PER_CSG 8 92 + 93 + #define MIN_CSGS 3 94 + #define MAX_CSG_PRIO 0xf 95 + 96 + struct panthor_group; 97 + 98 + /** 99 + * struct panthor_csg_slot - Command stream group slot 100 + * 101 + * This represents a FW slot for a scheduling group. 102 + */ 103 + struct panthor_csg_slot { 104 + /** @group: Scheduling group bound to this slot. */ 105 + struct panthor_group *group; 106 + 107 + /** @priority: Group priority. */ 108 + u8 priority; 109 + 110 + /** 111 + * @idle: True if the group bound to this slot is idle. 112 + * 113 + * A group is idle when it has nothing waiting for execution on 114 + * all its queues, or when queues are blocked waiting for something 115 + * to happen (synchronization object). 116 + */ 117 + bool idle; 118 + }; 119 + 120 + /** 121 + * enum panthor_csg_priority - Group priority 122 + */ 123 + enum panthor_csg_priority { 124 + /** @PANTHOR_CSG_PRIORITY_LOW: Low priority group. */ 125 + PANTHOR_CSG_PRIORITY_LOW = 0, 126 + 127 + /** @PANTHOR_CSG_PRIORITY_MEDIUM: Medium priority group. */ 128 + PANTHOR_CSG_PRIORITY_MEDIUM, 129 + 130 + /** @PANTHOR_CSG_PRIORITY_HIGH: High priority group. */ 131 + PANTHOR_CSG_PRIORITY_HIGH, 132 + 133 + /** 134 + * @PANTHOR_CSG_PRIORITY_RT: Real-time priority group. 135 + * 136 + * Real-time priority allows one to preempt scheduling of other 137 + * non-real-time groups. When such a group becomes executable, 138 + * it will evict the group with the lowest non-rt priority if 139 + * there's no free group slot available. 140 + * 141 + * Currently not exposed to userspace. 142 + */ 143 + PANTHOR_CSG_PRIORITY_RT, 144 + 145 + /** @PANTHOR_CSG_PRIORITY_COUNT: Number of priority levels. */ 146 + PANTHOR_CSG_PRIORITY_COUNT, 147 + }; 148 + 149 + /** 150 + * struct panthor_scheduler - Object used to manage the scheduler 151 + */ 152 + struct panthor_scheduler { 153 + /** @ptdev: Device. */ 154 + struct panthor_device *ptdev; 155 + 156 + /** 157 + * @wq: Workqueue used by our internal scheduler logic and 158 + * drm_gpu_scheduler. 159 + * 160 + * Used for the scheduler tick, group update or other kind of FW 161 + * event processing that can't be handled in the threaded interrupt 162 + * path. Also passed to the drm_gpu_scheduler instances embedded 163 + * in panthor_queue. 164 + */ 165 + struct workqueue_struct *wq; 166 + 167 + /** 168 + * @heap_alloc_wq: Workqueue used to schedule tiler_oom works. 169 + * 170 + * We have a queue dedicated to heap chunk allocation works to avoid 171 + * blocking the rest of the scheduler if the allocation tries to 172 + * reclaim memory. 173 + */ 174 + struct workqueue_struct *heap_alloc_wq; 175 + 176 + /** @tick_work: Work executed on a scheduling tick. */ 177 + struct delayed_work tick_work; 178 + 179 + /** 180 + * @sync_upd_work: Work used to process synchronization object updates. 181 + * 182 + * We use this work to unblock queues/groups that were waiting on a 183 + * synchronization object. 184 + */ 185 + struct work_struct sync_upd_work; 186 + 187 + /** 188 + * @fw_events_work: Work used to process FW events outside the interrupt path. 189 + * 190 + * Even if the interrupt is threaded, we need any event processing 191 + * that require taking the panthor_scheduler::lock to be processed 192 + * outside the interrupt path so we don't block the tick logic when 193 + * it calls panthor_fw_{csg,wait}_wait_acks(). Since most of the 194 + * event processing requires taking this lock, we just delegate all 195 + * FW event processing to the scheduler workqueue. 196 + */ 197 + struct work_struct fw_events_work; 198 + 199 + /** 200 + * @fw_events: Bitmask encoding pending FW events. 201 + */ 202 + atomic_t fw_events; 203 + 204 + /** 205 + * @resched_target: When the next tick should occur. 206 + * 207 + * Expressed in jiffies. 208 + */ 209 + u64 resched_target; 210 + 211 + /** 212 + * @last_tick: When the last tick occurred. 213 + * 214 + * Expressed in jiffies. 215 + */ 216 + u64 last_tick; 217 + 218 + /** @tick_period: Tick period in jiffies. */ 219 + u64 tick_period; 220 + 221 + /** 222 + * @lock: Lock protecting access to all the scheduler fields. 223 + * 224 + * Should be taken in the tick work, the irq handler, and anywhere the @groups 225 + * fields are touched. 226 + */ 227 + struct mutex lock; 228 + 229 + /** @groups: Various lists used to classify groups. */ 230 + struct { 231 + /** 232 + * @runnable: Runnable group lists. 233 + * 234 + * When a group has queues that want to execute something, 235 + * its panthor_group::run_node should be inserted here. 236 + * 237 + * One list per-priority. 238 + */ 239 + struct list_head runnable[PANTHOR_CSG_PRIORITY_COUNT]; 240 + 241 + /** 242 + * @idle: Idle group lists. 243 + * 244 + * When all queues of a group are idle (either because they 245 + * have nothing to execute, or because they are blocked), the 246 + * panthor_group::run_node field should be inserted here. 247 + * 248 + * One list per-priority. 249 + */ 250 + struct list_head idle[PANTHOR_CSG_PRIORITY_COUNT]; 251 + 252 + /** 253 + * @waiting: List of groups whose queues are blocked on a 254 + * synchronization object. 255 + * 256 + * Insert panthor_group::wait_node here when a group is waiting 257 + * for synchronization objects to be signaled. 258 + * 259 + * This list is evaluated in the @sync_upd_work work. 260 + */ 261 + struct list_head waiting; 262 + } groups; 263 + 264 + /** 265 + * @csg_slots: FW command stream group slots. 266 + */ 267 + struct panthor_csg_slot csg_slots[MAX_CSGS]; 268 + 269 + /** @csg_slot_count: Number of command stream group slots exposed by the FW. */ 270 + u32 csg_slot_count; 271 + 272 + /** @cs_slot_count: Number of command stream slot per group slot exposed by the FW. */ 273 + u32 cs_slot_count; 274 + 275 + /** @as_slot_count: Number of address space slots supported by the MMU. */ 276 + u32 as_slot_count; 277 + 278 + /** @used_csg_slot_count: Number of command stream group slot currently used. */ 279 + u32 used_csg_slot_count; 280 + 281 + /** @sb_slot_count: Number of scoreboard slots. */ 282 + u32 sb_slot_count; 283 + 284 + /** 285 + * @might_have_idle_groups: True if an active group might have become idle. 286 + * 287 + * This will force a tick, so other runnable groups can be scheduled if one 288 + * or more active groups became idle. 289 + */ 290 + bool might_have_idle_groups; 291 + 292 + /** @pm: Power management related fields. */ 293 + struct { 294 + /** @has_ref: True if the scheduler owns a runtime PM reference. */ 295 + bool has_ref; 296 + } pm; 297 + 298 + /** @reset: Reset related fields. */ 299 + struct { 300 + /** @lock: Lock protecting the other reset fields. */ 301 + struct mutex lock; 302 + 303 + /** 304 + * @in_progress: True if a reset is in progress. 305 + * 306 + * Set to true in panthor_sched_pre_reset() and back to false in 307 + * panthor_sched_post_reset(). 308 + */ 309 + atomic_t in_progress; 310 + 311 + /** 312 + * @stopped_groups: List containing all groups that were stopped 313 + * before a reset. 314 + * 315 + * Insert panthor_group::run_node in the pre_reset path. 316 + */ 317 + struct list_head stopped_groups; 318 + } reset; 319 + }; 320 + 321 + /** 322 + * struct panthor_syncobj_32b - 32-bit FW synchronization object 323 + */ 324 + struct panthor_syncobj_32b { 325 + /** @seqno: Sequence number. */ 326 + u32 seqno; 327 + 328 + /** 329 + * @status: Status. 330 + * 331 + * Not zero on failure. 332 + */ 333 + u32 status; 334 + }; 335 + 336 + /** 337 + * struct panthor_syncobj_64b - 64-bit FW synchronization object 338 + */ 339 + struct panthor_syncobj_64b { 340 + /** @seqno: Sequence number. */ 341 + u64 seqno; 342 + 343 + /** 344 + * @status: Status. 345 + * 346 + * Not zero on failure. 347 + */ 348 + u32 status; 349 + 350 + /** @pad: MBZ. */ 351 + u32 pad; 352 + }; 353 + 354 + /** 355 + * struct panthor_queue - Execution queue 356 + */ 357 + struct panthor_queue { 358 + /** @scheduler: DRM scheduler used for this queue. */ 359 + struct drm_gpu_scheduler scheduler; 360 + 361 + /** @entity: DRM scheduling entity used for this queue. */ 362 + struct drm_sched_entity entity; 363 + 364 + /** 365 + * @remaining_time: Time remaining before the job timeout expires. 366 + * 367 + * The job timeout is suspended when the queue is not scheduled by the 368 + * FW. Every time we suspend the timer, we need to save the remaining 369 + * time so we can restore it later on. 370 + */ 371 + unsigned long remaining_time; 372 + 373 + /** @timeout_suspended: True if the job timeout was suspended. */ 374 + bool timeout_suspended; 375 + 376 + /** 377 + * @doorbell_id: Doorbell assigned to this queue. 378 + * 379 + * Right now, all groups share the same doorbell, and the doorbell ID 380 + * is assigned to group_slot + 1 when the group is assigned a slot. But 381 + * we might decide to provide fine grained doorbell assignment at some 382 + * point, so don't have to wake up all queues in a group every time one 383 + * of them is updated. 384 + */ 385 + u8 doorbell_id; 386 + 387 + /** 388 + * @priority: Priority of the queue inside the group. 389 + * 390 + * Must be less than 16 (Only 4 bits available). 391 + */ 392 + u8 priority; 393 + #define CSF_MAX_QUEUE_PRIO GENMASK(3, 0) 394 + 395 + /** @ringbuf: Command stream ring-buffer. */ 396 + struct panthor_kernel_bo *ringbuf; 397 + 398 + /** @iface: Firmware interface. */ 399 + struct { 400 + /** @mem: FW memory allocated for this interface. */ 401 + struct panthor_kernel_bo *mem; 402 + 403 + /** @input: Input interface. */ 404 + struct panthor_fw_ringbuf_input_iface *input; 405 + 406 + /** @output: Output interface. */ 407 + const struct panthor_fw_ringbuf_output_iface *output; 408 + 409 + /** @input_fw_va: FW virtual address of the input interface buffer. */ 410 + u32 input_fw_va; 411 + 412 + /** @output_fw_va: FW virtual address of the output interface buffer. */ 413 + u32 output_fw_va; 414 + } iface; 415 + 416 + /** 417 + * @syncwait: Stores information about the synchronization object this 418 + * queue is waiting on. 419 + */ 420 + struct { 421 + /** @gpu_va: GPU address of the synchronization object. */ 422 + u64 gpu_va; 423 + 424 + /** @ref: Reference value to compare against. */ 425 + u64 ref; 426 + 427 + /** @gt: True if this is a greater-than test. */ 428 + bool gt; 429 + 430 + /** @sync64: True if this is a 64-bit sync object. */ 431 + bool sync64; 432 + 433 + /** @bo: Buffer object holding the synchronization object. */ 434 + struct drm_gem_object *obj; 435 + 436 + /** @offset: Offset of the synchronization object inside @bo. */ 437 + u64 offset; 438 + 439 + /** 440 + * @kmap: Kernel mapping of the buffer object holding the 441 + * synchronization object. 442 + */ 443 + void *kmap; 444 + } syncwait; 445 + 446 + /** @fence_ctx: Fence context fields. */ 447 + struct { 448 + /** @lock: Used to protect access to all fences allocated by this context. */ 449 + spinlock_t lock; 450 + 451 + /** 452 + * @id: Fence context ID. 453 + * 454 + * Allocated with dma_fence_context_alloc(). 455 + */ 456 + u64 id; 457 + 458 + /** @seqno: Sequence number of the last initialized fence. */ 459 + atomic64_t seqno; 460 + 461 + /** 462 + * @in_flight_jobs: List containing all in-flight jobs. 463 + * 464 + * Used to keep track and signal panthor_job::done_fence when the 465 + * synchronization object attached to the queue is signaled. 466 + */ 467 + struct list_head in_flight_jobs; 468 + } fence_ctx; 469 + }; 470 + 471 + /** 472 + * enum panthor_group_state - Scheduling group state. 473 + */ 474 + enum panthor_group_state { 475 + /** @PANTHOR_CS_GROUP_CREATED: Group was created, but not scheduled yet. */ 476 + PANTHOR_CS_GROUP_CREATED, 477 + 478 + /** @PANTHOR_CS_GROUP_ACTIVE: Group is currently scheduled. */ 479 + PANTHOR_CS_GROUP_ACTIVE, 480 + 481 + /** 482 + * @PANTHOR_CS_GROUP_SUSPENDED: Group was scheduled at least once, but is 483 + * inactive/suspended right now. 484 + */ 485 + PANTHOR_CS_GROUP_SUSPENDED, 486 + 487 + /** 488 + * @PANTHOR_CS_GROUP_TERMINATED: Group was terminated. 489 + * 490 + * Can no longer be scheduled. The only allowed action is a destruction. 491 + */ 492 + PANTHOR_CS_GROUP_TERMINATED, 493 + }; 494 + 495 + /** 496 + * struct panthor_group - Scheduling group object 497 + */ 498 + struct panthor_group { 499 + /** @refcount: Reference count */ 500 + struct kref refcount; 501 + 502 + /** @ptdev: Device. */ 503 + struct panthor_device *ptdev; 504 + 505 + /** @vm: VM bound to the group. */ 506 + struct panthor_vm *vm; 507 + 508 + /** @compute_core_mask: Mask of shader cores that can be used for compute jobs. */ 509 + u64 compute_core_mask; 510 + 511 + /** @fragment_core_mask: Mask of shader cores that can be used for fragment jobs. */ 512 + u64 fragment_core_mask; 513 + 514 + /** @tiler_core_mask: Mask of tiler cores that can be used for tiler jobs. */ 515 + u64 tiler_core_mask; 516 + 517 + /** @max_compute_cores: Maximum number of shader cores used for compute jobs. */ 518 + u8 max_compute_cores; 519 + 520 + /** @max_compute_cores: Maximum number of shader cores used for fragment jobs. */ 521 + u8 max_fragment_cores; 522 + 523 + /** @max_tiler_cores: Maximum number of tiler cores used for tiler jobs. */ 524 + u8 max_tiler_cores; 525 + 526 + /** @priority: Group priority (check panthor_csg_priority). */ 527 + u8 priority; 528 + 529 + /** @blocked_queues: Bitmask reflecting the blocked queues. */ 530 + u32 blocked_queues; 531 + 532 + /** @idle_queues: Bitmask reflecting the idle queues. */ 533 + u32 idle_queues; 534 + 535 + /** @fatal_lock: Lock used to protect access to fatal fields. */ 536 + spinlock_t fatal_lock; 537 + 538 + /** @fatal_queues: Bitmask reflecting the queues that hit a fatal exception. */ 539 + u32 fatal_queues; 540 + 541 + /** @tiler_oom: Mask of queues that have a tiler OOM event to process. */ 542 + atomic_t tiler_oom; 543 + 544 + /** @queue_count: Number of queues in this group. */ 545 + u32 queue_count; 546 + 547 + /** @queues: Queues owned by this group. */ 548 + struct panthor_queue *queues[MAX_CS_PER_CSG]; 549 + 550 + /** 551 + * @csg_id: ID of the FW group slot. 552 + * 553 + * -1 when the group is not scheduled/active. 554 + */ 555 + int csg_id; 556 + 557 + /** 558 + * @destroyed: True when the group has been destroyed. 559 + * 560 + * If a group is destroyed it becomes useless: no further jobs can be submitted 561 + * to its queues. We simply wait for all references to be dropped so we can 562 + * release the group object. 563 + */ 564 + bool destroyed; 565 + 566 + /** 567 + * @timedout: True when a timeout occurred on any of the queues owned by 568 + * this group. 569 + * 570 + * Timeouts can be reported by drm_sched or by the FW. In any case, any 571 + * timeout situation is unrecoverable, and the group becomes useless. 572 + * We simply wait for all references to be dropped so we can release the 573 + * group object. 574 + */ 575 + bool timedout; 576 + 577 + /** 578 + * @syncobjs: Pool of per-queue synchronization objects. 579 + * 580 + * One sync object per queue. The position of the sync object is 581 + * determined by the queue index. 582 + */ 583 + struct panthor_kernel_bo *syncobjs; 584 + 585 + /** @state: Group state. */ 586 + enum panthor_group_state state; 587 + 588 + /** 589 + * @suspend_buf: Suspend buffer. 590 + * 591 + * Stores the state of the group and its queues when a group is suspended. 592 + * Used at resume time to restore the group in its previous state. 593 + * 594 + * The size of the suspend buffer is exposed through the FW interface. 595 + */ 596 + struct panthor_kernel_bo *suspend_buf; 597 + 598 + /** 599 + * @protm_suspend_buf: Protection mode suspend buffer. 600 + * 601 + * Stores the state of the group and its queues when a group that's in 602 + * protection mode is suspended. 603 + * 604 + * Used at resume time to restore the group in its previous state. 605 + * 606 + * The size of the protection mode suspend buffer is exposed through the 607 + * FW interface. 608 + */ 609 + struct panthor_kernel_bo *protm_suspend_buf; 610 + 611 + /** @sync_upd_work: Work used to check/signal job fences. */ 612 + struct work_struct sync_upd_work; 613 + 614 + /** @tiler_oom_work: Work used to process tiler OOM events happening on this group. */ 615 + struct work_struct tiler_oom_work; 616 + 617 + /** @term_work: Work used to finish the group termination procedure. */ 618 + struct work_struct term_work; 619 + 620 + /** 621 + * @release_work: Work used to release group resources. 622 + * 623 + * We need to postpone the group release to avoid a deadlock when 624 + * the last ref is released in the tick work. 625 + */ 626 + struct work_struct release_work; 627 + 628 + /** 629 + * @run_node: Node used to insert the group in the 630 + * panthor_group::groups::{runnable,idle} and 631 + * panthor_group::reset.stopped_groups lists. 632 + */ 633 + struct list_head run_node; 634 + 635 + /** 636 + * @wait_node: Node used to insert the group in the 637 + * panthor_group::groups::waiting list. 638 + */ 639 + struct list_head wait_node; 640 + }; 641 + 642 + /** 643 + * group_queue_work() - Queue a group work 644 + * @group: Group to queue the work for. 645 + * @wname: Work name. 646 + * 647 + * Grabs a ref and queue a work item to the scheduler workqueue. If 648 + * the work was already queued, we release the reference we grabbed. 649 + * 650 + * Work callbacks must release the reference we grabbed here. 651 + */ 652 + #define group_queue_work(group, wname) \ 653 + do { \ 654 + group_get(group); \ 655 + if (!queue_work((group)->ptdev->scheduler->wq, &(group)->wname ## _work)) \ 656 + group_put(group); \ 657 + } while (0) 658 + 659 + /** 660 + * sched_queue_work() - Queue a scheduler work. 661 + * @sched: Scheduler object. 662 + * @wname: Work name. 663 + * 664 + * Conditionally queues a scheduler work if no reset is pending/in-progress. 665 + */ 666 + #define sched_queue_work(sched, wname) \ 667 + do { \ 668 + if (!atomic_read(&(sched)->reset.in_progress) && \ 669 + !panthor_device_reset_is_pending((sched)->ptdev)) \ 670 + queue_work((sched)->wq, &(sched)->wname ## _work); \ 671 + } while (0) 672 + 673 + /** 674 + * sched_queue_delayed_work() - Queue a scheduler delayed work. 675 + * @sched: Scheduler object. 676 + * @wname: Work name. 677 + * @delay: Work delay in jiffies. 678 + * 679 + * Conditionally queues a scheduler delayed work if no reset is 680 + * pending/in-progress. 681 + */ 682 + #define sched_queue_delayed_work(sched, wname, delay) \ 683 + do { \ 684 + if (!atomic_read(&sched->reset.in_progress) && \ 685 + !panthor_device_reset_is_pending((sched)->ptdev)) \ 686 + mod_delayed_work((sched)->wq, &(sched)->wname ## _work, delay); \ 687 + } while (0) 688 + 689 + /* 690 + * We currently set the maximum of groups per file to an arbitrary low value. 691 + * But this can be updated if we need more. 692 + */ 693 + #define MAX_GROUPS_PER_POOL 128 694 + 695 + /** 696 + * struct panthor_group_pool - Group pool 697 + * 698 + * Each file get assigned a group pool. 699 + */ 700 + struct panthor_group_pool { 701 + /** @xa: Xarray used to manage group handles. */ 702 + struct xarray xa; 703 + }; 704 + 705 + /** 706 + * struct panthor_job - Used to manage GPU job 707 + */ 708 + struct panthor_job { 709 + /** @base: Inherit from drm_sched_job. */ 710 + struct drm_sched_job base; 711 + 712 + /** @refcount: Reference count. */ 713 + struct kref refcount; 714 + 715 + /** @group: Group of the queue this job will be pushed to. */ 716 + struct panthor_group *group; 717 + 718 + /** @queue_idx: Index of the queue inside @group. */ 719 + u32 queue_idx; 720 + 721 + /** @call_info: Information about the userspace command stream call. */ 722 + struct { 723 + /** @start: GPU address of the userspace command stream. */ 724 + u64 start; 725 + 726 + /** @size: Size of the userspace command stream. */ 727 + u32 size; 728 + 729 + /** 730 + * @latest_flush: Flush ID at the time the userspace command 731 + * stream was built. 732 + * 733 + * Needed for the flush reduction mechanism. 734 + */ 735 + u32 latest_flush; 736 + } call_info; 737 + 738 + /** @ringbuf: Position of this job is in the ring buffer. */ 739 + struct { 740 + /** @start: Start offset. */ 741 + u64 start; 742 + 743 + /** @end: End offset. */ 744 + u64 end; 745 + } ringbuf; 746 + 747 + /** 748 + * @node: Used to insert the job in the panthor_queue::fence_ctx::in_flight_jobs 749 + * list. 750 + */ 751 + struct list_head node; 752 + 753 + /** @done_fence: Fence signaled when the job is finished or cancelled. */ 754 + struct dma_fence *done_fence; 755 + }; 756 + 757 + static void 758 + panthor_queue_put_syncwait_obj(struct panthor_queue *queue) 759 + { 760 + if (queue->syncwait.kmap) { 761 + struct iosys_map map = IOSYS_MAP_INIT_VADDR(queue->syncwait.kmap); 762 + 763 + drm_gem_vunmap_unlocked(queue->syncwait.obj, &map); 764 + queue->syncwait.kmap = NULL; 765 + } 766 + 767 + drm_gem_object_put(queue->syncwait.obj); 768 + queue->syncwait.obj = NULL; 769 + } 770 + 771 + static void * 772 + panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue *queue) 773 + { 774 + struct panthor_device *ptdev = group->ptdev; 775 + struct panthor_gem_object *bo; 776 + struct iosys_map map; 777 + int ret; 778 + 779 + if (queue->syncwait.kmap) 780 + return queue->syncwait.kmap + queue->syncwait.offset; 781 + 782 + bo = panthor_vm_get_bo_for_va(group->vm, 783 + queue->syncwait.gpu_va, 784 + &queue->syncwait.offset); 785 + if (drm_WARN_ON(&ptdev->base, IS_ERR_OR_NULL(bo))) 786 + goto err_put_syncwait_obj; 787 + 788 + queue->syncwait.obj = &bo->base.base; 789 + ret = drm_gem_vmap_unlocked(queue->syncwait.obj, &map); 790 + if (drm_WARN_ON(&ptdev->base, ret)) 791 + goto err_put_syncwait_obj; 792 + 793 + queue->syncwait.kmap = map.vaddr; 794 + if (drm_WARN_ON(&ptdev->base, !queue->syncwait.kmap)) 795 + goto err_put_syncwait_obj; 796 + 797 + return queue->syncwait.kmap + queue->syncwait.offset; 798 + 799 + err_put_syncwait_obj: 800 + panthor_queue_put_syncwait_obj(queue); 801 + return NULL; 802 + } 803 + 804 + static void group_free_queue(struct panthor_group *group, struct panthor_queue *queue) 805 + { 806 + if (IS_ERR_OR_NULL(queue)) 807 + return; 808 + 809 + if (queue->entity.fence_context) 810 + drm_sched_entity_destroy(&queue->entity); 811 + 812 + if (queue->scheduler.ops) 813 + drm_sched_fini(&queue->scheduler); 814 + 815 + panthor_queue_put_syncwait_obj(queue); 816 + 817 + panthor_kernel_bo_destroy(group->vm, queue->ringbuf); 818 + panthor_kernel_bo_destroy(panthor_fw_vm(group->ptdev), queue->iface.mem); 819 + 820 + kfree(queue); 821 + } 822 + 823 + static void group_release_work(struct work_struct *work) 824 + { 825 + struct panthor_group *group = container_of(work, 826 + struct panthor_group, 827 + release_work); 828 + struct panthor_device *ptdev = group->ptdev; 829 + u32 i; 830 + 831 + for (i = 0; i < group->queue_count; i++) 832 + group_free_queue(group, group->queues[i]); 833 + 834 + panthor_kernel_bo_destroy(panthor_fw_vm(ptdev), group->suspend_buf); 835 + panthor_kernel_bo_destroy(panthor_fw_vm(ptdev), group->protm_suspend_buf); 836 + panthor_kernel_bo_destroy(group->vm, group->syncobjs); 837 + 838 + panthor_vm_put(group->vm); 839 + kfree(group); 840 + } 841 + 842 + static void group_release(struct kref *kref) 843 + { 844 + struct panthor_group *group = container_of(kref, 845 + struct panthor_group, 846 + refcount); 847 + struct panthor_device *ptdev = group->ptdev; 848 + 849 + drm_WARN_ON(&ptdev->base, group->csg_id >= 0); 850 + drm_WARN_ON(&ptdev->base, !list_empty(&group->run_node)); 851 + drm_WARN_ON(&ptdev->base, !list_empty(&group->wait_node)); 852 + 853 + queue_work(panthor_cleanup_wq, &group->release_work); 854 + } 855 + 856 + static void group_put(struct panthor_group *group) 857 + { 858 + if (group) 859 + kref_put(&group->refcount, group_release); 860 + } 861 + 862 + static struct panthor_group * 863 + group_get(struct panthor_group *group) 864 + { 865 + if (group) 866 + kref_get(&group->refcount); 867 + 868 + return group; 869 + } 870 + 871 + /** 872 + * group_bind_locked() - Bind a group to a group slot 873 + * @group: Group. 874 + * @csg_id: Slot. 875 + * 876 + * Return: 0 on success, a negative error code otherwise. 877 + */ 878 + static int 879 + group_bind_locked(struct panthor_group *group, u32 csg_id) 880 + { 881 + struct panthor_device *ptdev = group->ptdev; 882 + struct panthor_csg_slot *csg_slot; 883 + int ret; 884 + 885 + lockdep_assert_held(&ptdev->scheduler->lock); 886 + 887 + if (drm_WARN_ON(&ptdev->base, group->csg_id != -1 || csg_id >= MAX_CSGS || 888 + ptdev->scheduler->csg_slots[csg_id].group)) 889 + return -EINVAL; 890 + 891 + ret = panthor_vm_active(group->vm); 892 + if (ret) 893 + return ret; 894 + 895 + csg_slot = &ptdev->scheduler->csg_slots[csg_id]; 896 + group_get(group); 897 + group->csg_id = csg_id; 898 + 899 + /* Dummy doorbell allocation: doorbell is assigned to the group and 900 + * all queues use the same doorbell. 901 + * 902 + * TODO: Implement LRU-based doorbell assignment, so the most often 903 + * updated queues get their own doorbell, thus avoiding useless checks 904 + * on queues belonging to the same group that are rarely updated. 905 + */ 906 + for (u32 i = 0; i < group->queue_count; i++) 907 + group->queues[i]->doorbell_id = csg_id + 1; 908 + 909 + csg_slot->group = group; 910 + 911 + return 0; 912 + } 913 + 914 + /** 915 + * group_unbind_locked() - Unbind a group from a slot. 916 + * @group: Group to unbind. 917 + * 918 + * Return: 0 on success, a negative error code otherwise. 919 + */ 920 + static int 921 + group_unbind_locked(struct panthor_group *group) 922 + { 923 + struct panthor_device *ptdev = group->ptdev; 924 + struct panthor_csg_slot *slot; 925 + 926 + lockdep_assert_held(&ptdev->scheduler->lock); 927 + 928 + if (drm_WARN_ON(&ptdev->base, group->csg_id < 0 || group->csg_id >= MAX_CSGS)) 929 + return -EINVAL; 930 + 931 + if (drm_WARN_ON(&ptdev->base, group->state == PANTHOR_CS_GROUP_ACTIVE)) 932 + return -EINVAL; 933 + 934 + slot = &ptdev->scheduler->csg_slots[group->csg_id]; 935 + panthor_vm_idle(group->vm); 936 + group->csg_id = -1; 937 + 938 + /* Tiler OOM events will be re-issued next time the group is scheduled. */ 939 + atomic_set(&group->tiler_oom, 0); 940 + cancel_work(&group->tiler_oom_work); 941 + 942 + for (u32 i = 0; i < group->queue_count; i++) 943 + group->queues[i]->doorbell_id = -1; 944 + 945 + slot->group = NULL; 946 + 947 + group_put(group); 948 + return 0; 949 + } 950 + 951 + /** 952 + * cs_slot_prog_locked() - Program a queue slot 953 + * @ptdev: Device. 954 + * @csg_id: Group slot ID. 955 + * @cs_id: Queue slot ID. 956 + * 957 + * Program a queue slot with the queue information so things can start being 958 + * executed on this queue. 959 + * 960 + * The group slot must have a group bound to it already (group_bind_locked()). 961 + */ 962 + static void 963 + cs_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 cs_id) 964 + { 965 + struct panthor_queue *queue = ptdev->scheduler->csg_slots[csg_id].group->queues[cs_id]; 966 + struct panthor_fw_cs_iface *cs_iface = panthor_fw_get_cs_iface(ptdev, csg_id, cs_id); 967 + 968 + lockdep_assert_held(&ptdev->scheduler->lock); 969 + 970 + queue->iface.input->extract = queue->iface.output->extract; 971 + drm_WARN_ON(&ptdev->base, queue->iface.input->insert < queue->iface.input->extract); 972 + 973 + cs_iface->input->ringbuf_base = panthor_kernel_bo_gpuva(queue->ringbuf); 974 + cs_iface->input->ringbuf_size = panthor_kernel_bo_size(queue->ringbuf); 975 + cs_iface->input->ringbuf_input = queue->iface.input_fw_va; 976 + cs_iface->input->ringbuf_output = queue->iface.output_fw_va; 977 + cs_iface->input->config = CS_CONFIG_PRIORITY(queue->priority) | 978 + CS_CONFIG_DOORBELL(queue->doorbell_id); 979 + cs_iface->input->ack_irq_mask = ~0; 980 + panthor_fw_update_reqs(cs_iface, req, 981 + CS_IDLE_SYNC_WAIT | 982 + CS_IDLE_EMPTY | 983 + CS_STATE_START | 984 + CS_EXTRACT_EVENT, 985 + CS_IDLE_SYNC_WAIT | 986 + CS_IDLE_EMPTY | 987 + CS_STATE_MASK | 988 + CS_EXTRACT_EVENT); 989 + if (queue->iface.input->insert != queue->iface.input->extract && queue->timeout_suspended) { 990 + drm_sched_resume_timeout(&queue->scheduler, queue->remaining_time); 991 + queue->timeout_suspended = false; 992 + } 993 + } 994 + 995 + /** 996 + * @cs_slot_reset_locked() - Reset a queue slot 997 + * @ptdev: Device. 998 + * @csg_id: Group slot. 999 + * @cs_id: Queue slot. 1000 + * 1001 + * Change the queue slot state to STOP and suspend the queue timeout if 1002 + * the queue is not blocked. 1003 + * 1004 + * The group slot must have a group bound to it (group_bind_locked()). 1005 + */ 1006 + static int 1007 + cs_slot_reset_locked(struct panthor_device *ptdev, u32 csg_id, u32 cs_id) 1008 + { 1009 + struct panthor_fw_cs_iface *cs_iface = panthor_fw_get_cs_iface(ptdev, csg_id, cs_id); 1010 + struct panthor_group *group = ptdev->scheduler->csg_slots[csg_id].group; 1011 + struct panthor_queue *queue = group->queues[cs_id]; 1012 + 1013 + lockdep_assert_held(&ptdev->scheduler->lock); 1014 + 1015 + panthor_fw_update_reqs(cs_iface, req, 1016 + CS_STATE_STOP, 1017 + CS_STATE_MASK); 1018 + 1019 + /* If the queue is blocked, we want to keep the timeout running, so 1020 + * we can detect unbounded waits and kill the group when that happens. 1021 + */ 1022 + if (!(group->blocked_queues & BIT(cs_id)) && !queue->timeout_suspended) { 1023 + queue->remaining_time = drm_sched_suspend_timeout(&queue->scheduler); 1024 + queue->timeout_suspended = true; 1025 + WARN_ON(queue->remaining_time > msecs_to_jiffies(JOB_TIMEOUT_MS)); 1026 + } 1027 + 1028 + return 0; 1029 + } 1030 + 1031 + /** 1032 + * csg_slot_sync_priority_locked() - Synchronize the group slot priority 1033 + * @ptdev: Device. 1034 + * @csg_id: Group slot ID. 1035 + * 1036 + * Group slot priority update happens asynchronously. When we receive a 1037 + * %CSG_ENDPOINT_CONFIG, we know the update is effective, and can 1038 + * reflect it to our panthor_csg_slot object. 1039 + */ 1040 + static void 1041 + csg_slot_sync_priority_locked(struct panthor_device *ptdev, u32 csg_id) 1042 + { 1043 + struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id]; 1044 + struct panthor_fw_csg_iface *csg_iface; 1045 + 1046 + lockdep_assert_held(&ptdev->scheduler->lock); 1047 + 1048 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 1049 + csg_slot->priority = (csg_iface->input->endpoint_req & CSG_EP_REQ_PRIORITY_MASK) >> 28; 1050 + } 1051 + 1052 + /** 1053 + * cs_slot_sync_queue_state_locked() - Synchronize the queue slot priority 1054 + * @ptdev: Device. 1055 + * @csg_id: Group slot. 1056 + * @cs_id: Queue slot. 1057 + * 1058 + * Queue state is updated on group suspend or STATUS_UPDATE event. 1059 + */ 1060 + static void 1061 + cs_slot_sync_queue_state_locked(struct panthor_device *ptdev, u32 csg_id, u32 cs_id) 1062 + { 1063 + struct panthor_group *group = ptdev->scheduler->csg_slots[csg_id].group; 1064 + struct panthor_queue *queue = group->queues[cs_id]; 1065 + struct panthor_fw_cs_iface *cs_iface = 1066 + panthor_fw_get_cs_iface(group->ptdev, csg_id, cs_id); 1067 + 1068 + u32 status_wait_cond; 1069 + 1070 + switch (cs_iface->output->status_blocked_reason) { 1071 + case CS_STATUS_BLOCKED_REASON_UNBLOCKED: 1072 + if (queue->iface.input->insert == queue->iface.output->extract && 1073 + cs_iface->output->status_scoreboards == 0) 1074 + group->idle_queues |= BIT(cs_id); 1075 + break; 1076 + 1077 + case CS_STATUS_BLOCKED_REASON_SYNC_WAIT: 1078 + if (list_empty(&group->wait_node)) { 1079 + list_move_tail(&group->wait_node, 1080 + &group->ptdev->scheduler->groups.waiting); 1081 + } 1082 + group->blocked_queues |= BIT(cs_id); 1083 + queue->syncwait.gpu_va = cs_iface->output->status_wait_sync_ptr; 1084 + queue->syncwait.ref = cs_iface->output->status_wait_sync_value; 1085 + status_wait_cond = cs_iface->output->status_wait & CS_STATUS_WAIT_SYNC_COND_MASK; 1086 + queue->syncwait.gt = status_wait_cond == CS_STATUS_WAIT_SYNC_COND_GT; 1087 + if (cs_iface->output->status_wait & CS_STATUS_WAIT_SYNC_64B) { 1088 + u64 sync_val_hi = cs_iface->output->status_wait_sync_value_hi; 1089 + 1090 + queue->syncwait.sync64 = true; 1091 + queue->syncwait.ref |= sync_val_hi << 32; 1092 + } else { 1093 + queue->syncwait.sync64 = false; 1094 + } 1095 + break; 1096 + 1097 + default: 1098 + /* Other reasons are not blocking. Consider the queue as runnable 1099 + * in those cases. 1100 + */ 1101 + break; 1102 + } 1103 + } 1104 + 1105 + static void 1106 + csg_slot_sync_queues_state_locked(struct panthor_device *ptdev, u32 csg_id) 1107 + { 1108 + struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id]; 1109 + struct panthor_group *group = csg_slot->group; 1110 + u32 i; 1111 + 1112 + lockdep_assert_held(&ptdev->scheduler->lock); 1113 + 1114 + group->idle_queues = 0; 1115 + group->blocked_queues = 0; 1116 + 1117 + for (i = 0; i < group->queue_count; i++) { 1118 + if (group->queues[i]) 1119 + cs_slot_sync_queue_state_locked(ptdev, csg_id, i); 1120 + } 1121 + } 1122 + 1123 + static void 1124 + csg_slot_sync_state_locked(struct panthor_device *ptdev, u32 csg_id) 1125 + { 1126 + struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id]; 1127 + struct panthor_fw_csg_iface *csg_iface; 1128 + struct panthor_group *group; 1129 + enum panthor_group_state new_state, old_state; 1130 + 1131 + lockdep_assert_held(&ptdev->scheduler->lock); 1132 + 1133 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 1134 + group = csg_slot->group; 1135 + 1136 + if (!group) 1137 + return; 1138 + 1139 + old_state = group->state; 1140 + switch (csg_iface->output->ack & CSG_STATE_MASK) { 1141 + case CSG_STATE_START: 1142 + case CSG_STATE_RESUME: 1143 + new_state = PANTHOR_CS_GROUP_ACTIVE; 1144 + break; 1145 + case CSG_STATE_TERMINATE: 1146 + new_state = PANTHOR_CS_GROUP_TERMINATED; 1147 + break; 1148 + case CSG_STATE_SUSPEND: 1149 + new_state = PANTHOR_CS_GROUP_SUSPENDED; 1150 + break; 1151 + } 1152 + 1153 + if (old_state == new_state) 1154 + return; 1155 + 1156 + if (new_state == PANTHOR_CS_GROUP_SUSPENDED) 1157 + csg_slot_sync_queues_state_locked(ptdev, csg_id); 1158 + 1159 + if (old_state == PANTHOR_CS_GROUP_ACTIVE) { 1160 + u32 i; 1161 + 1162 + /* Reset the queue slots so we start from a clean 1163 + * state when starting/resuming a new group on this 1164 + * CSG slot. No wait needed here, and no ringbell 1165 + * either, since the CS slot will only be re-used 1166 + * on the next CSG start operation. 1167 + */ 1168 + for (i = 0; i < group->queue_count; i++) { 1169 + if (group->queues[i]) 1170 + cs_slot_reset_locked(ptdev, csg_id, i); 1171 + } 1172 + } 1173 + 1174 + group->state = new_state; 1175 + } 1176 + 1177 + static int 1178 + csg_slot_prog_locked(struct panthor_device *ptdev, u32 csg_id, u32 priority) 1179 + { 1180 + struct panthor_fw_csg_iface *csg_iface; 1181 + struct panthor_csg_slot *csg_slot; 1182 + struct panthor_group *group; 1183 + u32 queue_mask = 0, i; 1184 + 1185 + lockdep_assert_held(&ptdev->scheduler->lock); 1186 + 1187 + if (priority > MAX_CSG_PRIO) 1188 + return -EINVAL; 1189 + 1190 + if (drm_WARN_ON(&ptdev->base, csg_id >= MAX_CSGS)) 1191 + return -EINVAL; 1192 + 1193 + csg_slot = &ptdev->scheduler->csg_slots[csg_id]; 1194 + group = csg_slot->group; 1195 + if (!group || group->state == PANTHOR_CS_GROUP_ACTIVE) 1196 + return 0; 1197 + 1198 + csg_iface = panthor_fw_get_csg_iface(group->ptdev, csg_id); 1199 + 1200 + for (i = 0; i < group->queue_count; i++) { 1201 + if (group->queues[i]) { 1202 + cs_slot_prog_locked(ptdev, csg_id, i); 1203 + queue_mask |= BIT(i); 1204 + } 1205 + } 1206 + 1207 + csg_iface->input->allow_compute = group->compute_core_mask; 1208 + csg_iface->input->allow_fragment = group->fragment_core_mask; 1209 + csg_iface->input->allow_other = group->tiler_core_mask; 1210 + csg_iface->input->endpoint_req = CSG_EP_REQ_COMPUTE(group->max_compute_cores) | 1211 + CSG_EP_REQ_FRAGMENT(group->max_fragment_cores) | 1212 + CSG_EP_REQ_TILER(group->max_tiler_cores) | 1213 + CSG_EP_REQ_PRIORITY(priority); 1214 + csg_iface->input->config = panthor_vm_as(group->vm); 1215 + 1216 + if (group->suspend_buf) 1217 + csg_iface->input->suspend_buf = panthor_kernel_bo_gpuva(group->suspend_buf); 1218 + else 1219 + csg_iface->input->suspend_buf = 0; 1220 + 1221 + if (group->protm_suspend_buf) { 1222 + csg_iface->input->protm_suspend_buf = 1223 + panthor_kernel_bo_gpuva(group->protm_suspend_buf); 1224 + } else { 1225 + csg_iface->input->protm_suspend_buf = 0; 1226 + } 1227 + 1228 + csg_iface->input->ack_irq_mask = ~0; 1229 + panthor_fw_toggle_reqs(csg_iface, doorbell_req, doorbell_ack, queue_mask); 1230 + return 0; 1231 + } 1232 + 1233 + static void 1234 + cs_slot_process_fatal_event_locked(struct panthor_device *ptdev, 1235 + u32 csg_id, u32 cs_id) 1236 + { 1237 + struct panthor_scheduler *sched = ptdev->scheduler; 1238 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[csg_id]; 1239 + struct panthor_group *group = csg_slot->group; 1240 + struct panthor_fw_cs_iface *cs_iface; 1241 + u32 fatal; 1242 + u64 info; 1243 + 1244 + lockdep_assert_held(&sched->lock); 1245 + 1246 + cs_iface = panthor_fw_get_cs_iface(ptdev, csg_id, cs_id); 1247 + fatal = cs_iface->output->fatal; 1248 + info = cs_iface->output->fatal_info; 1249 + 1250 + if (group) 1251 + group->fatal_queues |= BIT(cs_id); 1252 + 1253 + sched_queue_delayed_work(sched, tick, 0); 1254 + drm_warn(&ptdev->base, 1255 + "CSG slot %d CS slot: %d\n" 1256 + "CS_FATAL.EXCEPTION_TYPE: 0x%x (%s)\n" 1257 + "CS_FATAL.EXCEPTION_DATA: 0x%x\n" 1258 + "CS_FATAL_INFO.EXCEPTION_DATA: 0x%llx\n", 1259 + csg_id, cs_id, 1260 + (unsigned int)CS_EXCEPTION_TYPE(fatal), 1261 + panthor_exception_name(ptdev, CS_EXCEPTION_TYPE(fatal)), 1262 + (unsigned int)CS_EXCEPTION_DATA(fatal), 1263 + info); 1264 + } 1265 + 1266 + static void 1267 + cs_slot_process_fault_event_locked(struct panthor_device *ptdev, 1268 + u32 csg_id, u32 cs_id) 1269 + { 1270 + struct panthor_scheduler *sched = ptdev->scheduler; 1271 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[csg_id]; 1272 + struct panthor_group *group = csg_slot->group; 1273 + struct panthor_queue *queue = group && cs_id < group->queue_count ? 1274 + group->queues[cs_id] : NULL; 1275 + struct panthor_fw_cs_iface *cs_iface; 1276 + u32 fault; 1277 + u64 info; 1278 + 1279 + lockdep_assert_held(&sched->lock); 1280 + 1281 + cs_iface = panthor_fw_get_cs_iface(ptdev, csg_id, cs_id); 1282 + fault = cs_iface->output->fault; 1283 + info = cs_iface->output->fault_info; 1284 + 1285 + if (queue && CS_EXCEPTION_TYPE(fault) == DRM_PANTHOR_EXCEPTION_CS_INHERIT_FAULT) { 1286 + u64 cs_extract = queue->iface.output->extract; 1287 + struct panthor_job *job; 1288 + 1289 + spin_lock(&queue->fence_ctx.lock); 1290 + list_for_each_entry(job, &queue->fence_ctx.in_flight_jobs, node) { 1291 + if (cs_extract >= job->ringbuf.end) 1292 + continue; 1293 + 1294 + if (cs_extract < job->ringbuf.start) 1295 + break; 1296 + 1297 + dma_fence_set_error(job->done_fence, -EINVAL); 1298 + } 1299 + spin_unlock(&queue->fence_ctx.lock); 1300 + } 1301 + 1302 + drm_warn(&ptdev->base, 1303 + "CSG slot %d CS slot: %d\n" 1304 + "CS_FAULT.EXCEPTION_TYPE: 0x%x (%s)\n" 1305 + "CS_FAULT.EXCEPTION_DATA: 0x%x\n" 1306 + "CS_FAULT_INFO.EXCEPTION_DATA: 0x%llx\n", 1307 + csg_id, cs_id, 1308 + (unsigned int)CS_EXCEPTION_TYPE(fault), 1309 + panthor_exception_name(ptdev, CS_EXCEPTION_TYPE(fault)), 1310 + (unsigned int)CS_EXCEPTION_DATA(fault), 1311 + info); 1312 + } 1313 + 1314 + static int group_process_tiler_oom(struct panthor_group *group, u32 cs_id) 1315 + { 1316 + struct panthor_device *ptdev = group->ptdev; 1317 + struct panthor_scheduler *sched = ptdev->scheduler; 1318 + u32 renderpasses_in_flight, pending_frag_count; 1319 + struct panthor_heap_pool *heaps = NULL; 1320 + u64 heap_address, new_chunk_va = 0; 1321 + u32 vt_start, vt_end, frag_end; 1322 + int ret, csg_id; 1323 + 1324 + mutex_lock(&sched->lock); 1325 + csg_id = group->csg_id; 1326 + if (csg_id >= 0) { 1327 + struct panthor_fw_cs_iface *cs_iface; 1328 + 1329 + cs_iface = panthor_fw_get_cs_iface(ptdev, csg_id, cs_id); 1330 + heaps = panthor_vm_get_heap_pool(group->vm, false); 1331 + heap_address = cs_iface->output->heap_address; 1332 + vt_start = cs_iface->output->heap_vt_start; 1333 + vt_end = cs_iface->output->heap_vt_end; 1334 + frag_end = cs_iface->output->heap_frag_end; 1335 + renderpasses_in_flight = vt_start - frag_end; 1336 + pending_frag_count = vt_end - frag_end; 1337 + } 1338 + mutex_unlock(&sched->lock); 1339 + 1340 + /* The group got scheduled out, we stop here. We will get a new tiler OOM event 1341 + * when it's scheduled again. 1342 + */ 1343 + if (unlikely(csg_id < 0)) 1344 + return 0; 1345 + 1346 + if (!heaps || frag_end > vt_end || vt_end >= vt_start) { 1347 + ret = -EINVAL; 1348 + } else { 1349 + /* We do the allocation without holding the scheduler lock to avoid 1350 + * blocking the scheduling. 1351 + */ 1352 + ret = panthor_heap_grow(heaps, heap_address, 1353 + renderpasses_in_flight, 1354 + pending_frag_count, &new_chunk_va); 1355 + } 1356 + 1357 + if (ret && ret != -EBUSY) { 1358 + drm_warn(&ptdev->base, "Failed to extend the tiler heap\n"); 1359 + group->fatal_queues |= BIT(cs_id); 1360 + sched_queue_delayed_work(sched, tick, 0); 1361 + goto out_put_heap_pool; 1362 + } 1363 + 1364 + mutex_lock(&sched->lock); 1365 + csg_id = group->csg_id; 1366 + if (csg_id >= 0) { 1367 + struct panthor_fw_csg_iface *csg_iface; 1368 + struct panthor_fw_cs_iface *cs_iface; 1369 + 1370 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 1371 + cs_iface = panthor_fw_get_cs_iface(ptdev, csg_id, cs_id); 1372 + 1373 + cs_iface->input->heap_start = new_chunk_va; 1374 + cs_iface->input->heap_end = new_chunk_va; 1375 + panthor_fw_update_reqs(cs_iface, req, cs_iface->output->ack, CS_TILER_OOM); 1376 + panthor_fw_toggle_reqs(csg_iface, doorbell_req, doorbell_ack, BIT(cs_id)); 1377 + panthor_fw_ring_csg_doorbells(ptdev, BIT(csg_id)); 1378 + } 1379 + mutex_unlock(&sched->lock); 1380 + 1381 + /* We allocated a chunck, but couldn't link it to the heap 1382 + * context because the group was scheduled out while we were 1383 + * allocating memory. We need to return this chunk to the heap. 1384 + */ 1385 + if (unlikely(csg_id < 0 && new_chunk_va)) 1386 + panthor_heap_return_chunk(heaps, heap_address, new_chunk_va); 1387 + 1388 + ret = 0; 1389 + 1390 + out_put_heap_pool: 1391 + panthor_heap_pool_put(heaps); 1392 + return ret; 1393 + } 1394 + 1395 + static void group_tiler_oom_work(struct work_struct *work) 1396 + { 1397 + struct panthor_group *group = 1398 + container_of(work, struct panthor_group, tiler_oom_work); 1399 + u32 tiler_oom = atomic_xchg(&group->tiler_oom, 0); 1400 + 1401 + while (tiler_oom) { 1402 + u32 cs_id = ffs(tiler_oom) - 1; 1403 + 1404 + group_process_tiler_oom(group, cs_id); 1405 + tiler_oom &= ~BIT(cs_id); 1406 + } 1407 + 1408 + group_put(group); 1409 + } 1410 + 1411 + static void 1412 + cs_slot_process_tiler_oom_event_locked(struct panthor_device *ptdev, 1413 + u32 csg_id, u32 cs_id) 1414 + { 1415 + struct panthor_scheduler *sched = ptdev->scheduler; 1416 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[csg_id]; 1417 + struct panthor_group *group = csg_slot->group; 1418 + 1419 + lockdep_assert_held(&sched->lock); 1420 + 1421 + if (drm_WARN_ON(&ptdev->base, !group)) 1422 + return; 1423 + 1424 + atomic_or(BIT(cs_id), &group->tiler_oom); 1425 + 1426 + /* We don't use group_queue_work() here because we want to queue the 1427 + * work item to the heap_alloc_wq. 1428 + */ 1429 + group_get(group); 1430 + if (!queue_work(sched->heap_alloc_wq, &group->tiler_oom_work)) 1431 + group_put(group); 1432 + } 1433 + 1434 + static bool cs_slot_process_irq_locked(struct panthor_device *ptdev, 1435 + u32 csg_id, u32 cs_id) 1436 + { 1437 + struct panthor_fw_cs_iface *cs_iface; 1438 + u32 req, ack, events; 1439 + 1440 + lockdep_assert_held(&ptdev->scheduler->lock); 1441 + 1442 + cs_iface = panthor_fw_get_cs_iface(ptdev, csg_id, cs_id); 1443 + req = cs_iface->input->req; 1444 + ack = cs_iface->output->ack; 1445 + events = (req ^ ack) & CS_EVT_MASK; 1446 + 1447 + if (events & CS_FATAL) 1448 + cs_slot_process_fatal_event_locked(ptdev, csg_id, cs_id); 1449 + 1450 + if (events & CS_FAULT) 1451 + cs_slot_process_fault_event_locked(ptdev, csg_id, cs_id); 1452 + 1453 + if (events & CS_TILER_OOM) 1454 + cs_slot_process_tiler_oom_event_locked(ptdev, csg_id, cs_id); 1455 + 1456 + /* We don't acknowledge the TILER_OOM event since its handling is 1457 + * deferred to a separate work. 1458 + */ 1459 + panthor_fw_update_reqs(cs_iface, req, ack, CS_FATAL | CS_FAULT); 1460 + 1461 + return (events & (CS_FAULT | CS_TILER_OOM)) != 0; 1462 + } 1463 + 1464 + static void csg_slot_sync_idle_state_locked(struct panthor_device *ptdev, u32 csg_id) 1465 + { 1466 + struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id]; 1467 + struct panthor_fw_csg_iface *csg_iface; 1468 + 1469 + lockdep_assert_held(&ptdev->scheduler->lock); 1470 + 1471 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 1472 + csg_slot->idle = csg_iface->output->status_state & CSG_STATUS_STATE_IS_IDLE; 1473 + } 1474 + 1475 + static void csg_slot_process_idle_event_locked(struct panthor_device *ptdev, u32 csg_id) 1476 + { 1477 + struct panthor_scheduler *sched = ptdev->scheduler; 1478 + 1479 + lockdep_assert_held(&sched->lock); 1480 + 1481 + sched->might_have_idle_groups = true; 1482 + 1483 + /* Schedule a tick so we can evict idle groups and schedule non-idle 1484 + * ones. This will also update runtime PM and devfreq busy/idle states, 1485 + * so the device can lower its frequency or get suspended. 1486 + */ 1487 + sched_queue_delayed_work(sched, tick, 0); 1488 + } 1489 + 1490 + static void csg_slot_sync_update_locked(struct panthor_device *ptdev, 1491 + u32 csg_id) 1492 + { 1493 + struct panthor_csg_slot *csg_slot = &ptdev->scheduler->csg_slots[csg_id]; 1494 + struct panthor_group *group = csg_slot->group; 1495 + 1496 + lockdep_assert_held(&ptdev->scheduler->lock); 1497 + 1498 + if (group) 1499 + group_queue_work(group, sync_upd); 1500 + 1501 + sched_queue_work(ptdev->scheduler, sync_upd); 1502 + } 1503 + 1504 + static void 1505 + csg_slot_process_progress_timer_event_locked(struct panthor_device *ptdev, u32 csg_id) 1506 + { 1507 + struct panthor_scheduler *sched = ptdev->scheduler; 1508 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[csg_id]; 1509 + struct panthor_group *group = csg_slot->group; 1510 + 1511 + lockdep_assert_held(&sched->lock); 1512 + 1513 + drm_warn(&ptdev->base, "CSG slot %d progress timeout\n", csg_id); 1514 + 1515 + group = csg_slot->group; 1516 + if (!drm_WARN_ON(&ptdev->base, !group)) 1517 + group->timedout = true; 1518 + 1519 + sched_queue_delayed_work(sched, tick, 0); 1520 + } 1521 + 1522 + static void sched_process_csg_irq_locked(struct panthor_device *ptdev, u32 csg_id) 1523 + { 1524 + u32 req, ack, cs_irq_req, cs_irq_ack, cs_irqs, csg_events; 1525 + struct panthor_fw_csg_iface *csg_iface; 1526 + u32 ring_cs_db_mask = 0; 1527 + 1528 + lockdep_assert_held(&ptdev->scheduler->lock); 1529 + 1530 + if (drm_WARN_ON(&ptdev->base, csg_id >= ptdev->scheduler->csg_slot_count)) 1531 + return; 1532 + 1533 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 1534 + req = READ_ONCE(csg_iface->input->req); 1535 + ack = READ_ONCE(csg_iface->output->ack); 1536 + cs_irq_req = READ_ONCE(csg_iface->output->cs_irq_req); 1537 + cs_irq_ack = READ_ONCE(csg_iface->input->cs_irq_ack); 1538 + csg_events = (req ^ ack) & CSG_EVT_MASK; 1539 + 1540 + /* There may not be any pending CSG/CS interrupts to process */ 1541 + if (req == ack && cs_irq_req == cs_irq_ack) 1542 + return; 1543 + 1544 + /* Immediately set IRQ_ACK bits to be same as the IRQ_REQ bits before 1545 + * examining the CS_ACK & CS_REQ bits. This would ensure that Host 1546 + * doesn't miss an interrupt for the CS in the race scenario where 1547 + * whilst Host is servicing an interrupt for the CS, firmware sends 1548 + * another interrupt for that CS. 1549 + */ 1550 + csg_iface->input->cs_irq_ack = cs_irq_req; 1551 + 1552 + panthor_fw_update_reqs(csg_iface, req, ack, 1553 + CSG_SYNC_UPDATE | 1554 + CSG_IDLE | 1555 + CSG_PROGRESS_TIMER_EVENT); 1556 + 1557 + if (csg_events & CSG_IDLE) 1558 + csg_slot_process_idle_event_locked(ptdev, csg_id); 1559 + 1560 + if (csg_events & CSG_PROGRESS_TIMER_EVENT) 1561 + csg_slot_process_progress_timer_event_locked(ptdev, csg_id); 1562 + 1563 + cs_irqs = cs_irq_req ^ cs_irq_ack; 1564 + while (cs_irqs) { 1565 + u32 cs_id = ffs(cs_irqs) - 1; 1566 + 1567 + if (cs_slot_process_irq_locked(ptdev, csg_id, cs_id)) 1568 + ring_cs_db_mask |= BIT(cs_id); 1569 + 1570 + cs_irqs &= ~BIT(cs_id); 1571 + } 1572 + 1573 + if (csg_events & CSG_SYNC_UPDATE) 1574 + csg_slot_sync_update_locked(ptdev, csg_id); 1575 + 1576 + if (ring_cs_db_mask) 1577 + panthor_fw_toggle_reqs(csg_iface, doorbell_req, doorbell_ack, ring_cs_db_mask); 1578 + 1579 + panthor_fw_ring_csg_doorbells(ptdev, BIT(csg_id)); 1580 + } 1581 + 1582 + static void sched_process_idle_event_locked(struct panthor_device *ptdev) 1583 + { 1584 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 1585 + 1586 + lockdep_assert_held(&ptdev->scheduler->lock); 1587 + 1588 + /* Acknowledge the idle event and schedule a tick. */ 1589 + panthor_fw_update_reqs(glb_iface, req, glb_iface->output->ack, GLB_IDLE); 1590 + sched_queue_delayed_work(ptdev->scheduler, tick, 0); 1591 + } 1592 + 1593 + /** 1594 + * panthor_sched_process_global_irq() - Process the scheduling part of a global IRQ 1595 + * @ptdev: Device. 1596 + */ 1597 + static void sched_process_global_irq_locked(struct panthor_device *ptdev) 1598 + { 1599 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 1600 + u32 req, ack, evts; 1601 + 1602 + lockdep_assert_held(&ptdev->scheduler->lock); 1603 + 1604 + req = READ_ONCE(glb_iface->input->req); 1605 + ack = READ_ONCE(glb_iface->output->ack); 1606 + evts = (req ^ ack) & GLB_EVT_MASK; 1607 + 1608 + if (evts & GLB_IDLE) 1609 + sched_process_idle_event_locked(ptdev); 1610 + } 1611 + 1612 + static void process_fw_events_work(struct work_struct *work) 1613 + { 1614 + struct panthor_scheduler *sched = container_of(work, struct panthor_scheduler, 1615 + fw_events_work); 1616 + u32 events = atomic_xchg(&sched->fw_events, 0); 1617 + struct panthor_device *ptdev = sched->ptdev; 1618 + 1619 + mutex_lock(&sched->lock); 1620 + 1621 + if (events & JOB_INT_GLOBAL_IF) { 1622 + sched_process_global_irq_locked(ptdev); 1623 + events &= ~JOB_INT_GLOBAL_IF; 1624 + } 1625 + 1626 + while (events) { 1627 + u32 csg_id = ffs(events) - 1; 1628 + 1629 + sched_process_csg_irq_locked(ptdev, csg_id); 1630 + events &= ~BIT(csg_id); 1631 + } 1632 + 1633 + mutex_unlock(&sched->lock); 1634 + } 1635 + 1636 + /** 1637 + * panthor_sched_report_fw_events() - Report FW events to the scheduler. 1638 + */ 1639 + void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events) 1640 + { 1641 + if (!ptdev->scheduler) 1642 + return; 1643 + 1644 + atomic_or(events, &ptdev->scheduler->fw_events); 1645 + sched_queue_work(ptdev->scheduler, fw_events); 1646 + } 1647 + 1648 + static const char *fence_get_driver_name(struct dma_fence *fence) 1649 + { 1650 + return "panthor"; 1651 + } 1652 + 1653 + static const char *queue_fence_get_timeline_name(struct dma_fence *fence) 1654 + { 1655 + return "queue-fence"; 1656 + } 1657 + 1658 + static const struct dma_fence_ops panthor_queue_fence_ops = { 1659 + .get_driver_name = fence_get_driver_name, 1660 + .get_timeline_name = queue_fence_get_timeline_name, 1661 + }; 1662 + 1663 + /** 1664 + */ 1665 + struct panthor_csg_slots_upd_ctx { 1666 + u32 update_mask; 1667 + u32 timedout_mask; 1668 + struct { 1669 + u32 value; 1670 + u32 mask; 1671 + } requests[MAX_CSGS]; 1672 + }; 1673 + 1674 + static void csgs_upd_ctx_init(struct panthor_csg_slots_upd_ctx *ctx) 1675 + { 1676 + memset(ctx, 0, sizeof(*ctx)); 1677 + } 1678 + 1679 + static void csgs_upd_ctx_queue_reqs(struct panthor_device *ptdev, 1680 + struct panthor_csg_slots_upd_ctx *ctx, 1681 + u32 csg_id, u32 value, u32 mask) 1682 + { 1683 + if (drm_WARN_ON(&ptdev->base, !mask) || 1684 + drm_WARN_ON(&ptdev->base, csg_id >= ptdev->scheduler->csg_slot_count)) 1685 + return; 1686 + 1687 + ctx->requests[csg_id].value = (ctx->requests[csg_id].value & ~mask) | (value & mask); 1688 + ctx->requests[csg_id].mask |= mask; 1689 + ctx->update_mask |= BIT(csg_id); 1690 + } 1691 + 1692 + static int csgs_upd_ctx_apply_locked(struct panthor_device *ptdev, 1693 + struct panthor_csg_slots_upd_ctx *ctx) 1694 + { 1695 + struct panthor_scheduler *sched = ptdev->scheduler; 1696 + u32 update_slots = ctx->update_mask; 1697 + 1698 + lockdep_assert_held(&sched->lock); 1699 + 1700 + if (!ctx->update_mask) 1701 + return 0; 1702 + 1703 + while (update_slots) { 1704 + struct panthor_fw_csg_iface *csg_iface; 1705 + u32 csg_id = ffs(update_slots) - 1; 1706 + 1707 + update_slots &= ~BIT(csg_id); 1708 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 1709 + panthor_fw_update_reqs(csg_iface, req, 1710 + ctx->requests[csg_id].value, 1711 + ctx->requests[csg_id].mask); 1712 + } 1713 + 1714 + panthor_fw_ring_csg_doorbells(ptdev, ctx->update_mask); 1715 + 1716 + update_slots = ctx->update_mask; 1717 + while (update_slots) { 1718 + struct panthor_fw_csg_iface *csg_iface; 1719 + u32 csg_id = ffs(update_slots) - 1; 1720 + u32 req_mask = ctx->requests[csg_id].mask, acked; 1721 + int ret; 1722 + 1723 + update_slots &= ~BIT(csg_id); 1724 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 1725 + 1726 + ret = panthor_fw_csg_wait_acks(ptdev, csg_id, req_mask, &acked, 100); 1727 + 1728 + if (acked & CSG_ENDPOINT_CONFIG) 1729 + csg_slot_sync_priority_locked(ptdev, csg_id); 1730 + 1731 + if (acked & CSG_STATE_MASK) 1732 + csg_slot_sync_state_locked(ptdev, csg_id); 1733 + 1734 + if (acked & CSG_STATUS_UPDATE) { 1735 + csg_slot_sync_queues_state_locked(ptdev, csg_id); 1736 + csg_slot_sync_idle_state_locked(ptdev, csg_id); 1737 + } 1738 + 1739 + if (ret && acked != req_mask && 1740 + ((csg_iface->input->req ^ csg_iface->output->ack) & req_mask) != 0) { 1741 + drm_err(&ptdev->base, "CSG %d update request timedout", csg_id); 1742 + ctx->timedout_mask |= BIT(csg_id); 1743 + } 1744 + } 1745 + 1746 + if (ctx->timedout_mask) 1747 + return -ETIMEDOUT; 1748 + 1749 + return 0; 1750 + } 1751 + 1752 + struct panthor_sched_tick_ctx { 1753 + struct list_head old_groups[PANTHOR_CSG_PRIORITY_COUNT]; 1754 + struct list_head groups[PANTHOR_CSG_PRIORITY_COUNT]; 1755 + u32 idle_group_count; 1756 + u32 group_count; 1757 + enum panthor_csg_priority min_priority; 1758 + struct panthor_vm *vms[MAX_CS_PER_CSG]; 1759 + u32 as_count; 1760 + bool immediate_tick; 1761 + u32 csg_upd_failed_mask; 1762 + }; 1763 + 1764 + static bool 1765 + tick_ctx_is_full(const struct panthor_scheduler *sched, 1766 + const struct panthor_sched_tick_ctx *ctx) 1767 + { 1768 + return ctx->group_count == sched->csg_slot_count; 1769 + } 1770 + 1771 + static bool 1772 + group_is_idle(struct panthor_group *group) 1773 + { 1774 + struct panthor_device *ptdev = group->ptdev; 1775 + u32 inactive_queues; 1776 + 1777 + if (group->csg_id >= 0) 1778 + return ptdev->scheduler->csg_slots[group->csg_id].idle; 1779 + 1780 + inactive_queues = group->idle_queues | group->blocked_queues; 1781 + return hweight32(inactive_queues) == group->queue_count; 1782 + } 1783 + 1784 + static bool 1785 + group_can_run(struct panthor_group *group) 1786 + { 1787 + return group->state != PANTHOR_CS_GROUP_TERMINATED && 1788 + !group->destroyed && group->fatal_queues == 0 && 1789 + !group->timedout; 1790 + } 1791 + 1792 + static void 1793 + tick_ctx_pick_groups_from_list(const struct panthor_scheduler *sched, 1794 + struct panthor_sched_tick_ctx *ctx, 1795 + struct list_head *queue, 1796 + bool skip_idle_groups, 1797 + bool owned_by_tick_ctx) 1798 + { 1799 + struct panthor_group *group, *tmp; 1800 + 1801 + if (tick_ctx_is_full(sched, ctx)) 1802 + return; 1803 + 1804 + list_for_each_entry_safe(group, tmp, queue, run_node) { 1805 + u32 i; 1806 + 1807 + if (!group_can_run(group)) 1808 + continue; 1809 + 1810 + if (skip_idle_groups && group_is_idle(group)) 1811 + continue; 1812 + 1813 + for (i = 0; i < ctx->as_count; i++) { 1814 + if (ctx->vms[i] == group->vm) 1815 + break; 1816 + } 1817 + 1818 + if (i == ctx->as_count && ctx->as_count == sched->as_slot_count) 1819 + continue; 1820 + 1821 + if (!owned_by_tick_ctx) 1822 + group_get(group); 1823 + 1824 + list_move_tail(&group->run_node, &ctx->groups[group->priority]); 1825 + ctx->group_count++; 1826 + if (group_is_idle(group)) 1827 + ctx->idle_group_count++; 1828 + 1829 + if (i == ctx->as_count) 1830 + ctx->vms[ctx->as_count++] = group->vm; 1831 + 1832 + if (ctx->min_priority > group->priority) 1833 + ctx->min_priority = group->priority; 1834 + 1835 + if (tick_ctx_is_full(sched, ctx)) 1836 + return; 1837 + } 1838 + } 1839 + 1840 + static void 1841 + tick_ctx_insert_old_group(struct panthor_scheduler *sched, 1842 + struct panthor_sched_tick_ctx *ctx, 1843 + struct panthor_group *group, 1844 + bool full_tick) 1845 + { 1846 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[group->csg_id]; 1847 + struct panthor_group *other_group; 1848 + 1849 + if (!full_tick) { 1850 + list_add_tail(&group->run_node, &ctx->old_groups[group->priority]); 1851 + return; 1852 + } 1853 + 1854 + /* Rotate to make sure groups with lower CSG slot 1855 + * priorities have a chance to get a higher CSG slot 1856 + * priority next time they get picked. This priority 1857 + * has an impact on resource request ordering, so it's 1858 + * important to make sure we don't let one group starve 1859 + * all other groups with the same group priority. 1860 + */ 1861 + list_for_each_entry(other_group, 1862 + &ctx->old_groups[csg_slot->group->priority], 1863 + run_node) { 1864 + struct panthor_csg_slot *other_csg_slot = &sched->csg_slots[other_group->csg_id]; 1865 + 1866 + if (other_csg_slot->priority > csg_slot->priority) { 1867 + list_add_tail(&csg_slot->group->run_node, &other_group->run_node); 1868 + return; 1869 + } 1870 + } 1871 + 1872 + list_add_tail(&group->run_node, &ctx->old_groups[group->priority]); 1873 + } 1874 + 1875 + static void 1876 + tick_ctx_init(struct panthor_scheduler *sched, 1877 + struct panthor_sched_tick_ctx *ctx, 1878 + bool full_tick) 1879 + { 1880 + struct panthor_device *ptdev = sched->ptdev; 1881 + struct panthor_csg_slots_upd_ctx upd_ctx; 1882 + int ret; 1883 + u32 i; 1884 + 1885 + memset(ctx, 0, sizeof(*ctx)); 1886 + csgs_upd_ctx_init(&upd_ctx); 1887 + 1888 + ctx->min_priority = PANTHOR_CSG_PRIORITY_COUNT; 1889 + for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) { 1890 + INIT_LIST_HEAD(&ctx->groups[i]); 1891 + INIT_LIST_HEAD(&ctx->old_groups[i]); 1892 + } 1893 + 1894 + for (i = 0; i < sched->csg_slot_count; i++) { 1895 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[i]; 1896 + struct panthor_group *group = csg_slot->group; 1897 + struct panthor_fw_csg_iface *csg_iface; 1898 + 1899 + if (!group) 1900 + continue; 1901 + 1902 + csg_iface = panthor_fw_get_csg_iface(ptdev, i); 1903 + group_get(group); 1904 + 1905 + /* If there was unhandled faults on the VM, force processing of 1906 + * CSG IRQs, so we can flag the faulty queue. 1907 + */ 1908 + if (panthor_vm_has_unhandled_faults(group->vm)) { 1909 + sched_process_csg_irq_locked(ptdev, i); 1910 + 1911 + /* No fatal fault reported, flag all queues as faulty. */ 1912 + if (!group->fatal_queues) 1913 + group->fatal_queues |= GENMASK(group->queue_count - 1, 0); 1914 + } 1915 + 1916 + tick_ctx_insert_old_group(sched, ctx, group, full_tick); 1917 + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i, 1918 + csg_iface->output->ack ^ CSG_STATUS_UPDATE, 1919 + CSG_STATUS_UPDATE); 1920 + } 1921 + 1922 + ret = csgs_upd_ctx_apply_locked(ptdev, &upd_ctx); 1923 + if (ret) { 1924 + panthor_device_schedule_reset(ptdev); 1925 + ctx->csg_upd_failed_mask |= upd_ctx.timedout_mask; 1926 + } 1927 + } 1928 + 1929 + #define NUM_INSTRS_PER_SLOT 16 1930 + 1931 + static void 1932 + group_term_post_processing(struct panthor_group *group) 1933 + { 1934 + struct panthor_job *job, *tmp; 1935 + LIST_HEAD(faulty_jobs); 1936 + bool cookie; 1937 + u32 i = 0; 1938 + 1939 + if (drm_WARN_ON(&group->ptdev->base, group_can_run(group))) 1940 + return; 1941 + 1942 + cookie = dma_fence_begin_signalling(); 1943 + for (i = 0; i < group->queue_count; i++) { 1944 + struct panthor_queue *queue = group->queues[i]; 1945 + struct panthor_syncobj_64b *syncobj; 1946 + int err; 1947 + 1948 + if (group->fatal_queues & BIT(i)) 1949 + err = -EINVAL; 1950 + else if (group->timedout) 1951 + err = -ETIMEDOUT; 1952 + else 1953 + err = -ECANCELED; 1954 + 1955 + if (!queue) 1956 + continue; 1957 + 1958 + spin_lock(&queue->fence_ctx.lock); 1959 + list_for_each_entry_safe(job, tmp, &queue->fence_ctx.in_flight_jobs, node) { 1960 + list_move_tail(&job->node, &faulty_jobs); 1961 + dma_fence_set_error(job->done_fence, err); 1962 + dma_fence_signal_locked(job->done_fence); 1963 + } 1964 + spin_unlock(&queue->fence_ctx.lock); 1965 + 1966 + /* Manually update the syncobj seqno to unblock waiters. */ 1967 + syncobj = group->syncobjs->kmap + (i * sizeof(*syncobj)); 1968 + syncobj->status = ~0; 1969 + syncobj->seqno = atomic64_read(&queue->fence_ctx.seqno); 1970 + sched_queue_work(group->ptdev->scheduler, sync_upd); 1971 + } 1972 + dma_fence_end_signalling(cookie); 1973 + 1974 + list_for_each_entry_safe(job, tmp, &faulty_jobs, node) { 1975 + list_del_init(&job->node); 1976 + panthor_job_put(&job->base); 1977 + } 1978 + } 1979 + 1980 + static void group_term_work(struct work_struct *work) 1981 + { 1982 + struct panthor_group *group = 1983 + container_of(work, struct panthor_group, term_work); 1984 + 1985 + group_term_post_processing(group); 1986 + group_put(group); 1987 + } 1988 + 1989 + static void 1990 + tick_ctx_cleanup(struct panthor_scheduler *sched, 1991 + struct panthor_sched_tick_ctx *ctx) 1992 + { 1993 + struct panthor_group *group, *tmp; 1994 + u32 i; 1995 + 1996 + for (i = 0; i < ARRAY_SIZE(ctx->old_groups); i++) { 1997 + list_for_each_entry_safe(group, tmp, &ctx->old_groups[i], run_node) { 1998 + /* If everything went fine, we should only have groups 1999 + * to be terminated in the old_groups lists. 2000 + */ 2001 + drm_WARN_ON(&group->ptdev->base, !ctx->csg_upd_failed_mask && 2002 + group_can_run(group)); 2003 + 2004 + if (!group_can_run(group)) { 2005 + list_del_init(&group->run_node); 2006 + list_del_init(&group->wait_node); 2007 + group_queue_work(group, term); 2008 + } else if (group->csg_id >= 0) { 2009 + list_del_init(&group->run_node); 2010 + } else { 2011 + list_move(&group->run_node, 2012 + group_is_idle(group) ? 2013 + &sched->groups.idle[group->priority] : 2014 + &sched->groups.runnable[group->priority]); 2015 + } 2016 + group_put(group); 2017 + } 2018 + } 2019 + 2020 + for (i = 0; i < ARRAY_SIZE(ctx->groups); i++) { 2021 + /* If everything went fine, the groups to schedule lists should 2022 + * be empty. 2023 + */ 2024 + drm_WARN_ON(&group->ptdev->base, 2025 + !ctx->csg_upd_failed_mask && !list_empty(&ctx->groups[i])); 2026 + 2027 + list_for_each_entry_safe(group, tmp, &ctx->groups[i], run_node) { 2028 + if (group->csg_id >= 0) { 2029 + list_del_init(&group->run_node); 2030 + } else { 2031 + list_move(&group->run_node, 2032 + group_is_idle(group) ? 2033 + &sched->groups.idle[group->priority] : 2034 + &sched->groups.runnable[group->priority]); 2035 + } 2036 + group_put(group); 2037 + } 2038 + } 2039 + } 2040 + 2041 + static void 2042 + tick_ctx_apply(struct panthor_scheduler *sched, struct panthor_sched_tick_ctx *ctx) 2043 + { 2044 + struct panthor_group *group, *tmp; 2045 + struct panthor_device *ptdev = sched->ptdev; 2046 + struct panthor_csg_slot *csg_slot; 2047 + int prio, new_csg_prio = MAX_CSG_PRIO, i; 2048 + u32 csg_mod_mask = 0, free_csg_slots = 0; 2049 + struct panthor_csg_slots_upd_ctx upd_ctx; 2050 + int ret; 2051 + 2052 + csgs_upd_ctx_init(&upd_ctx); 2053 + 2054 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; prio >= 0; prio--) { 2055 + /* Suspend or terminate evicted groups. */ 2056 + list_for_each_entry(group, &ctx->old_groups[prio], run_node) { 2057 + bool term = !group_can_run(group); 2058 + int csg_id = group->csg_id; 2059 + 2060 + if (drm_WARN_ON(&ptdev->base, csg_id < 0)) 2061 + continue; 2062 + 2063 + csg_slot = &sched->csg_slots[csg_id]; 2064 + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, 2065 + term ? CSG_STATE_TERMINATE : CSG_STATE_SUSPEND, 2066 + CSG_STATE_MASK); 2067 + } 2068 + 2069 + /* Update priorities on already running groups. */ 2070 + list_for_each_entry(group, &ctx->groups[prio], run_node) { 2071 + struct panthor_fw_csg_iface *csg_iface; 2072 + int csg_id = group->csg_id; 2073 + 2074 + if (csg_id < 0) { 2075 + new_csg_prio--; 2076 + continue; 2077 + } 2078 + 2079 + csg_slot = &sched->csg_slots[csg_id]; 2080 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 2081 + if (csg_slot->priority == new_csg_prio) { 2082 + new_csg_prio--; 2083 + continue; 2084 + } 2085 + 2086 + panthor_fw_update_reqs(csg_iface, endpoint_req, 2087 + CSG_EP_REQ_PRIORITY(new_csg_prio), 2088 + CSG_EP_REQ_PRIORITY_MASK); 2089 + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, 2090 + csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG, 2091 + CSG_ENDPOINT_CONFIG); 2092 + new_csg_prio--; 2093 + } 2094 + } 2095 + 2096 + ret = csgs_upd_ctx_apply_locked(ptdev, &upd_ctx); 2097 + if (ret) { 2098 + panthor_device_schedule_reset(ptdev); 2099 + ctx->csg_upd_failed_mask |= upd_ctx.timedout_mask; 2100 + return; 2101 + } 2102 + 2103 + /* Unbind evicted groups. */ 2104 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; prio >= 0; prio--) { 2105 + list_for_each_entry(group, &ctx->old_groups[prio], run_node) { 2106 + /* This group is gone. Process interrupts to clear 2107 + * any pending interrupts before we start the new 2108 + * group. 2109 + */ 2110 + if (group->csg_id >= 0) 2111 + sched_process_csg_irq_locked(ptdev, group->csg_id); 2112 + 2113 + group_unbind_locked(group); 2114 + } 2115 + } 2116 + 2117 + for (i = 0; i < sched->csg_slot_count; i++) { 2118 + if (!sched->csg_slots[i].group) 2119 + free_csg_slots |= BIT(i); 2120 + } 2121 + 2122 + csgs_upd_ctx_init(&upd_ctx); 2123 + new_csg_prio = MAX_CSG_PRIO; 2124 + 2125 + /* Start new groups. */ 2126 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; prio >= 0; prio--) { 2127 + list_for_each_entry(group, &ctx->groups[prio], run_node) { 2128 + int csg_id = group->csg_id; 2129 + struct panthor_fw_csg_iface *csg_iface; 2130 + 2131 + if (csg_id >= 0) { 2132 + new_csg_prio--; 2133 + continue; 2134 + } 2135 + 2136 + csg_id = ffs(free_csg_slots) - 1; 2137 + if (drm_WARN_ON(&ptdev->base, csg_id < 0)) 2138 + break; 2139 + 2140 + csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); 2141 + csg_slot = &sched->csg_slots[csg_id]; 2142 + csg_mod_mask |= BIT(csg_id); 2143 + group_bind_locked(group, csg_id); 2144 + csg_slot_prog_locked(ptdev, csg_id, new_csg_prio--); 2145 + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, 2146 + group->state == PANTHOR_CS_GROUP_SUSPENDED ? 2147 + CSG_STATE_RESUME : CSG_STATE_START, 2148 + CSG_STATE_MASK); 2149 + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, 2150 + csg_iface->output->ack ^ CSG_ENDPOINT_CONFIG, 2151 + CSG_ENDPOINT_CONFIG); 2152 + free_csg_slots &= ~BIT(csg_id); 2153 + } 2154 + } 2155 + 2156 + ret = csgs_upd_ctx_apply_locked(ptdev, &upd_ctx); 2157 + if (ret) { 2158 + panthor_device_schedule_reset(ptdev); 2159 + ctx->csg_upd_failed_mask |= upd_ctx.timedout_mask; 2160 + return; 2161 + } 2162 + 2163 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; prio >= 0; prio--) { 2164 + list_for_each_entry_safe(group, tmp, &ctx->groups[prio], run_node) { 2165 + list_del_init(&group->run_node); 2166 + 2167 + /* If the group has been destroyed while we were 2168 + * scheduling, ask for an immediate tick to 2169 + * re-evaluate as soon as possible and get rid of 2170 + * this dangling group. 2171 + */ 2172 + if (group->destroyed) 2173 + ctx->immediate_tick = true; 2174 + group_put(group); 2175 + } 2176 + 2177 + /* Return evicted groups to the idle or run queues. Groups 2178 + * that can no longer be run (because they've been destroyed 2179 + * or experienced an unrecoverable error) will be scheduled 2180 + * for destruction in tick_ctx_cleanup(). 2181 + */ 2182 + list_for_each_entry_safe(group, tmp, &ctx->old_groups[prio], run_node) { 2183 + if (!group_can_run(group)) 2184 + continue; 2185 + 2186 + if (group_is_idle(group)) 2187 + list_move_tail(&group->run_node, &sched->groups.idle[prio]); 2188 + else 2189 + list_move_tail(&group->run_node, &sched->groups.runnable[prio]); 2190 + group_put(group); 2191 + } 2192 + } 2193 + 2194 + sched->used_csg_slot_count = ctx->group_count; 2195 + sched->might_have_idle_groups = ctx->idle_group_count > 0; 2196 + } 2197 + 2198 + static u64 2199 + tick_ctx_update_resched_target(struct panthor_scheduler *sched, 2200 + const struct panthor_sched_tick_ctx *ctx) 2201 + { 2202 + /* We had space left, no need to reschedule until some external event happens. */ 2203 + if (!tick_ctx_is_full(sched, ctx)) 2204 + goto no_tick; 2205 + 2206 + /* If idle groups were scheduled, no need to wake up until some external 2207 + * event happens (group unblocked, new job submitted, ...). 2208 + */ 2209 + if (ctx->idle_group_count) 2210 + goto no_tick; 2211 + 2212 + if (drm_WARN_ON(&sched->ptdev->base, ctx->min_priority >= PANTHOR_CSG_PRIORITY_COUNT)) 2213 + goto no_tick; 2214 + 2215 + /* If there are groups of the same priority waiting, we need to 2216 + * keep the scheduler ticking, otherwise, we'll just wait for 2217 + * new groups with higher priority to be queued. 2218 + */ 2219 + if (!list_empty(&sched->groups.runnable[ctx->min_priority])) { 2220 + u64 resched_target = sched->last_tick + sched->tick_period; 2221 + 2222 + if (time_before64(sched->resched_target, sched->last_tick) || 2223 + time_before64(resched_target, sched->resched_target)) 2224 + sched->resched_target = resched_target; 2225 + 2226 + return sched->resched_target - sched->last_tick; 2227 + } 2228 + 2229 + no_tick: 2230 + sched->resched_target = U64_MAX; 2231 + return U64_MAX; 2232 + } 2233 + 2234 + static void tick_work(struct work_struct *work) 2235 + { 2236 + struct panthor_scheduler *sched = container_of(work, struct panthor_scheduler, 2237 + tick_work.work); 2238 + struct panthor_device *ptdev = sched->ptdev; 2239 + struct panthor_sched_tick_ctx ctx; 2240 + u64 remaining_jiffies = 0, resched_delay; 2241 + u64 now = get_jiffies_64(); 2242 + int prio, ret, cookie; 2243 + 2244 + if (!drm_dev_enter(&ptdev->base, &cookie)) 2245 + return; 2246 + 2247 + ret = pm_runtime_resume_and_get(ptdev->base.dev); 2248 + if (drm_WARN_ON(&ptdev->base, ret)) 2249 + goto out_dev_exit; 2250 + 2251 + if (time_before64(now, sched->resched_target)) 2252 + remaining_jiffies = sched->resched_target - now; 2253 + 2254 + mutex_lock(&sched->lock); 2255 + if (panthor_device_reset_is_pending(sched->ptdev)) 2256 + goto out_unlock; 2257 + 2258 + tick_ctx_init(sched, &ctx, remaining_jiffies != 0); 2259 + if (ctx.csg_upd_failed_mask) 2260 + goto out_cleanup_ctx; 2261 + 2262 + if (remaining_jiffies) { 2263 + /* Scheduling forced in the middle of a tick. Only RT groups 2264 + * can preempt non-RT ones. Currently running RT groups can't be 2265 + * preempted. 2266 + */ 2267 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; 2268 + prio >= 0 && !tick_ctx_is_full(sched, &ctx); 2269 + prio--) { 2270 + tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], 2271 + true, true); 2272 + if (prio == PANTHOR_CSG_PRIORITY_RT) { 2273 + tick_ctx_pick_groups_from_list(sched, &ctx, 2274 + &sched->groups.runnable[prio], 2275 + true, false); 2276 + } 2277 + } 2278 + } 2279 + 2280 + /* First pick non-idle groups */ 2281 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; 2282 + prio >= 0 && !tick_ctx_is_full(sched, &ctx); 2283 + prio--) { 2284 + tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.runnable[prio], 2285 + true, false); 2286 + tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], true, true); 2287 + } 2288 + 2289 + /* If we have free CSG slots left, pick idle groups */ 2290 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; 2291 + prio >= 0 && !tick_ctx_is_full(sched, &ctx); 2292 + prio--) { 2293 + /* Check the old_group queue first to avoid reprogramming the slots */ 2294 + tick_ctx_pick_groups_from_list(sched, &ctx, &ctx.old_groups[prio], false, true); 2295 + tick_ctx_pick_groups_from_list(sched, &ctx, &sched->groups.idle[prio], 2296 + false, false); 2297 + } 2298 + 2299 + tick_ctx_apply(sched, &ctx); 2300 + if (ctx.csg_upd_failed_mask) 2301 + goto out_cleanup_ctx; 2302 + 2303 + if (ctx.idle_group_count == ctx.group_count) { 2304 + panthor_devfreq_record_idle(sched->ptdev); 2305 + if (sched->pm.has_ref) { 2306 + pm_runtime_put_autosuspend(ptdev->base.dev); 2307 + sched->pm.has_ref = false; 2308 + } 2309 + } else { 2310 + panthor_devfreq_record_busy(sched->ptdev); 2311 + if (!sched->pm.has_ref) { 2312 + pm_runtime_get(ptdev->base.dev); 2313 + sched->pm.has_ref = true; 2314 + } 2315 + } 2316 + 2317 + sched->last_tick = now; 2318 + resched_delay = tick_ctx_update_resched_target(sched, &ctx); 2319 + if (ctx.immediate_tick) 2320 + resched_delay = 0; 2321 + 2322 + if (resched_delay != U64_MAX) 2323 + sched_queue_delayed_work(sched, tick, resched_delay); 2324 + 2325 + out_cleanup_ctx: 2326 + tick_ctx_cleanup(sched, &ctx); 2327 + 2328 + out_unlock: 2329 + mutex_unlock(&sched->lock); 2330 + pm_runtime_mark_last_busy(ptdev->base.dev); 2331 + pm_runtime_put_autosuspend(ptdev->base.dev); 2332 + 2333 + out_dev_exit: 2334 + drm_dev_exit(cookie); 2335 + } 2336 + 2337 + static int panthor_queue_eval_syncwait(struct panthor_group *group, u8 queue_idx) 2338 + { 2339 + struct panthor_queue *queue = group->queues[queue_idx]; 2340 + union { 2341 + struct panthor_syncobj_64b sync64; 2342 + struct panthor_syncobj_32b sync32; 2343 + } *syncobj; 2344 + bool result; 2345 + u64 value; 2346 + 2347 + syncobj = panthor_queue_get_syncwait_obj(group, queue); 2348 + if (!syncobj) 2349 + return -EINVAL; 2350 + 2351 + value = queue->syncwait.sync64 ? 2352 + syncobj->sync64.seqno : 2353 + syncobj->sync32.seqno; 2354 + 2355 + if (queue->syncwait.gt) 2356 + result = value > queue->syncwait.ref; 2357 + else 2358 + result = value <= queue->syncwait.ref; 2359 + 2360 + if (result) 2361 + panthor_queue_put_syncwait_obj(queue); 2362 + 2363 + return result; 2364 + } 2365 + 2366 + static void sync_upd_work(struct work_struct *work) 2367 + { 2368 + struct panthor_scheduler *sched = container_of(work, 2369 + struct panthor_scheduler, 2370 + sync_upd_work); 2371 + struct panthor_group *group, *tmp; 2372 + bool immediate_tick = false; 2373 + 2374 + mutex_lock(&sched->lock); 2375 + list_for_each_entry_safe(group, tmp, &sched->groups.waiting, wait_node) { 2376 + u32 tested_queues = group->blocked_queues; 2377 + u32 unblocked_queues = 0; 2378 + 2379 + while (tested_queues) { 2380 + u32 cs_id = ffs(tested_queues) - 1; 2381 + int ret; 2382 + 2383 + ret = panthor_queue_eval_syncwait(group, cs_id); 2384 + drm_WARN_ON(&group->ptdev->base, ret < 0); 2385 + if (ret) 2386 + unblocked_queues |= BIT(cs_id); 2387 + 2388 + tested_queues &= ~BIT(cs_id); 2389 + } 2390 + 2391 + if (unblocked_queues) { 2392 + group->blocked_queues &= ~unblocked_queues; 2393 + 2394 + if (group->csg_id < 0) { 2395 + list_move(&group->run_node, 2396 + &sched->groups.runnable[group->priority]); 2397 + if (group->priority == PANTHOR_CSG_PRIORITY_RT) 2398 + immediate_tick = true; 2399 + } 2400 + } 2401 + 2402 + if (!group->blocked_queues) 2403 + list_del_init(&group->wait_node); 2404 + } 2405 + mutex_unlock(&sched->lock); 2406 + 2407 + if (immediate_tick) 2408 + sched_queue_delayed_work(sched, tick, 0); 2409 + } 2410 + 2411 + static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) 2412 + { 2413 + struct panthor_device *ptdev = group->ptdev; 2414 + struct panthor_scheduler *sched = ptdev->scheduler; 2415 + struct list_head *queue = &sched->groups.runnable[group->priority]; 2416 + u64 delay_jiffies = 0; 2417 + bool was_idle; 2418 + u64 now; 2419 + 2420 + if (!group_can_run(group)) 2421 + return; 2422 + 2423 + /* All updated queues are blocked, no need to wake up the scheduler. */ 2424 + if ((queue_mask & group->blocked_queues) == queue_mask) 2425 + return; 2426 + 2427 + was_idle = group_is_idle(group); 2428 + group->idle_queues &= ~queue_mask; 2429 + 2430 + /* Don't mess up with the lists if we're in a middle of a reset. */ 2431 + if (atomic_read(&sched->reset.in_progress)) 2432 + return; 2433 + 2434 + if (was_idle && !group_is_idle(group)) 2435 + list_move_tail(&group->run_node, queue); 2436 + 2437 + /* RT groups are preemptive. */ 2438 + if (group->priority == PANTHOR_CSG_PRIORITY_RT) { 2439 + sched_queue_delayed_work(sched, tick, 0); 2440 + return; 2441 + } 2442 + 2443 + /* Some groups might be idle, force an immediate tick to 2444 + * re-evaluate. 2445 + */ 2446 + if (sched->might_have_idle_groups) { 2447 + sched_queue_delayed_work(sched, tick, 0); 2448 + return; 2449 + } 2450 + 2451 + /* Scheduler is ticking, nothing to do. */ 2452 + if (sched->resched_target != U64_MAX) { 2453 + /* If there are free slots, force immediating ticking. */ 2454 + if (sched->used_csg_slot_count < sched->csg_slot_count) 2455 + sched_queue_delayed_work(sched, tick, 0); 2456 + 2457 + return; 2458 + } 2459 + 2460 + /* Scheduler tick was off, recalculate the resched_target based on the 2461 + * last tick event, and queue the scheduler work. 2462 + */ 2463 + now = get_jiffies_64(); 2464 + sched->resched_target = sched->last_tick + sched->tick_period; 2465 + if (sched->used_csg_slot_count == sched->csg_slot_count && 2466 + time_before64(now, sched->resched_target)) 2467 + delay_jiffies = min_t(unsigned long, sched->resched_target - now, ULONG_MAX); 2468 + 2469 + sched_queue_delayed_work(sched, tick, delay_jiffies); 2470 + } 2471 + 2472 + static void queue_stop(struct panthor_queue *queue, 2473 + struct panthor_job *bad_job) 2474 + { 2475 + drm_sched_stop(&queue->scheduler, bad_job ? &bad_job->base : NULL); 2476 + } 2477 + 2478 + static void queue_start(struct panthor_queue *queue) 2479 + { 2480 + struct panthor_job *job; 2481 + 2482 + /* Re-assign the parent fences. */ 2483 + list_for_each_entry(job, &queue->scheduler.pending_list, base.list) 2484 + job->base.s_fence->parent = dma_fence_get(job->done_fence); 2485 + 2486 + drm_sched_start(&queue->scheduler, true); 2487 + } 2488 + 2489 + static void panthor_group_stop(struct panthor_group *group) 2490 + { 2491 + struct panthor_scheduler *sched = group->ptdev->scheduler; 2492 + 2493 + lockdep_assert_held(&sched->reset.lock); 2494 + 2495 + for (u32 i = 0; i < group->queue_count; i++) 2496 + queue_stop(group->queues[i], NULL); 2497 + 2498 + group_get(group); 2499 + list_move_tail(&group->run_node, &sched->reset.stopped_groups); 2500 + } 2501 + 2502 + static void panthor_group_start(struct panthor_group *group) 2503 + { 2504 + struct panthor_scheduler *sched = group->ptdev->scheduler; 2505 + 2506 + lockdep_assert_held(&group->ptdev->scheduler->reset.lock); 2507 + 2508 + for (u32 i = 0; i < group->queue_count; i++) 2509 + queue_start(group->queues[i]); 2510 + 2511 + if (group_can_run(group)) { 2512 + list_move_tail(&group->run_node, 2513 + group_is_idle(group) ? 2514 + &sched->groups.idle[group->priority] : 2515 + &sched->groups.runnable[group->priority]); 2516 + } else { 2517 + list_del_init(&group->run_node); 2518 + list_del_init(&group->wait_node); 2519 + group_queue_work(group, term); 2520 + } 2521 + 2522 + group_put(group); 2523 + } 2524 + 2525 + static void panthor_sched_immediate_tick(struct panthor_device *ptdev) 2526 + { 2527 + struct panthor_scheduler *sched = ptdev->scheduler; 2528 + 2529 + sched_queue_delayed_work(sched, tick, 0); 2530 + } 2531 + 2532 + /** 2533 + * panthor_sched_report_mmu_fault() - Report MMU faults to the scheduler. 2534 + */ 2535 + void panthor_sched_report_mmu_fault(struct panthor_device *ptdev) 2536 + { 2537 + /* Force a tick to immediately kill faulty groups. */ 2538 + if (ptdev->scheduler) 2539 + panthor_sched_immediate_tick(ptdev); 2540 + } 2541 + 2542 + void panthor_sched_resume(struct panthor_device *ptdev) 2543 + { 2544 + /* Force a tick to re-evaluate after a resume. */ 2545 + panthor_sched_immediate_tick(ptdev); 2546 + } 2547 + 2548 + void panthor_sched_suspend(struct panthor_device *ptdev) 2549 + { 2550 + struct panthor_scheduler *sched = ptdev->scheduler; 2551 + struct panthor_csg_slots_upd_ctx upd_ctx; 2552 + u64 suspended_slots, faulty_slots; 2553 + struct panthor_group *group; 2554 + u32 i; 2555 + 2556 + mutex_lock(&sched->lock); 2557 + csgs_upd_ctx_init(&upd_ctx); 2558 + for (i = 0; i < sched->csg_slot_count; i++) { 2559 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[i]; 2560 + 2561 + if (csg_slot->group) { 2562 + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, i, 2563 + CSG_STATE_SUSPEND, 2564 + CSG_STATE_MASK); 2565 + } 2566 + } 2567 + 2568 + suspended_slots = upd_ctx.update_mask; 2569 + 2570 + csgs_upd_ctx_apply_locked(ptdev, &upd_ctx); 2571 + suspended_slots &= ~upd_ctx.timedout_mask; 2572 + faulty_slots = upd_ctx.timedout_mask; 2573 + 2574 + if (faulty_slots) { 2575 + u32 slot_mask = faulty_slots; 2576 + 2577 + drm_err(&ptdev->base, "CSG suspend failed, escalating to termination"); 2578 + csgs_upd_ctx_init(&upd_ctx); 2579 + while (slot_mask) { 2580 + u32 csg_id = ffs(slot_mask) - 1; 2581 + 2582 + csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, 2583 + CSG_STATE_TERMINATE, 2584 + CSG_STATE_MASK); 2585 + slot_mask &= ~BIT(csg_id); 2586 + } 2587 + 2588 + csgs_upd_ctx_apply_locked(ptdev, &upd_ctx); 2589 + 2590 + slot_mask = upd_ctx.timedout_mask; 2591 + while (slot_mask) { 2592 + u32 csg_id = ffs(slot_mask) - 1; 2593 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[csg_id]; 2594 + 2595 + /* Terminate command timedout, but the soft-reset will 2596 + * automatically terminate all active groups, so let's 2597 + * force the state to halted here. 2598 + */ 2599 + if (csg_slot->group->state != PANTHOR_CS_GROUP_TERMINATED) 2600 + csg_slot->group->state = PANTHOR_CS_GROUP_TERMINATED; 2601 + slot_mask &= ~BIT(csg_id); 2602 + } 2603 + } 2604 + 2605 + /* Flush L2 and LSC caches to make sure suspend state is up-to-date. 2606 + * If the flush fails, flag all queues for termination. 2607 + */ 2608 + if (suspended_slots) { 2609 + bool flush_caches_failed = false; 2610 + u32 slot_mask = suspended_slots; 2611 + 2612 + if (panthor_gpu_flush_caches(ptdev, CACHE_CLEAN, CACHE_CLEAN, 0)) 2613 + flush_caches_failed = true; 2614 + 2615 + while (slot_mask) { 2616 + u32 csg_id = ffs(slot_mask) - 1; 2617 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[csg_id]; 2618 + 2619 + if (flush_caches_failed) 2620 + csg_slot->group->state = PANTHOR_CS_GROUP_TERMINATED; 2621 + else 2622 + csg_slot_sync_update_locked(ptdev, csg_id); 2623 + 2624 + slot_mask &= ~BIT(csg_id); 2625 + } 2626 + 2627 + if (flush_caches_failed) 2628 + faulty_slots |= suspended_slots; 2629 + } 2630 + 2631 + for (i = 0; i < sched->csg_slot_count; i++) { 2632 + struct panthor_csg_slot *csg_slot = &sched->csg_slots[i]; 2633 + 2634 + group = csg_slot->group; 2635 + if (!group) 2636 + continue; 2637 + 2638 + group_get(group); 2639 + 2640 + if (group->csg_id >= 0) 2641 + sched_process_csg_irq_locked(ptdev, group->csg_id); 2642 + 2643 + group_unbind_locked(group); 2644 + 2645 + drm_WARN_ON(&group->ptdev->base, !list_empty(&group->run_node)); 2646 + 2647 + if (group_can_run(group)) { 2648 + list_add(&group->run_node, 2649 + &sched->groups.idle[group->priority]); 2650 + } else { 2651 + /* We don't bother stopping the scheduler if the group is 2652 + * faulty, the group termination work will finish the job. 2653 + */ 2654 + list_del_init(&group->wait_node); 2655 + group_queue_work(group, term); 2656 + } 2657 + group_put(group); 2658 + } 2659 + mutex_unlock(&sched->lock); 2660 + } 2661 + 2662 + void panthor_sched_pre_reset(struct panthor_device *ptdev) 2663 + { 2664 + struct panthor_scheduler *sched = ptdev->scheduler; 2665 + struct panthor_group *group, *group_tmp; 2666 + u32 i; 2667 + 2668 + mutex_lock(&sched->reset.lock); 2669 + atomic_set(&sched->reset.in_progress, true); 2670 + 2671 + /* Cancel all scheduler works. Once this is done, these works can't be 2672 + * scheduled again until the reset operation is complete. 2673 + */ 2674 + cancel_work_sync(&sched->sync_upd_work); 2675 + cancel_delayed_work_sync(&sched->tick_work); 2676 + 2677 + panthor_sched_suspend(ptdev); 2678 + 2679 + /* Stop all groups that might still accept jobs, so we don't get passed 2680 + * new jobs while we're resetting. 2681 + */ 2682 + for (i = 0; i < ARRAY_SIZE(sched->groups.runnable); i++) { 2683 + /* All groups should be in the idle lists. */ 2684 + drm_WARN_ON(&ptdev->base, !list_empty(&sched->groups.runnable[i])); 2685 + list_for_each_entry_safe(group, group_tmp, &sched->groups.runnable[i], run_node) 2686 + panthor_group_stop(group); 2687 + } 2688 + 2689 + for (i = 0; i < ARRAY_SIZE(sched->groups.idle); i++) { 2690 + list_for_each_entry_safe(group, group_tmp, &sched->groups.idle[i], run_node) 2691 + panthor_group_stop(group); 2692 + } 2693 + 2694 + mutex_unlock(&sched->reset.lock); 2695 + } 2696 + 2697 + void panthor_sched_post_reset(struct panthor_device *ptdev) 2698 + { 2699 + struct panthor_scheduler *sched = ptdev->scheduler; 2700 + struct panthor_group *group, *group_tmp; 2701 + 2702 + mutex_lock(&sched->reset.lock); 2703 + 2704 + list_for_each_entry_safe(group, group_tmp, &sched->reset.stopped_groups, run_node) 2705 + panthor_group_start(group); 2706 + 2707 + /* We're done resetting the GPU, clear the reset.in_progress bit so we can 2708 + * kick the scheduler. 2709 + */ 2710 + atomic_set(&sched->reset.in_progress, false); 2711 + mutex_unlock(&sched->reset.lock); 2712 + 2713 + sched_queue_delayed_work(sched, tick, 0); 2714 + 2715 + sched_queue_work(sched, sync_upd); 2716 + } 2717 + 2718 + static void group_sync_upd_work(struct work_struct *work) 2719 + { 2720 + struct panthor_group *group = 2721 + container_of(work, struct panthor_group, sync_upd_work); 2722 + struct panthor_job *job, *job_tmp; 2723 + LIST_HEAD(done_jobs); 2724 + u32 queue_idx; 2725 + bool cookie; 2726 + 2727 + cookie = dma_fence_begin_signalling(); 2728 + for (queue_idx = 0; queue_idx < group->queue_count; queue_idx++) { 2729 + struct panthor_queue *queue = group->queues[queue_idx]; 2730 + struct panthor_syncobj_64b *syncobj; 2731 + 2732 + if (!queue) 2733 + continue; 2734 + 2735 + syncobj = group->syncobjs->kmap + (queue_idx * sizeof(*syncobj)); 2736 + 2737 + spin_lock(&queue->fence_ctx.lock); 2738 + list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) { 2739 + if (!job->call_info.size) 2740 + continue; 2741 + 2742 + if (syncobj->seqno < job->done_fence->seqno) 2743 + break; 2744 + 2745 + list_move_tail(&job->node, &done_jobs); 2746 + dma_fence_signal_locked(job->done_fence); 2747 + } 2748 + spin_unlock(&queue->fence_ctx.lock); 2749 + } 2750 + dma_fence_end_signalling(cookie); 2751 + 2752 + list_for_each_entry_safe(job, job_tmp, &done_jobs, node) { 2753 + list_del_init(&job->node); 2754 + panthor_job_put(&job->base); 2755 + } 2756 + 2757 + group_put(group); 2758 + } 2759 + 2760 + static struct dma_fence * 2761 + queue_run_job(struct drm_sched_job *sched_job) 2762 + { 2763 + struct panthor_job *job = container_of(sched_job, struct panthor_job, base); 2764 + struct panthor_group *group = job->group; 2765 + struct panthor_queue *queue = group->queues[job->queue_idx]; 2766 + struct panthor_device *ptdev = group->ptdev; 2767 + struct panthor_scheduler *sched = ptdev->scheduler; 2768 + u32 ringbuf_size = panthor_kernel_bo_size(queue->ringbuf); 2769 + u32 ringbuf_insert = queue->iface.input->insert & (ringbuf_size - 1); 2770 + u64 addr_reg = ptdev->csif_info.cs_reg_count - 2771 + ptdev->csif_info.unpreserved_cs_reg_count; 2772 + u64 val_reg = addr_reg + 2; 2773 + u64 sync_addr = panthor_kernel_bo_gpuva(group->syncobjs) + 2774 + job->queue_idx * sizeof(struct panthor_syncobj_64b); 2775 + u32 waitall_mask = GENMASK(sched->sb_slot_count - 1, 0); 2776 + struct dma_fence *done_fence; 2777 + int ret; 2778 + 2779 + u64 call_instrs[NUM_INSTRS_PER_SLOT] = { 2780 + /* MOV32 rX+2, cs.latest_flush */ 2781 + (2ull << 56) | (val_reg << 48) | job->call_info.latest_flush, 2782 + 2783 + /* FLUSH_CACHE2.clean_inv_all.no_wait.signal(0) rX+2 */ 2784 + (36ull << 56) | (0ull << 48) | (val_reg << 40) | (0 << 16) | 0x233, 2785 + 2786 + /* MOV48 rX:rX+1, cs.start */ 2787 + (1ull << 56) | (addr_reg << 48) | job->call_info.start, 2788 + 2789 + /* MOV32 rX+2, cs.size */ 2790 + (2ull << 56) | (val_reg << 48) | job->call_info.size, 2791 + 2792 + /* WAIT(0) => waits for FLUSH_CACHE2 instruction */ 2793 + (3ull << 56) | (1 << 16), 2794 + 2795 + /* CALL rX:rX+1, rX+2 */ 2796 + (32ull << 56) | (addr_reg << 40) | (val_reg << 32), 2797 + 2798 + /* MOV48 rX:rX+1, sync_addr */ 2799 + (1ull << 56) | (addr_reg << 48) | sync_addr, 2800 + 2801 + /* MOV48 rX+2, #1 */ 2802 + (1ull << 56) | (val_reg << 48) | 1, 2803 + 2804 + /* WAIT(all) */ 2805 + (3ull << 56) | (waitall_mask << 16), 2806 + 2807 + /* SYNC_ADD64.system_scope.propage_err.nowait rX:rX+1, rX+2*/ 2808 + (51ull << 56) | (0ull << 48) | (addr_reg << 40) | (val_reg << 32) | (0 << 16) | 1, 2809 + 2810 + /* ERROR_BARRIER, so we can recover from faults at job 2811 + * boundaries. 2812 + */ 2813 + (47ull << 56), 2814 + }; 2815 + 2816 + /* Need to be cacheline aligned to please the prefetcher. */ 2817 + static_assert(sizeof(call_instrs) % 64 == 0, 2818 + "call_instrs is not aligned on a cacheline"); 2819 + 2820 + /* Stream size is zero, nothing to do => return a NULL fence and let 2821 + * drm_sched signal the parent. 2822 + */ 2823 + if (!job->call_info.size) 2824 + return NULL; 2825 + 2826 + ret = pm_runtime_resume_and_get(ptdev->base.dev); 2827 + if (drm_WARN_ON(&ptdev->base, ret)) 2828 + return ERR_PTR(ret); 2829 + 2830 + mutex_lock(&sched->lock); 2831 + if (!group_can_run(group)) { 2832 + done_fence = ERR_PTR(-ECANCELED); 2833 + goto out_unlock; 2834 + } 2835 + 2836 + dma_fence_init(job->done_fence, 2837 + &panthor_queue_fence_ops, 2838 + &queue->fence_ctx.lock, 2839 + queue->fence_ctx.id, 2840 + atomic64_inc_return(&queue->fence_ctx.seqno)); 2841 + 2842 + memcpy(queue->ringbuf->kmap + ringbuf_insert, 2843 + call_instrs, sizeof(call_instrs)); 2844 + 2845 + panthor_job_get(&job->base); 2846 + spin_lock(&queue->fence_ctx.lock); 2847 + list_add_tail(&job->node, &queue->fence_ctx.in_flight_jobs); 2848 + spin_unlock(&queue->fence_ctx.lock); 2849 + 2850 + job->ringbuf.start = queue->iface.input->insert; 2851 + job->ringbuf.end = job->ringbuf.start + sizeof(call_instrs); 2852 + 2853 + /* Make sure the ring buffer is updated before the INSERT 2854 + * register. 2855 + */ 2856 + wmb(); 2857 + 2858 + queue->iface.input->extract = queue->iface.output->extract; 2859 + queue->iface.input->insert = job->ringbuf.end; 2860 + 2861 + if (group->csg_id < 0) { 2862 + /* If the queue is blocked, we want to keep the timeout running, so we 2863 + * can detect unbounded waits and kill the group when that happens. 2864 + * Otherwise, we suspend the timeout so the time we spend waiting for 2865 + * a CSG slot is not counted. 2866 + */ 2867 + if (!(group->blocked_queues & BIT(job->queue_idx)) && 2868 + !queue->timeout_suspended) { 2869 + queue->remaining_time = drm_sched_suspend_timeout(&queue->scheduler); 2870 + queue->timeout_suspended = true; 2871 + } 2872 + 2873 + group_schedule_locked(group, BIT(job->queue_idx)); 2874 + } else { 2875 + gpu_write(ptdev, CSF_DOORBELL(queue->doorbell_id), 1); 2876 + if (!sched->pm.has_ref && 2877 + !(group->blocked_queues & BIT(job->queue_idx))) { 2878 + pm_runtime_get(ptdev->base.dev); 2879 + sched->pm.has_ref = true; 2880 + } 2881 + } 2882 + 2883 + done_fence = dma_fence_get(job->done_fence); 2884 + 2885 + out_unlock: 2886 + mutex_unlock(&sched->lock); 2887 + pm_runtime_mark_last_busy(ptdev->base.dev); 2888 + pm_runtime_put_autosuspend(ptdev->base.dev); 2889 + 2890 + return done_fence; 2891 + } 2892 + 2893 + static enum drm_gpu_sched_stat 2894 + queue_timedout_job(struct drm_sched_job *sched_job) 2895 + { 2896 + struct panthor_job *job = container_of(sched_job, struct panthor_job, base); 2897 + struct panthor_group *group = job->group; 2898 + struct panthor_device *ptdev = group->ptdev; 2899 + struct panthor_scheduler *sched = ptdev->scheduler; 2900 + struct panthor_queue *queue = group->queues[job->queue_idx]; 2901 + 2902 + drm_warn(&ptdev->base, "job timeout\n"); 2903 + 2904 + drm_WARN_ON(&ptdev->base, atomic_read(&sched->reset.in_progress)); 2905 + 2906 + queue_stop(queue, job); 2907 + 2908 + mutex_lock(&sched->lock); 2909 + group->timedout = true; 2910 + if (group->csg_id >= 0) { 2911 + sched_queue_delayed_work(ptdev->scheduler, tick, 0); 2912 + } else { 2913 + /* Remove from the run queues, so the scheduler can't 2914 + * pick the group on the next tick. 2915 + */ 2916 + list_del_init(&group->run_node); 2917 + list_del_init(&group->wait_node); 2918 + 2919 + group_queue_work(group, term); 2920 + } 2921 + mutex_unlock(&sched->lock); 2922 + 2923 + queue_start(queue); 2924 + 2925 + return DRM_GPU_SCHED_STAT_NOMINAL; 2926 + } 2927 + 2928 + static void queue_free_job(struct drm_sched_job *sched_job) 2929 + { 2930 + drm_sched_job_cleanup(sched_job); 2931 + panthor_job_put(sched_job); 2932 + } 2933 + 2934 + static const struct drm_sched_backend_ops panthor_queue_sched_ops = { 2935 + .run_job = queue_run_job, 2936 + .timedout_job = queue_timedout_job, 2937 + .free_job = queue_free_job, 2938 + }; 2939 + 2940 + static struct panthor_queue * 2941 + group_create_queue(struct panthor_group *group, 2942 + const struct drm_panthor_queue_create *args) 2943 + { 2944 + struct drm_gpu_scheduler *drm_sched; 2945 + struct panthor_queue *queue; 2946 + int ret; 2947 + 2948 + if (args->pad[0] || args->pad[1] || args->pad[2]) 2949 + return ERR_PTR(-EINVAL); 2950 + 2951 + if (args->ringbuf_size < SZ_4K || args->ringbuf_size > SZ_64K || 2952 + !is_power_of_2(args->ringbuf_size)) 2953 + return ERR_PTR(-EINVAL); 2954 + 2955 + if (args->priority > CSF_MAX_QUEUE_PRIO) 2956 + return ERR_PTR(-EINVAL); 2957 + 2958 + queue = kzalloc(sizeof(*queue), GFP_KERNEL); 2959 + if (!queue) 2960 + return ERR_PTR(-ENOMEM); 2961 + 2962 + queue->fence_ctx.id = dma_fence_context_alloc(1); 2963 + spin_lock_init(&queue->fence_ctx.lock); 2964 + INIT_LIST_HEAD(&queue->fence_ctx.in_flight_jobs); 2965 + 2966 + queue->priority = args->priority; 2967 + 2968 + queue->ringbuf = panthor_kernel_bo_create(group->ptdev, group->vm, 2969 + args->ringbuf_size, 2970 + DRM_PANTHOR_BO_NO_MMAP, 2971 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | 2972 + DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED, 2973 + PANTHOR_VM_KERNEL_AUTO_VA); 2974 + if (IS_ERR(queue->ringbuf)) { 2975 + ret = PTR_ERR(queue->ringbuf); 2976 + goto err_free_queue; 2977 + } 2978 + 2979 + ret = panthor_kernel_bo_vmap(queue->ringbuf); 2980 + if (ret) 2981 + goto err_free_queue; 2982 + 2983 + queue->iface.mem = panthor_fw_alloc_queue_iface_mem(group->ptdev, 2984 + &queue->iface.input, 2985 + &queue->iface.output, 2986 + &queue->iface.input_fw_va, 2987 + &queue->iface.output_fw_va); 2988 + if (IS_ERR(queue->iface.mem)) { 2989 + ret = PTR_ERR(queue->iface.mem); 2990 + goto err_free_queue; 2991 + } 2992 + 2993 + ret = drm_sched_init(&queue->scheduler, &panthor_queue_sched_ops, 2994 + group->ptdev->scheduler->wq, 1, 2995 + args->ringbuf_size / (NUM_INSTRS_PER_SLOT * sizeof(u64)), 2996 + 0, msecs_to_jiffies(JOB_TIMEOUT_MS), 2997 + group->ptdev->reset.wq, 2998 + NULL, "panthor-queue", group->ptdev->base.dev); 2999 + if (ret) 3000 + goto err_free_queue; 3001 + 3002 + drm_sched = &queue->scheduler; 3003 + ret = drm_sched_entity_init(&queue->entity, 0, &drm_sched, 1, NULL); 3004 + 3005 + return queue; 3006 + 3007 + err_free_queue: 3008 + group_free_queue(group, queue); 3009 + return ERR_PTR(ret); 3010 + } 3011 + 3012 + #define MAX_GROUPS_PER_POOL 128 3013 + 3014 + int panthor_group_create(struct panthor_file *pfile, 3015 + const struct drm_panthor_group_create *group_args, 3016 + const struct drm_panthor_queue_create *queue_args) 3017 + { 3018 + struct panthor_device *ptdev = pfile->ptdev; 3019 + struct panthor_group_pool *gpool = pfile->groups; 3020 + struct panthor_scheduler *sched = ptdev->scheduler; 3021 + struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, 0); 3022 + struct panthor_group *group = NULL; 3023 + u32 gid, i, suspend_size; 3024 + int ret; 3025 + 3026 + if (group_args->pad) 3027 + return -EINVAL; 3028 + 3029 + if (group_args->priority > PANTHOR_CSG_PRIORITY_HIGH) 3030 + return -EINVAL; 3031 + 3032 + if ((group_args->compute_core_mask & ~ptdev->gpu_info.shader_present) || 3033 + (group_args->fragment_core_mask & ~ptdev->gpu_info.shader_present) || 3034 + (group_args->tiler_core_mask & ~ptdev->gpu_info.tiler_present)) 3035 + return -EINVAL; 3036 + 3037 + if (hweight64(group_args->compute_core_mask) < group_args->max_compute_cores || 3038 + hweight64(group_args->fragment_core_mask) < group_args->max_fragment_cores || 3039 + hweight64(group_args->tiler_core_mask) < group_args->max_tiler_cores) 3040 + return -EINVAL; 3041 + 3042 + group = kzalloc(sizeof(*group), GFP_KERNEL); 3043 + if (!group) 3044 + return -ENOMEM; 3045 + 3046 + spin_lock_init(&group->fatal_lock); 3047 + kref_init(&group->refcount); 3048 + group->state = PANTHOR_CS_GROUP_CREATED; 3049 + group->csg_id = -1; 3050 + 3051 + group->ptdev = ptdev; 3052 + group->max_compute_cores = group_args->max_compute_cores; 3053 + group->compute_core_mask = group_args->compute_core_mask; 3054 + group->max_fragment_cores = group_args->max_fragment_cores; 3055 + group->fragment_core_mask = group_args->fragment_core_mask; 3056 + group->max_tiler_cores = group_args->max_tiler_cores; 3057 + group->tiler_core_mask = group_args->tiler_core_mask; 3058 + group->priority = group_args->priority; 3059 + 3060 + INIT_LIST_HEAD(&group->wait_node); 3061 + INIT_LIST_HEAD(&group->run_node); 3062 + INIT_WORK(&group->term_work, group_term_work); 3063 + INIT_WORK(&group->sync_upd_work, group_sync_upd_work); 3064 + INIT_WORK(&group->tiler_oom_work, group_tiler_oom_work); 3065 + INIT_WORK(&group->release_work, group_release_work); 3066 + 3067 + group->vm = panthor_vm_pool_get_vm(pfile->vms, group_args->vm_id); 3068 + if (!group->vm) { 3069 + ret = -EINVAL; 3070 + goto err_put_group; 3071 + } 3072 + 3073 + suspend_size = csg_iface->control->suspend_size; 3074 + group->suspend_buf = panthor_fw_alloc_suspend_buf_mem(ptdev, suspend_size); 3075 + if (IS_ERR(group->suspend_buf)) { 3076 + ret = PTR_ERR(group->suspend_buf); 3077 + group->suspend_buf = NULL; 3078 + goto err_put_group; 3079 + } 3080 + 3081 + suspend_size = csg_iface->control->protm_suspend_size; 3082 + group->protm_suspend_buf = panthor_fw_alloc_suspend_buf_mem(ptdev, suspend_size); 3083 + if (IS_ERR(group->protm_suspend_buf)) { 3084 + ret = PTR_ERR(group->protm_suspend_buf); 3085 + group->protm_suspend_buf = NULL; 3086 + goto err_put_group; 3087 + } 3088 + 3089 + group->syncobjs = panthor_kernel_bo_create(ptdev, group->vm, 3090 + group_args->queues.count * 3091 + sizeof(struct panthor_syncobj_64b), 3092 + DRM_PANTHOR_BO_NO_MMAP, 3093 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | 3094 + DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED, 3095 + PANTHOR_VM_KERNEL_AUTO_VA); 3096 + if (IS_ERR(group->syncobjs)) { 3097 + ret = PTR_ERR(group->syncobjs); 3098 + goto err_put_group; 3099 + } 3100 + 3101 + ret = panthor_kernel_bo_vmap(group->syncobjs); 3102 + if (ret) 3103 + goto err_put_group; 3104 + 3105 + memset(group->syncobjs->kmap, 0, 3106 + group_args->queues.count * sizeof(struct panthor_syncobj_64b)); 3107 + 3108 + for (i = 0; i < group_args->queues.count; i++) { 3109 + group->queues[i] = group_create_queue(group, &queue_args[i]); 3110 + if (IS_ERR(group->queues[i])) { 3111 + ret = PTR_ERR(group->queues[i]); 3112 + group->queues[i] = NULL; 3113 + goto err_put_group; 3114 + } 3115 + 3116 + group->queue_count++; 3117 + } 3118 + 3119 + group->idle_queues = GENMASK(group->queue_count - 1, 0); 3120 + 3121 + ret = xa_alloc(&gpool->xa, &gid, group, XA_LIMIT(1, MAX_GROUPS_PER_POOL), GFP_KERNEL); 3122 + if (ret) 3123 + goto err_put_group; 3124 + 3125 + mutex_lock(&sched->reset.lock); 3126 + if (atomic_read(&sched->reset.in_progress)) { 3127 + panthor_group_stop(group); 3128 + } else { 3129 + mutex_lock(&sched->lock); 3130 + list_add_tail(&group->run_node, 3131 + &sched->groups.idle[group->priority]); 3132 + mutex_unlock(&sched->lock); 3133 + } 3134 + mutex_unlock(&sched->reset.lock); 3135 + 3136 + return gid; 3137 + 3138 + err_put_group: 3139 + group_put(group); 3140 + return ret; 3141 + } 3142 + 3143 + int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle) 3144 + { 3145 + struct panthor_group_pool *gpool = pfile->groups; 3146 + struct panthor_device *ptdev = pfile->ptdev; 3147 + struct panthor_scheduler *sched = ptdev->scheduler; 3148 + struct panthor_group *group; 3149 + 3150 + group = xa_erase(&gpool->xa, group_handle); 3151 + if (!group) 3152 + return -EINVAL; 3153 + 3154 + for (u32 i = 0; i < group->queue_count; i++) { 3155 + if (group->queues[i]) 3156 + drm_sched_entity_destroy(&group->queues[i]->entity); 3157 + } 3158 + 3159 + mutex_lock(&sched->reset.lock); 3160 + mutex_lock(&sched->lock); 3161 + group->destroyed = true; 3162 + if (group->csg_id >= 0) { 3163 + sched_queue_delayed_work(sched, tick, 0); 3164 + } else if (!atomic_read(&sched->reset.in_progress)) { 3165 + /* Remove from the run queues, so the scheduler can't 3166 + * pick the group on the next tick. 3167 + */ 3168 + list_del_init(&group->run_node); 3169 + list_del_init(&group->wait_node); 3170 + group_queue_work(group, term); 3171 + } 3172 + mutex_unlock(&sched->lock); 3173 + mutex_unlock(&sched->reset.lock); 3174 + 3175 + group_put(group); 3176 + return 0; 3177 + } 3178 + 3179 + int panthor_group_get_state(struct panthor_file *pfile, 3180 + struct drm_panthor_group_get_state *get_state) 3181 + { 3182 + struct panthor_group_pool *gpool = pfile->groups; 3183 + struct panthor_device *ptdev = pfile->ptdev; 3184 + struct panthor_scheduler *sched = ptdev->scheduler; 3185 + struct panthor_group *group; 3186 + 3187 + if (get_state->pad) 3188 + return -EINVAL; 3189 + 3190 + group = group_get(xa_load(&gpool->xa, get_state->group_handle)); 3191 + if (!group) 3192 + return -EINVAL; 3193 + 3194 + memset(get_state, 0, sizeof(*get_state)); 3195 + 3196 + mutex_lock(&sched->lock); 3197 + if (group->timedout) 3198 + get_state->state |= DRM_PANTHOR_GROUP_STATE_TIMEDOUT; 3199 + if (group->fatal_queues) { 3200 + get_state->state |= DRM_PANTHOR_GROUP_STATE_FATAL_FAULT; 3201 + get_state->fatal_queues = group->fatal_queues; 3202 + } 3203 + mutex_unlock(&sched->lock); 3204 + 3205 + group_put(group); 3206 + return 0; 3207 + } 3208 + 3209 + int panthor_group_pool_create(struct panthor_file *pfile) 3210 + { 3211 + struct panthor_group_pool *gpool; 3212 + 3213 + gpool = kzalloc(sizeof(*gpool), GFP_KERNEL); 3214 + if (!gpool) 3215 + return -ENOMEM; 3216 + 3217 + xa_init_flags(&gpool->xa, XA_FLAGS_ALLOC1); 3218 + pfile->groups = gpool; 3219 + return 0; 3220 + } 3221 + 3222 + void panthor_group_pool_destroy(struct panthor_file *pfile) 3223 + { 3224 + struct panthor_group_pool *gpool = pfile->groups; 3225 + struct panthor_group *group; 3226 + unsigned long i; 3227 + 3228 + if (IS_ERR_OR_NULL(gpool)) 3229 + return; 3230 + 3231 + xa_for_each(&gpool->xa, i, group) 3232 + panthor_group_destroy(pfile, i); 3233 + 3234 + xa_destroy(&gpool->xa); 3235 + kfree(gpool); 3236 + pfile->groups = NULL; 3237 + } 3238 + 3239 + static void job_release(struct kref *ref) 3240 + { 3241 + struct panthor_job *job = container_of(ref, struct panthor_job, refcount); 3242 + 3243 + drm_WARN_ON(&job->group->ptdev->base, !list_empty(&job->node)); 3244 + 3245 + if (job->base.s_fence) 3246 + drm_sched_job_cleanup(&job->base); 3247 + 3248 + if (job->done_fence && job->done_fence->ops) 3249 + dma_fence_put(job->done_fence); 3250 + else 3251 + dma_fence_free(job->done_fence); 3252 + 3253 + group_put(job->group); 3254 + 3255 + kfree(job); 3256 + } 3257 + 3258 + struct drm_sched_job *panthor_job_get(struct drm_sched_job *sched_job) 3259 + { 3260 + if (sched_job) { 3261 + struct panthor_job *job = container_of(sched_job, struct panthor_job, base); 3262 + 3263 + kref_get(&job->refcount); 3264 + } 3265 + 3266 + return sched_job; 3267 + } 3268 + 3269 + void panthor_job_put(struct drm_sched_job *sched_job) 3270 + { 3271 + struct panthor_job *job = container_of(sched_job, struct panthor_job, base); 3272 + 3273 + if (sched_job) 3274 + kref_put(&job->refcount, job_release); 3275 + } 3276 + 3277 + struct panthor_vm *panthor_job_vm(struct drm_sched_job *sched_job) 3278 + { 3279 + struct panthor_job *job = container_of(sched_job, struct panthor_job, base); 3280 + 3281 + return job->group->vm; 3282 + } 3283 + 3284 + struct drm_sched_job * 3285 + panthor_job_create(struct panthor_file *pfile, 3286 + u16 group_handle, 3287 + const struct drm_panthor_queue_submit *qsubmit) 3288 + { 3289 + struct panthor_group_pool *gpool = pfile->groups; 3290 + struct panthor_job *job; 3291 + int ret; 3292 + 3293 + if (qsubmit->pad) 3294 + return ERR_PTR(-EINVAL); 3295 + 3296 + /* If stream_addr is zero, so stream_size should be. */ 3297 + if ((qsubmit->stream_size == 0) != (qsubmit->stream_addr == 0)) 3298 + return ERR_PTR(-EINVAL); 3299 + 3300 + /* Make sure the address is aligned on 64-byte (cacheline) and the size is 3301 + * aligned on 8-byte (instruction size). 3302 + */ 3303 + if ((qsubmit->stream_addr & 63) || (qsubmit->stream_size & 7)) 3304 + return ERR_PTR(-EINVAL); 3305 + 3306 + /* bits 24:30 must be zero. */ 3307 + if (qsubmit->latest_flush & GENMASK(30, 24)) 3308 + return ERR_PTR(-EINVAL); 3309 + 3310 + job = kzalloc(sizeof(*job), GFP_KERNEL); 3311 + if (!job) 3312 + return ERR_PTR(-ENOMEM); 3313 + 3314 + kref_init(&job->refcount); 3315 + job->queue_idx = qsubmit->queue_index; 3316 + job->call_info.size = qsubmit->stream_size; 3317 + job->call_info.start = qsubmit->stream_addr; 3318 + job->call_info.latest_flush = qsubmit->latest_flush; 3319 + INIT_LIST_HEAD(&job->node); 3320 + 3321 + job->group = group_get(xa_load(&gpool->xa, group_handle)); 3322 + if (!job->group) { 3323 + ret = -EINVAL; 3324 + goto err_put_job; 3325 + } 3326 + 3327 + if (job->queue_idx >= job->group->queue_count || 3328 + !job->group->queues[job->queue_idx]) { 3329 + ret = -EINVAL; 3330 + goto err_put_job; 3331 + } 3332 + 3333 + job->done_fence = kzalloc(sizeof(*job->done_fence), GFP_KERNEL); 3334 + if (!job->done_fence) { 3335 + ret = -ENOMEM; 3336 + goto err_put_job; 3337 + } 3338 + 3339 + ret = drm_sched_job_init(&job->base, 3340 + &job->group->queues[job->queue_idx]->entity, 3341 + 1, job->group); 3342 + if (ret) 3343 + goto err_put_job; 3344 + 3345 + return &job->base; 3346 + 3347 + err_put_job: 3348 + panthor_job_put(&job->base); 3349 + return ERR_PTR(ret); 3350 + } 3351 + 3352 + void panthor_job_update_resvs(struct drm_exec *exec, struct drm_sched_job *sched_job) 3353 + { 3354 + struct panthor_job *job = container_of(sched_job, struct panthor_job, base); 3355 + 3356 + /* Still not sure why we want USAGE_WRITE for external objects, since I 3357 + * was assuming this would be handled through explicit syncs being imported 3358 + * to external BOs with DMA_BUF_IOCTL_IMPORT_SYNC_FILE, but other drivers 3359 + * seem to pass DMA_RESV_USAGE_WRITE, so there must be a good reason. 3360 + */ 3361 + panthor_vm_update_resvs(job->group->vm, exec, &sched_job->s_fence->finished, 3362 + DMA_RESV_USAGE_BOOKKEEP, DMA_RESV_USAGE_WRITE); 3363 + } 3364 + 3365 + void panthor_sched_unplug(struct panthor_device *ptdev) 3366 + { 3367 + struct panthor_scheduler *sched = ptdev->scheduler; 3368 + 3369 + cancel_delayed_work_sync(&sched->tick_work); 3370 + 3371 + mutex_lock(&sched->lock); 3372 + if (sched->pm.has_ref) { 3373 + pm_runtime_put(ptdev->base.dev); 3374 + sched->pm.has_ref = false; 3375 + } 3376 + mutex_unlock(&sched->lock); 3377 + } 3378 + 3379 + static void panthor_sched_fini(struct drm_device *ddev, void *res) 3380 + { 3381 + struct panthor_scheduler *sched = res; 3382 + int prio; 3383 + 3384 + if (!sched || !sched->csg_slot_count) 3385 + return; 3386 + 3387 + cancel_delayed_work_sync(&sched->tick_work); 3388 + 3389 + if (sched->wq) 3390 + destroy_workqueue(sched->wq); 3391 + 3392 + if (sched->heap_alloc_wq) 3393 + destroy_workqueue(sched->heap_alloc_wq); 3394 + 3395 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; prio >= 0; prio--) { 3396 + drm_WARN_ON(ddev, !list_empty(&sched->groups.runnable[prio])); 3397 + drm_WARN_ON(ddev, !list_empty(&sched->groups.idle[prio])); 3398 + } 3399 + 3400 + drm_WARN_ON(ddev, !list_empty(&sched->groups.waiting)); 3401 + } 3402 + 3403 + int panthor_sched_init(struct panthor_device *ptdev) 3404 + { 3405 + struct panthor_fw_global_iface *glb_iface = panthor_fw_get_glb_iface(ptdev); 3406 + struct panthor_fw_csg_iface *csg_iface = panthor_fw_get_csg_iface(ptdev, 0); 3407 + struct panthor_fw_cs_iface *cs_iface = panthor_fw_get_cs_iface(ptdev, 0, 0); 3408 + struct panthor_scheduler *sched; 3409 + u32 gpu_as_count, num_groups; 3410 + int prio, ret; 3411 + 3412 + sched = drmm_kzalloc(&ptdev->base, sizeof(*sched), GFP_KERNEL); 3413 + if (!sched) 3414 + return -ENOMEM; 3415 + 3416 + /* The highest bit in JOB_INT_* is reserved for globabl IRQs. That 3417 + * leaves 31 bits for CSG IRQs, hence the MAX_CSGS clamp here. 3418 + */ 3419 + num_groups = min_t(u32, MAX_CSGS, glb_iface->control->group_num); 3420 + 3421 + /* The FW-side scheduler might deadlock if two groups with the same 3422 + * priority try to access a set of resources that overlaps, with part 3423 + * of the resources being allocated to one group and the other part to 3424 + * the other group, both groups waiting for the remaining resources to 3425 + * be allocated. To avoid that, it is recommended to assign each CSG a 3426 + * different priority. In theory we could allow several groups to have 3427 + * the same CSG priority if they don't request the same resources, but 3428 + * that makes the scheduling logic more complicated, so let's clamp 3429 + * the number of CSG slots to MAX_CSG_PRIO + 1 for now. 3430 + */ 3431 + num_groups = min_t(u32, MAX_CSG_PRIO + 1, num_groups); 3432 + 3433 + /* We need at least one AS for the MCU and one for the GPU contexts. */ 3434 + gpu_as_count = hweight32(ptdev->gpu_info.as_present & GENMASK(31, 1)); 3435 + if (!gpu_as_count) { 3436 + drm_err(&ptdev->base, "Not enough AS (%d, expected at least 2)", 3437 + gpu_as_count + 1); 3438 + return -EINVAL; 3439 + } 3440 + 3441 + sched->ptdev = ptdev; 3442 + sched->sb_slot_count = CS_FEATURES_SCOREBOARDS(cs_iface->control->features); 3443 + sched->csg_slot_count = num_groups; 3444 + sched->cs_slot_count = csg_iface->control->stream_num; 3445 + sched->as_slot_count = gpu_as_count; 3446 + ptdev->csif_info.csg_slot_count = sched->csg_slot_count; 3447 + ptdev->csif_info.cs_slot_count = sched->cs_slot_count; 3448 + ptdev->csif_info.scoreboard_slot_count = sched->sb_slot_count; 3449 + 3450 + sched->last_tick = 0; 3451 + sched->resched_target = U64_MAX; 3452 + sched->tick_period = msecs_to_jiffies(10); 3453 + INIT_DELAYED_WORK(&sched->tick_work, tick_work); 3454 + INIT_WORK(&sched->sync_upd_work, sync_upd_work); 3455 + INIT_WORK(&sched->fw_events_work, process_fw_events_work); 3456 + 3457 + ret = drmm_mutex_init(&ptdev->base, &sched->lock); 3458 + if (ret) 3459 + return ret; 3460 + 3461 + for (prio = PANTHOR_CSG_PRIORITY_COUNT - 1; prio >= 0; prio--) { 3462 + INIT_LIST_HEAD(&sched->groups.runnable[prio]); 3463 + INIT_LIST_HEAD(&sched->groups.idle[prio]); 3464 + } 3465 + INIT_LIST_HEAD(&sched->groups.waiting); 3466 + 3467 + ret = drmm_mutex_init(&ptdev->base, &sched->reset.lock); 3468 + if (ret) 3469 + return ret; 3470 + 3471 + INIT_LIST_HEAD(&sched->reset.stopped_groups); 3472 + 3473 + /* sched->heap_alloc_wq will be used for heap chunk allocation on 3474 + * tiler OOM events, which means we can't use the same workqueue for 3475 + * the scheduler because works queued by the scheduler are in 3476 + * the dma-signalling path. Allocate a dedicated heap_alloc_wq to 3477 + * work around this limitation. 3478 + * 3479 + * FIXME: Ultimately, what we need is a failable/non-blocking GEM 3480 + * allocation path that we can call when a heap OOM is reported. The 3481 + * FW is smart enough to fall back on other methods if the kernel can't 3482 + * allocate memory, and fail the tiling job if none of these 3483 + * countermeasures worked. 3484 + * 3485 + * Set WQ_MEM_RECLAIM on sched->wq to unblock the situation when the 3486 + * system is running out of memory. 3487 + */ 3488 + sched->heap_alloc_wq = alloc_workqueue("panthor-heap-alloc", WQ_UNBOUND, 0); 3489 + sched->wq = alloc_workqueue("panthor-csf-sched", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); 3490 + if (!sched->wq || !sched->heap_alloc_wq) { 3491 + panthor_sched_fini(&ptdev->base, sched); 3492 + drm_err(&ptdev->base, "Failed to allocate the workqueues"); 3493 + return -ENOMEM; 3494 + } 3495 + 3496 + ret = drmm_add_action_or_reset(&ptdev->base, panthor_sched_fini, sched); 3497 + if (ret) 3498 + return ret; 3499 + 3500 + ptdev->scheduler = sched; 3501 + return 0; 3502 + }
+50
drivers/gpu/drm/panthor/panthor_sched.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 or MIT */ 2 + /* Copyright 2023 Collabora ltd. */ 3 + 4 + #ifndef __PANTHOR_SCHED_H__ 5 + #define __PANTHOR_SCHED_H__ 6 + 7 + struct drm_exec; 8 + struct dma_fence; 9 + struct drm_file; 10 + struct drm_gem_object; 11 + struct drm_sched_job; 12 + struct drm_panthor_group_create; 13 + struct drm_panthor_queue_create; 14 + struct drm_panthor_group_get_state; 15 + struct drm_panthor_queue_submit; 16 + struct panthor_device; 17 + struct panthor_file; 18 + struct panthor_group_pool; 19 + struct panthor_job; 20 + 21 + int panthor_group_create(struct panthor_file *pfile, 22 + const struct drm_panthor_group_create *group_args, 23 + const struct drm_panthor_queue_create *queue_args); 24 + int panthor_group_destroy(struct panthor_file *pfile, u32 group_handle); 25 + int panthor_group_get_state(struct panthor_file *pfile, 26 + struct drm_panthor_group_get_state *get_state); 27 + 28 + struct drm_sched_job * 29 + panthor_job_create(struct panthor_file *pfile, 30 + u16 group_handle, 31 + const struct drm_panthor_queue_submit *qsubmit); 32 + struct drm_sched_job *panthor_job_get(struct drm_sched_job *job); 33 + struct panthor_vm *panthor_job_vm(struct drm_sched_job *sched_job); 34 + void panthor_job_put(struct drm_sched_job *job); 35 + void panthor_job_update_resvs(struct drm_exec *exec, struct drm_sched_job *job); 36 + 37 + int panthor_group_pool_create(struct panthor_file *pfile); 38 + void panthor_group_pool_destroy(struct panthor_file *pfile); 39 + 40 + int panthor_sched_init(struct panthor_device *ptdev); 41 + void panthor_sched_unplug(struct panthor_device *ptdev); 42 + void panthor_sched_pre_reset(struct panthor_device *ptdev); 43 + void panthor_sched_post_reset(struct panthor_device *ptdev); 44 + void panthor_sched_suspend(struct panthor_device *ptdev); 45 + void panthor_sched_resume(struct panthor_device *ptdev); 46 + 47 + void panthor_sched_report_mmu_fault(struct panthor_device *ptdev); 48 + void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events); 49 + 50 + #endif
+11 -15
drivers/gpu/drm/qxl/qxl_object.c
··· 29 29 #include "qxl_drv.h" 30 30 #include "qxl_object.h" 31 31 32 - static int __qxl_bo_pin(struct qxl_bo *bo); 33 - static void __qxl_bo_unpin(struct qxl_bo *bo); 34 - 35 32 static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo) 36 33 { 37 34 struct qxl_bo *bo; ··· 164 167 goto out; 165 168 } 166 169 167 - r = __qxl_bo_pin(bo); 168 - if (r) 169 - return r; 170 - 171 170 r = ttm_bo_vmap(&bo->tbo, &bo->map); 172 171 if (r) { 173 - __qxl_bo_unpin(bo); 172 + qxl_bo_unpin_locked(bo); 174 173 return r; 175 174 } 176 175 bo->map_count = 1; ··· 239 246 return; 240 247 bo->kptr = NULL; 241 248 ttm_bo_vunmap(&bo->tbo, &bo->map); 242 - __qxl_bo_unpin(bo); 243 249 } 244 250 245 251 int qxl_bo_vunmap(struct qxl_bo *bo) ··· 282 290 return bo; 283 291 } 284 292 285 - static int __qxl_bo_pin(struct qxl_bo *bo) 293 + int qxl_bo_pin_locked(struct qxl_bo *bo) 286 294 { 287 295 struct ttm_operation_ctx ctx = { false, false }; 288 296 struct drm_device *ddev = bo->tbo.base.dev; 289 297 int r; 298 + 299 + dma_resv_assert_held(bo->tbo.base.resv); 290 300 291 301 if (bo->tbo.pin_count) { 292 302 ttm_bo_pin(&bo->tbo); ··· 303 309 return r; 304 310 } 305 311 306 - static void __qxl_bo_unpin(struct qxl_bo *bo) 312 + void qxl_bo_unpin_locked(struct qxl_bo *bo) 307 313 { 314 + dma_resv_assert_held(bo->tbo.base.resv); 315 + 308 316 ttm_bo_unpin(&bo->tbo); 309 317 } 310 318 311 319 /* 312 320 * Reserve the BO before pinning the object. If the BO was reserved 313 - * beforehand, use the internal version directly __qxl_bo_pin. 321 + * beforehand, use the internal version directly qxl_bo_pin_locked. 314 322 * 315 323 */ 316 324 int qxl_bo_pin(struct qxl_bo *bo) ··· 323 327 if (r) 324 328 return r; 325 329 326 - r = __qxl_bo_pin(bo); 330 + r = qxl_bo_pin_locked(bo); 327 331 qxl_bo_unreserve(bo); 328 332 return r; 329 333 } 330 334 331 335 /* 332 336 * Reserve the BO before pinning the object. If the BO was reserved 333 - * beforehand, use the internal version directly __qxl_bo_unpin. 337 + * beforehand, use the internal version directly qxl_bo_unpin_locked. 334 338 * 335 339 */ 336 340 int qxl_bo_unpin(struct qxl_bo *bo) ··· 341 345 if (r) 342 346 return r; 343 347 344 - __qxl_bo_unpin(bo); 348 + qxl_bo_unpin_locked(bo); 345 349 qxl_bo_unreserve(bo); 346 350 return 0; 347 351 }
+2
drivers/gpu/drm/qxl/qxl_object.h
··· 67 67 void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev, struct qxl_bo *bo, void *map); 68 68 extern struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo); 69 69 extern void qxl_bo_unref(struct qxl_bo **bo); 70 + extern int qxl_bo_pin_locked(struct qxl_bo *bo); 71 + extern void qxl_bo_unpin_locked(struct qxl_bo *bo); 70 72 extern int qxl_bo_pin(struct qxl_bo *bo); 71 73 extern int qxl_bo_unpin(struct qxl_bo *bo); 72 74 extern void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain);
+2 -2
drivers/gpu/drm/qxl/qxl_prime.c
··· 32 32 { 33 33 struct qxl_bo *bo = gem_to_qxl_bo(obj); 34 34 35 - return qxl_bo_pin(bo); 35 + return qxl_bo_pin_locked(bo); 36 36 } 37 37 38 38 void qxl_gem_prime_unpin(struct drm_gem_object *obj) 39 39 { 40 40 struct qxl_bo *bo = gem_to_qxl_bo(obj); 41 41 42 - qxl_bo_unpin(bo); 42 + qxl_bo_unpin_locked(bo); 43 43 } 44 44 45 45 struct sg_table *qxl_gem_prime_get_sg_table(struct drm_gem_object *obj)
+5 -3
drivers/gpu/drm/radeon/Kconfig
··· 2 2 3 3 config DRM_RADEON 4 4 tristate "ATI Radeon" 5 - depends on DRM && PCI && MMU 6 5 depends on AGP || !AGP 6 + depends on DRM 7 + depends on DRM_DISPLAY_DP_HELPER 8 + depends on DRM_DISPLAY_HELPER 9 + depends on PCI 10 + depends on MMU 7 11 select FW_LOADER 8 - select DRM_DISPLAY_DP_HELPER 9 - select DRM_DISPLAY_HELPER 10 12 select DRM_KMS_HELPER 11 13 select DRM_SUBALLOC_HELPER 12 14 select DRM_TTM
-11
drivers/gpu/drm/radeon/radeon_prime.c
··· 73 73 struct radeon_bo *bo = gem_to_radeon_bo(obj); 74 74 int ret = 0; 75 75 76 - ret = radeon_bo_reserve(bo, false); 77 - if (unlikely(ret != 0)) 78 - return ret; 79 - 80 76 /* pin buffer into GTT */ 81 77 ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL); 82 78 if (likely(ret == 0)) 83 79 bo->prime_shared_count++; 84 80 85 - radeon_bo_unreserve(bo); 86 81 return ret; 87 82 } 88 83 89 84 void radeon_gem_prime_unpin(struct drm_gem_object *obj) 90 85 { 91 86 struct radeon_bo *bo = gem_to_radeon_bo(obj); 92 - int ret = 0; 93 - 94 - ret = radeon_bo_reserve(bo, false); 95 - if (unlikely(ret != 0)) 96 - return; 97 87 98 88 radeon_bo_unpin(bo); 99 89 if (bo->prime_shared_count) 100 90 bo->prime_shared_count--; 101 - radeon_bo_unreserve(bo); 102 91 } 103 92 104 93
+1 -1
drivers/gpu/drm/renesas/rcar-du/Kconfig
··· 25 25 config DRM_RCAR_DW_HDMI 26 26 tristate "R-Car Gen3 and RZ/G2 DU HDMI Encoder Support" 27 27 depends on DRM && OF 28 + depends on DRM_DW_HDMI 28 29 depends on DRM_RCAR_DU || COMPILE_TEST 29 - select DRM_DW_HDMI 30 30 help 31 31 Enable support for R-Car Gen3 or RZ/G2 internal HDMI encoder. 32 32
-3
drivers/gpu/drm/renesas/rz-du/rzg2l_du_vsp.c
··· 66 66 void rzg2l_du_vsp_atomic_flush(struct rzg2l_du_crtc *crtc) 67 67 { 68 68 struct vsp1_du_atomic_pipe_config cfg = { { 0, } }; 69 - struct rzg2l_du_crtc_state *state; 70 - 71 - state = to_rzg2l_crtc_state(crtc->crtc.state); 72 69 73 70 vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg); 74 71 }
+5 -5
drivers/gpu/drm/rockchip/Kconfig
··· 7 7 select DRM_PANEL 8 8 select VIDEOMODE_HELPERS 9 9 select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP 10 - select DRM_DW_HDMI if ROCKCHIP_DW_HDMI 11 10 select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI 12 11 select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI 13 12 select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI ··· 35 36 36 37 config ROCKCHIP_ANALOGIX_DP 37 38 bool "Rockchip specific extensions for Analogix DP driver" 39 + depends on DRM_DISPLAY_DP_HELPER 40 + depends on DRM_DISPLAY_HELPER 38 41 depends on ROCKCHIP_VOP 39 - select DRM_DISPLAY_HELPER 40 - select DRM_DISPLAY_DP_HELPER 41 42 help 42 43 This selects support for Rockchip SoC specific extensions 43 44 for the Analogix Core DP driver. If you want to enable DP ··· 45 46 46 47 config ROCKCHIP_CDN_DP 47 48 bool "Rockchip cdn DP" 49 + depends on DRM_DISPLAY_DP_HELPER 50 + depends on DRM_DISPLAY_HELPER 48 51 depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m) 49 - select DRM_DISPLAY_HELPER 50 - select DRM_DISPLAY_DP_HELPER 51 52 help 52 53 This selects support for Rockchip SoC specific extensions 53 54 for the cdn DP driver. If you want to enable Dp on ··· 56 57 57 58 config ROCKCHIP_DW_HDMI 58 59 bool "Rockchip specific extensions for Synopsys DW HDMI" 60 + depends on DRM_DW_HDMI 59 61 help 60 62 This selects support for Rockchip SoC specific extensions 61 63 for the Synopsys DesignWare HDMI driver. If you want to
+1 -1
drivers/gpu/drm/sun4i/Kconfig
··· 57 57 config DRM_SUN8I_DW_HDMI 58 58 tristate "Support for Allwinner version of DesignWare HDMI" 59 59 depends on DRM_SUN4I 60 + depends on DRM_DW_HDMI 60 61 default DRM_SUN4I 61 - select DRM_DW_HDMI 62 62 help 63 63 Choose this option if you have an Allwinner SoC with the 64 64 DesignWare HDMI controller. SoCs that support HDMI and
+4 -4
drivers/gpu/drm/tegra/Kconfig
··· 4 4 depends on ARCH_TEGRA || COMPILE_TEST 5 5 depends on COMMON_CLK 6 6 depends on DRM 7 + depends on DRM_DISPLAY_DP_AUX_BUS 8 + depends on DRM_DISPLAY_DP_HELPER 9 + depends on DRM_DISPLAY_HDMI_HELPER 10 + depends on DRM_DISPLAY_HELPER 7 11 depends on OF 8 - select DRM_DISPLAY_DP_HELPER 9 - select DRM_DISPLAY_HDMI_HELPER 10 - select DRM_DISPLAY_HELPER 11 - select DRM_DP_AUX_BUS 12 12 select DRM_KMS_HELPER 13 13 select DRM_MIPI_DSI 14 14 select DRM_PANEL
+1 -2
drivers/gpu/drm/tidss/tidss_kms.c
··· 135 135 dev_dbg(dev, "no panel/bridge for port %d\n", i); 136 136 continue; 137 137 } else if (ret) { 138 - dev_dbg(dev, "port %d probe returned %d\n", i, ret); 139 - return ret; 138 + return dev_err_probe(dev, ret, "port %d probe failed\n", i); 140 139 } 141 140 142 141 if (panel) {
+109 -126
drivers/gpu/drm/ttm/ttm_bo.c
··· 724 724 return ret; 725 725 } 726 726 727 - /* 728 - * Repeatedly evict memory from the LRU for @mem_type until we create enough 729 - * space, or we've evicted everything and there isn't enough space. 730 - */ 731 - static int ttm_bo_mem_force_space(struct ttm_buffer_object *bo, 732 - const struct ttm_place *place, 733 - struct ttm_resource **mem, 734 - struct ttm_operation_ctx *ctx) 735 - { 736 - struct ttm_device *bdev = bo->bdev; 737 - struct ttm_resource_manager *man; 738 - struct ww_acquire_ctx *ticket; 739 - int ret; 740 - 741 - man = ttm_manager_type(bdev, place->mem_type); 742 - ticket = dma_resv_locking_ctx(bo->base.resv); 743 - do { 744 - ret = ttm_resource_alloc(bo, place, mem); 745 - if (likely(!ret)) 746 - break; 747 - if (unlikely(ret != -ENOSPC)) 748 - return ret; 749 - ret = ttm_mem_evict_first(bdev, man, place, ctx, 750 - ticket); 751 - if (unlikely(ret != 0)) 752 - return ret; 753 - } while (1); 754 - 755 - return ttm_bo_add_move_fence(bo, man, *mem, ctx->no_wait_gpu); 756 - } 757 - 758 727 /** 759 - * ttm_bo_mem_space 728 + * ttm_bo_alloc_resource - Allocate backing store for a BO 760 729 * 761 - * @bo: Pointer to a struct ttm_buffer_object. the data of which 762 - * we want to allocate space for. 763 - * @placement: Proposed new placement for the buffer object. 764 - * @mem: A struct ttm_resource. 730 + * @bo: Pointer to a struct ttm_buffer_object of which we want a resource for 731 + * @placement: Proposed new placement for the buffer object 765 732 * @ctx: if and how to sleep, lock buffers and alloc memory 733 + * @force_space: If we should evict buffers to force space 734 + * @res: The resulting struct ttm_resource. 766 735 * 767 - * Allocate memory space for the buffer object pointed to by @bo, using 768 - * the placement flags in @placement, potentially evicting other idle buffer objects. 769 - * This function may sleep while waiting for space to become available. 736 + * Allocates a resource for the buffer object pointed to by @bo, using the 737 + * placement flags in @placement, potentially evicting other buffer objects when 738 + * @force_space is true. 739 + * This function may sleep while waiting for resources to become available. 770 740 * Returns: 771 - * -EBUSY: No space available (only if no_wait == 1). 741 + * -EBUSY: No space available (only if no_wait == true). 772 742 * -ENOSPC: Could not allocate space for the buffer object, either due to 773 743 * fragmentation or concurrent allocators. 774 744 * -ERESTARTSYS: An interruptible sleep was interrupted by a signal. 775 745 */ 776 - int ttm_bo_mem_space(struct ttm_buffer_object *bo, 777 - struct ttm_placement *placement, 778 - struct ttm_resource **mem, 779 - struct ttm_operation_ctx *ctx) 746 + static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo, 747 + struct ttm_placement *placement, 748 + struct ttm_operation_ctx *ctx, 749 + bool force_space, 750 + struct ttm_resource **res) 780 751 { 781 752 struct ttm_device *bdev = bo->bdev; 782 - bool type_found = false; 753 + struct ww_acquire_ctx *ticket; 783 754 int i, ret; 784 755 756 + ticket = dma_resv_locking_ctx(bo->base.resv); 785 757 ret = dma_resv_reserve_fences(bo->base.resv, 1); 786 758 if (unlikely(ret)) 787 759 return ret; ··· 762 790 const struct ttm_place *place = &placement->placement[i]; 763 791 struct ttm_resource_manager *man; 764 792 765 - if (place->flags & TTM_PL_FLAG_FALLBACK) 766 - continue; 767 - 768 793 man = ttm_manager_type(bdev, place->mem_type); 769 794 if (!man || !ttm_resource_manager_used(man)) 770 795 continue; 771 796 772 - type_found = true; 773 - ret = ttm_resource_alloc(bo, place, mem); 774 - if (ret == -ENOSPC) 797 + if (place->flags & (force_space ? TTM_PL_FLAG_DESIRED : 798 + TTM_PL_FLAG_FALLBACK)) 775 799 continue; 776 - if (unlikely(ret)) 777 - goto error; 778 800 779 - ret = ttm_bo_add_move_fence(bo, man, *mem, ctx->no_wait_gpu); 801 + do { 802 + ret = ttm_resource_alloc(bo, place, res); 803 + if (unlikely(ret && ret != -ENOSPC)) 804 + return ret; 805 + if (likely(!ret) || !force_space) 806 + break; 807 + 808 + ret = ttm_mem_evict_first(bdev, man, place, ctx, 809 + ticket); 810 + if (unlikely(ret == -EBUSY)) 811 + break; 812 + if (unlikely(ret)) 813 + return ret; 814 + } while (1); 815 + if (ret) 816 + continue; 817 + 818 + ret = ttm_bo_add_move_fence(bo, man, *res, ctx->no_wait_gpu); 780 819 if (unlikely(ret)) { 781 - ttm_resource_free(bo, mem); 820 + ttm_resource_free(bo, res); 782 821 if (ret == -EBUSY) 783 822 continue; 784 823 785 - goto error; 824 + return ret; 786 825 } 787 826 return 0; 788 827 } 789 828 790 - for (i = 0; i < placement->num_placement; ++i) { 791 - const struct ttm_place *place = &placement->placement[i]; 792 - struct ttm_resource_manager *man; 829 + return -ENOSPC; 830 + } 793 831 794 - if (place->flags & TTM_PL_FLAG_DESIRED) 795 - continue; 832 + /* 833 + * ttm_bo_mem_space - Wrapper around ttm_bo_alloc_resource 834 + * 835 + * @bo: Pointer to a struct ttm_buffer_object of which we want a resource for 836 + * @placement: Proposed new placement for the buffer object 837 + * @res: The resulting struct ttm_resource. 838 + * @ctx: if and how to sleep, lock buffers and alloc memory 839 + * 840 + * Tries both idle allocation and forcefully eviction of buffers. See 841 + * ttm_bo_alloc_resource for details. 842 + */ 843 + int ttm_bo_mem_space(struct ttm_buffer_object *bo, 844 + struct ttm_placement *placement, 845 + struct ttm_resource **res, 846 + struct ttm_operation_ctx *ctx) 847 + { 848 + bool force_space = false; 849 + int ret; 796 850 797 - man = ttm_manager_type(bdev, place->mem_type); 798 - if (!man || !ttm_resource_manager_used(man)) 799 - continue; 851 + do { 852 + ret = ttm_bo_alloc_resource(bo, placement, ctx, 853 + force_space, res); 854 + force_space = !force_space; 855 + } while (ret == -ENOSPC && force_space); 800 856 801 - type_found = true; 802 - ret = ttm_bo_mem_force_space(bo, place, mem, ctx); 803 - if (likely(!ret)) 804 - return 0; 805 - 806 - if (ret && ret != -EBUSY) 807 - goto error; 808 - } 809 - 810 - ret = -ENOSPC; 811 - if (!type_found) { 812 - pr_err(TTM_PFX "No compatible memory type found\n"); 813 - ret = -EINVAL; 814 - } 815 - 816 - error: 817 857 return ret; 818 858 } 819 859 EXPORT_SYMBOL(ttm_bo_mem_space); 820 - 821 - static int ttm_bo_move_buffer(struct ttm_buffer_object *bo, 822 - struct ttm_placement *placement, 823 - struct ttm_operation_ctx *ctx) 824 - { 825 - struct ttm_resource *mem; 826 - struct ttm_place hop; 827 - int ret; 828 - 829 - dma_resv_assert_held(bo->base.resv); 830 - 831 - /* 832 - * Determine where to move the buffer. 833 - * 834 - * If driver determines move is going to need 835 - * an extra step then it will return -EMULTIHOP 836 - * and the buffer will be moved to the temporary 837 - * stop and the driver will be called to make 838 - * the second hop. 839 - */ 840 - ret = ttm_bo_mem_space(bo, placement, &mem, ctx); 841 - if (ret) 842 - return ret; 843 - bounce: 844 - ret = ttm_bo_handle_move_mem(bo, mem, false, ctx, &hop); 845 - if (ret == -EMULTIHOP) { 846 - ret = ttm_bo_bounce_temp_buffer(bo, &mem, ctx, &hop); 847 - if (ret) 848 - goto out; 849 - /* try and move to final place now. */ 850 - goto bounce; 851 - } 852 - out: 853 - if (ret) 854 - ttm_resource_free(bo, &mem); 855 - return ret; 856 - } 857 860 858 861 /** 859 862 * ttm_bo_validate ··· 849 902 struct ttm_placement *placement, 850 903 struct ttm_operation_ctx *ctx) 851 904 { 905 + struct ttm_resource *res; 906 + struct ttm_place hop; 907 + bool force_space; 852 908 int ret; 853 909 854 910 dma_resv_assert_held(bo->base.resv); ··· 862 912 if (!placement->num_placement) 863 913 return ttm_bo_pipeline_gutting(bo); 864 914 865 - /* Check whether we need to move buffer. */ 866 - if (bo->resource && ttm_resource_compatible(bo->resource, placement)) 867 - return 0; 915 + force_space = false; 916 + do { 917 + /* Check whether we need to move buffer. */ 918 + if (bo->resource && 919 + ttm_resource_compatible(bo->resource, placement, 920 + force_space)) 921 + return 0; 868 922 869 - /* Moving of pinned BOs is forbidden */ 870 - if (bo->pin_count) 871 - return -EINVAL; 923 + /* Moving of pinned BOs is forbidden */ 924 + if (bo->pin_count) 925 + return -EINVAL; 872 926 873 - ret = ttm_bo_move_buffer(bo, placement, ctx); 927 + /* 928 + * Determine where to move the buffer. 929 + * 930 + * If driver determines move is going to need 931 + * an extra step then it will return -EMULTIHOP 932 + * and the buffer will be moved to the temporary 933 + * stop and the driver will be called to make 934 + * the second hop. 935 + */ 936 + ret = ttm_bo_alloc_resource(bo, placement, ctx, force_space, 937 + &res); 938 + force_space = !force_space; 939 + if (ret == -ENOSPC) 940 + continue; 941 + if (ret) 942 + return ret; 943 + 944 + bounce: 945 + ret = ttm_bo_handle_move_mem(bo, res, false, ctx, &hop); 946 + if (ret == -EMULTIHOP) { 947 + ret = ttm_bo_bounce_temp_buffer(bo, &res, ctx, &hop); 948 + /* try and move to final place now. */ 949 + if (!ret) 950 + goto bounce; 951 + } 952 + if (ret) { 953 + ttm_resource_free(bo, &res); 954 + return ret; 955 + } 956 + 957 + } while (ret && force_space); 958 + 874 959 /* For backward compatibility with userspace */ 875 960 if (ret == -ENOSPC) 876 961 return -ENOMEM; 877 - if (ret) 878 - return ret; 879 962 880 963 /* 881 964 * We might need to add a TTM.
+13 -4
drivers/gpu/drm/ttm/ttm_resource.c
··· 105 105 pos->first = res; 106 106 pos->last = res; 107 107 } else { 108 + WARN_ON(pos->first->bo->base.resv != res->bo->base.resv); 108 109 ttm_lru_bulk_move_pos_tail(pos, res); 109 110 } 110 111 } ··· 296 295 * 297 296 * @res: the resource to check 298 297 * @placement: the placement to check against 298 + * @evicting: true if the caller is doing evictions 299 299 * 300 300 * Returns true if the placement is compatible. 301 301 */ 302 302 bool ttm_resource_compatible(struct ttm_resource *res, 303 - struct ttm_placement *placement) 303 + struct ttm_placement *placement, 304 + bool evicting) 304 305 { 305 306 struct ttm_buffer_object *bo = res->bo; 306 307 struct ttm_device *bdev = bo->bdev; ··· 318 315 if (res->mem_type != place->mem_type) 319 316 continue; 320 317 318 + if (place->flags & (evicting ? TTM_PL_FLAG_DESIRED : 319 + TTM_PL_FLAG_FALLBACK)) 320 + continue; 321 + 322 + if (place->flags & TTM_PL_FLAG_CONTIGUOUS && 323 + !(res->placement & TTM_PL_FLAG_CONTIGUOUS)) 324 + continue; 325 + 321 326 man = ttm_manager_type(bdev, res->mem_type); 322 327 if (man->func->compatible && 323 328 !man->func->compatible(man, res, place, bo->base.size)) 324 329 continue; 325 330 326 - if ((!(place->flags & TTM_PL_FLAG_CONTIGUOUS) || 327 - (res->placement & TTM_PL_FLAG_CONTIGUOUS))) 328 - return true; 331 + return true; 329 332 } 330 333 return false; 331 334 }
+5 -5
drivers/gpu/drm/vc4/Kconfig
··· 2 2 config DRM_VC4 3 3 tristate "Broadcom VC4 Graphics" 4 4 depends on ARCH_BCM || ARCH_BCM2835 || COMPILE_TEST 5 + depends on COMMON_CLK 6 + depends on DRM 7 + depends on DRM_DISPLAY_HDMI_HELPER 8 + depends on DRM_DISPLAY_HELPER 9 + depends on PM 5 10 # Make sure not 'y' when RASPBERRYPI_FIRMWARE is 'm'. This can only 6 11 # happen when COMPILE_TEST=y, hence the added !RASPBERRYPI_FIRMWARE. 7 12 depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) 8 - depends on DRM 9 13 depends on SND && SND_SOC 10 - depends on COMMON_CLK 11 - depends on PM 12 - select DRM_DISPLAY_HDMI_HELPER 13 - select DRM_DISPLAY_HELPER 14 14 select DRM_KMS_HELPER 15 15 select DRM_GEM_DMA_HELPER 16 16 select DRM_PANEL_BRIDGE
+8 -21
drivers/gpu/drm/vmwgfx/vmwgfx_gem.c
··· 48 48 { 49 49 } 50 50 51 - static int vmw_gem_pin_private(struct drm_gem_object *obj, bool do_pin) 52 - { 53 - struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(obj); 54 - struct vmw_bo *vbo = to_vmw_bo(obj); 55 - int ret; 56 - 57 - ret = ttm_bo_reserve(bo, false, false, NULL); 58 - if (unlikely(ret != 0)) 59 - goto err; 60 - 61 - vmw_bo_pin_reserved(vbo, do_pin); 62 - 63 - ttm_bo_unreserve(bo); 64 - 65 - err: 66 - return ret; 67 - } 68 - 69 - 70 51 static int vmw_gem_object_pin(struct drm_gem_object *obj) 71 52 { 72 - return vmw_gem_pin_private(obj, true); 53 + struct vmw_bo *vbo = to_vmw_bo(obj); 54 + 55 + vmw_bo_pin_reserved(vbo, true); 56 + 57 + return 0; 73 58 } 74 59 75 60 static void vmw_gem_object_unpin(struct drm_gem_object *obj) 76 61 { 77 - vmw_gem_pin_private(obj, false); 62 + struct vmw_bo *vbo = to_vmw_bo(obj); 63 + 64 + vmw_bo_pin_reserved(vbo, false); 78 65 } 79 66 80 67 static struct sg_table *vmw_gem_object_get_sg_table(struct drm_gem_object *obj)
+8 -5
drivers/gpu/drm/xe/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config DRM_XE 3 3 tristate "Intel Xe Graphics" 4 - depends on DRM && PCI && MMU && (m || (y && KUNIT=y)) 4 + depends on (m || (y && KUNIT=y)) 5 + depends on DRM 6 + depends on DRM_DISPLAY_DP_HELPER 7 + depends on DRM_DISPLAY_HDCP_HELPER 8 + depends on DRM_DISPLAY_HDMI_HELPER 9 + depends on DRM_DISPLAY_HELPER 10 + depends on MMU 11 + depends on PCI 5 12 select INTERVAL_TREE 6 13 # we need shmfs for the swappable backing store, and in particular 7 14 # the shmem_readpage() which depends upon tmpfs ··· 20 13 select DRM_KUNIT_TEST_HELPERS if DRM_XE_KUNIT_TEST != n 21 14 select DRM_PANEL 22 15 select DRM_SUBALLOC_HELPER 23 - select DRM_DISPLAY_DP_HELPER 24 - select DRM_DISPLAY_HDCP_HELPER 25 - select DRM_DISPLAY_HDMI_HELPER 26 - select DRM_DISPLAY_HELPER 27 16 select DRM_MIPI_DSI 28 17 select RELAY 29 18 select IRQ_WORK
+5 -3
drivers/gpu/drm/xlnx/Kconfig
··· 1 1 config DRM_ZYNQMP_DPSUB 2 2 tristate "ZynqMP DisplayPort Controller Driver" 3 3 depends on ARCH_ZYNQMP || COMPILE_TEST 4 - depends on COMMON_CLK && DRM && OF 4 + depends on COMMON_CLK 5 5 depends on DMADEVICES 6 + depends on DRM 7 + depends on DRM_DISPLAY_DP_HELPER 8 + depends on DRM_DISPLAY_HELPER 9 + depends on OF 6 10 depends on PHY_XILINX_ZYNQMP 7 11 depends on XILINX_ZYNQMP_DPDMA 8 12 select DMA_ENGINE 9 - select DRM_DISPLAY_DP_HELPER 10 - select DRM_DISPLAY_HELPER 11 13 select DRM_GEM_DMA_HELPER 12 14 select DRM_KMS_HELPER 13 15 select GENERIC_PHY
+4
drivers/gpu/drm/xlnx/zynqmp_dp.c
··· 1714 1714 goto err_free; 1715 1715 } 1716 1716 1717 + ret = zynqmp_dp_reset(dp, true); 1718 + if (ret < 0) 1719 + return ret; 1720 + 1717 1721 ret = zynqmp_dp_reset(dp, false); 1718 1722 if (ret < 0) 1719 1723 goto err_free;
+6
drivers/video/fbdev/core/Kconfig
··· 144 144 select FB_SYS_IMAGEBLIT 145 145 select FB_SYSMEM_FOPS 146 146 147 + config FB_DMAMEM_HELPERS_DEFERRED 148 + bool 149 + depends on FB_CORE 150 + select FB_DEFERRED_IO 151 + select FB_DMAMEM_HELPERS 152 + 147 153 config FB_IOMEM_FOPS 148 154 tristate 149 155 depends on FB_CORE
+3
include/drm/amd_asic_type.h
··· 22 22 23 23 #ifndef __AMD_ASIC_TYPE_H__ 24 24 #define __AMD_ASIC_TYPE_H__ 25 + 26 + #include <linux/types.h> 27 + 25 28 /* 26 29 * Supported ASIC types 27 30 */
+3 -1
include/drm/bridge/samsung-dsim.h
··· 11 11 #include <linux/regulator/consumer.h> 12 12 13 13 #include <drm/drm_atomic_helper.h> 14 - #include <drm/drm_of.h> 14 + #include <drm/drm_bridge.h> 15 15 #include <drm/drm_mipi_dsi.h> 16 + #include <drm/drm_of.h> 16 17 18 + struct platform_device; 17 19 struct samsung_dsim; 18 20 19 21 #define DSIM_STATE_ENABLED BIT(0)
+13 -2
include/drm/display/drm_dp_helper.h
··· 422 422 * @wait_hpd_asserted: wait for HPD to be asserted 423 423 * 424 424 * This is mainly useful for eDP panels drivers to wait for an eDP 425 - * panel to finish powering on. This is an optional function. 425 + * panel to finish powering on. It is optional for DP AUX controllers 426 + * to implement this function. It is required for DP AUX endpoints 427 + * (panel drivers) to call this function after powering up but before 428 + * doing AUX transfers unless the DP AUX endpoint driver knows that 429 + * we're not using the AUX controller's HPD. One example of the panel 430 + * driver not needing to call this is if HPD is hooked up to a GPIO 431 + * that the panel driver can read directly. 432 + * 433 + * If a DP AUX controller does not implement this function then it 434 + * may still support eDP panels that use the AUX controller's built-in 435 + * HPD signal by implementing a long wait for HPD in the transfer() 436 + * callback, though this is deprecated. 426 437 * 427 438 * This function will efficiently wait for the HPD signal to be 428 439 * asserted. The `wait_us` parameter that is passed in says that we ··· 733 722 734 723 #endif 735 724 736 - #ifdef CONFIG_DRM_DP_CEC 725 + #ifdef CONFIG_DRM_DISPLAY_DP_AUX_CEC 737 726 void drm_dp_cec_irq(struct drm_dp_aux *aux); 738 727 void drm_dp_cec_register_connector(struct drm_dp_aux *aux, 739 728 struct drm_connector *connector);
-1
include/drm/display/drm_dp_mst_helper.h
··· 83 83 * @passthrough_aux: parent aux to which DSC pass-through requests should be 84 84 * sent, only set if DSC pass-through is possible. 85 85 * @parent: branch device parent of this port 86 - * @vcpi: Virtual Channel Payload info for this port. 87 86 * @connector: DRM connector this port is connected to. Protected by 88 87 * &drm_dp_mst_topology_mgr.base.lock. 89 88 * @mgr: topology manager this port lives under.
+10
include/drm/drm_client.h
··· 141 141 142 142 /** 143 143 * @gem: GEM object backing this buffer 144 + * 145 + * FIXME: The dependency on GEM here isn't required, we could 146 + * convert the driver handle to a dma-buf instead and use the 147 + * backend-agnostic dma-buf vmap support instead. This would 148 + * require that the handle2fd prime ioctl is reworked to pull the 149 + * fd_install step out of the driver backend hooks, to make that 150 + * final step optional for internal users. 144 151 */ 145 152 struct drm_gem_object *gem; 146 153 ··· 166 159 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); 167 160 void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); 168 161 int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect); 162 + int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer, 163 + struct iosys_map *map_copy); 164 + void drm_client_buffer_vunmap_local(struct drm_client_buffer *buffer); 169 165 int drm_client_buffer_vmap(struct drm_client_buffer *buffer, 170 166 struct iosys_map *map); 171 167 void drm_client_buffer_vunmap(struct drm_client_buffer *buffer);
+7 -1
include/drm/drm_debugfs_crc.h
··· 22 22 #ifndef __DRM_DEBUGFS_CRC_H__ 23 23 #define __DRM_DEBUGFS_CRC_H__ 24 24 25 + #include <linux/spinlock_types.h> 26 + #include <linux/types.h> 27 + #include <linux/wait.h> 28 + 29 + struct drm_crtc; 30 + 25 31 #define DRM_MAX_CRC_NR 10 26 32 27 33 /** 28 34 * struct drm_crtc_crc_entry - entry describing a frame's content 29 35 * @has_frame_counter: whether the source was able to provide a frame number 30 36 * @frame: number of the frame this CRC is about, if @has_frame_counter is true 31 - * @crc: array of values that characterize the frame 37 + * @crcs: array of values that characterize the frame 32 38 */ 33 39 struct drm_crtc_crc_entry { 34 40 bool has_frame_counter;
+11 -1
include/drm/drm_edid.h
··· 312 312 u8 checksum; 313 313 } __packed; 314 314 315 + /* EDID matching */ 316 + struct drm_edid_ident { 317 + /* ID encoded by drm_edid_encode_panel_id() */ 318 + u32 panel_id; 319 + const char *name; 320 + }; 321 + 315 322 #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) 316 323 317 324 /* Short Audio Descriptor */ ··· 417 410 void *data); 418 411 struct edid *drm_get_edid(struct drm_connector *connector, 419 412 struct i2c_adapter *adapter); 420 - u32 drm_edid_get_panel_id(struct i2c_adapter *adapter); 413 + const struct drm_edid *drm_edid_read_base_block(struct i2c_adapter *adapter); 414 + u32 drm_edid_get_panel_id(const struct drm_edid *drm_edid); 415 + bool drm_edid_match(const struct drm_edid *drm_edid, 416 + const struct drm_edid_ident *ident); 421 417 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector, 422 418 struct i2c_adapter *adapter); 423 419 struct edid *drm_edid_duplicate(const struct edid *edid);
+74 -17
include/drm/drm_encoder_slave.h
··· 34 34 35 35 /** 36 36 * struct drm_encoder_slave_funcs - Entry points exposed by a slave encoder driver 37 - * @set_config: Initialize any encoder-specific modesetting parameters. 38 - * The meaning of the @params parameter is implementation 39 - * dependent. It will usually be a structure with DVO port 40 - * data format settings or timings. It's not required for 41 - * the new parameters to take effect until the next mode 42 - * is set. 43 37 * 44 38 * Most of its members are analogous to the function pointers in 45 39 * &drm_encoder_helper_funcs and they can optionally be used to ··· 42 48 * if the encoder is the currently selected one for the connector. 43 49 */ 44 50 struct drm_encoder_slave_funcs { 51 + /** 52 + * @set_config: Initialize any encoder-specific modesetting parameters. 53 + * The meaning of the @params parameter is implementation dependent. It 54 + * will usually be a structure with DVO port data format settings or 55 + * timings. It's not required for the new parameters to take effect 56 + * until the next mode is set. 57 + */ 45 58 void (*set_config)(struct drm_encoder *encoder, 46 59 void *params); 47 60 61 + /** 62 + * @destroy: Analogous to &drm_encoder_funcs @destroy callback. 63 + */ 48 64 void (*destroy)(struct drm_encoder *encoder); 65 + 66 + /** 67 + * @dpms: Analogous to &drm_encoder_helper_funcs @dpms callback. Wrapped 68 + * by drm_i2c_encoder_dpms(). 69 + */ 49 70 void (*dpms)(struct drm_encoder *encoder, int mode); 71 + 72 + /** 73 + * @save: Save state. Wrapped by drm_i2c_encoder_save(). 74 + */ 50 75 void (*save)(struct drm_encoder *encoder); 76 + 77 + /** 78 + * @restore: Restore state. Wrapped by drm_i2c_encoder_restore(). 79 + */ 51 80 void (*restore)(struct drm_encoder *encoder); 81 + 82 + /** 83 + * @mode_fixup: Analogous to &drm_encoder_helper_funcs @mode_fixup 84 + * callback. Wrapped by drm_i2c_encoder_mode_fixup(). 85 + */ 52 86 bool (*mode_fixup)(struct drm_encoder *encoder, 53 87 const struct drm_display_mode *mode, 54 88 struct drm_display_mode *adjusted_mode); 89 + 90 + /** 91 + * @mode_valid: Analogous to &drm_encoder_helper_funcs @mode_valid. 92 + */ 55 93 int (*mode_valid)(struct drm_encoder *encoder, 56 94 struct drm_display_mode *mode); 95 + /** 96 + * @mode_set: Analogous to &drm_encoder_helper_funcs @mode_set 97 + * callback. Wrapped by drm_i2c_encoder_mode_set(). 98 + */ 57 99 void (*mode_set)(struct drm_encoder *encoder, 58 100 struct drm_display_mode *mode, 59 101 struct drm_display_mode *adjusted_mode); 60 102 103 + /** 104 + * @detect: Analogous to &drm_encoder_helper_funcs @detect 105 + * callback. Wrapped by drm_i2c_encoder_detect(). 106 + */ 61 107 enum drm_connector_status (*detect)(struct drm_encoder *encoder, 62 108 struct drm_connector *connector); 109 + /** 110 + * @get_modes: Get modes. 111 + */ 63 112 int (*get_modes)(struct drm_encoder *encoder, 64 113 struct drm_connector *connector); 114 + /** 115 + * @create_resources: Create resources. 116 + */ 65 117 int (*create_resources)(struct drm_encoder *encoder, 66 118 struct drm_connector *connector); 119 + /** 120 + * @set_property: Set property. 121 + */ 67 122 int (*set_property)(struct drm_encoder *encoder, 68 123 struct drm_connector *connector, 69 124 struct drm_property *property, 70 125 uint64_t val); 71 - 72 126 }; 73 127 74 128 /** 75 129 * struct drm_encoder_slave - Slave encoder struct 76 - * @base: DRM encoder object. 77 - * @slave_funcs: Slave encoder callbacks. 78 - * @slave_priv: Slave encoder private data. 79 - * @bus_priv: Bus specific data. 80 130 * 81 131 * A &drm_encoder_slave has two sets of callbacks, @slave_funcs and the 82 132 * ones in @base. The former are never actually called by the common ··· 133 95 * this. 134 96 */ 135 97 struct drm_encoder_slave { 98 + /** 99 + * @base: DRM encoder object. 100 + */ 136 101 struct drm_encoder base; 137 102 103 + /** 104 + * @slave_funcs: Slave encoder callbacks. 105 + */ 138 106 const struct drm_encoder_slave_funcs *slave_funcs; 107 + 108 + /** 109 + * @slave_priv: Slave encoder private data. 110 + */ 139 111 void *slave_priv; 112 + 113 + /** 114 + * @bus_priv: Bus specific data. 115 + */ 140 116 void *bus_priv; 141 117 }; 142 118 #define to_encoder_slave(x) container_of((x), struct drm_encoder_slave, base) ··· 164 112 /** 165 113 * struct drm_i2c_encoder_driver 166 114 * 167 - * Describes a device driver for an encoder connected to the GPU 168 - * through an I2C bus. In addition to the entry points in @i2c_driver 169 - * an @encoder_init function should be provided. It will be called to 170 - * give the driver an opportunity to allocate any per-encoder data 171 - * structures and to initialize the @slave_funcs and (optionally) 172 - * @slave_priv members of @encoder. 115 + * Describes a device driver for an encoder connected to the GPU through an I2C 116 + * bus. 173 117 */ 174 118 struct drm_i2c_encoder_driver { 119 + /** 120 + * @i2c_driver: I2C device driver description. 121 + */ 175 122 struct i2c_driver i2c_driver; 176 123 124 + /** 125 + * @encoder_init: Callback to allocate any per-encoder data structures 126 + * and to initialize the @slave_funcs and (optionally) @slave_priv 127 + * members of @encoder. 128 + */ 177 129 int (*encoder_init)(struct i2c_client *client, 178 130 struct drm_device *dev, 179 131 struct drm_encoder_slave *encoder); ··· 189 133 190 134 /** 191 135 * drm_i2c_encoder_get_client - Get the I2C client corresponding to an encoder 136 + * @encoder: The encoder 192 137 */ 193 138 static inline struct i2c_client *drm_i2c_encoder_get_client(struct drm_encoder *encoder) 194 139 {
+1
include/drm/drm_format_helper.h
··· 25 25 * All fields are considered private. 26 26 */ 27 27 struct drm_format_conv_state { 28 + /* private: */ 28 29 struct { 29 30 void *mem; 30 31 size_t size;
+3
include/drm/drm_gem.h
··· 527 527 void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, 528 528 bool dirty, bool accessed); 529 529 530 + void drm_gem_lock(struct drm_gem_object *obj); 531 + void drm_gem_unlock(struct drm_gem_object *obj); 532 + 530 533 int drm_gem_vmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map); 531 534 void drm_gem_vunmap_unlocked(struct drm_gem_object *obj, struct iosys_map *map); 532 535
+5 -2
include/drm/drm_gem_shmem_helper.h
··· 108 108 struct iosys_map *map); 109 109 int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct *vma); 110 110 111 + int drm_gem_shmem_pin_locked(struct drm_gem_shmem_object *shmem); 112 + void drm_gem_shmem_unpin_locked(struct drm_gem_shmem_object *shmem); 113 + 111 114 int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv); 112 115 113 116 static inline bool drm_gem_shmem_is_purgeable(struct drm_gem_shmem_object *shmem) ··· 176 173 { 177 174 struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 178 175 179 - return drm_gem_shmem_pin(shmem); 176 + return drm_gem_shmem_pin_locked(shmem); 180 177 } 181 178 182 179 /** ··· 190 187 { 191 188 struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); 192 189 193 - drm_gem_shmem_unpin(shmem); 190 + drm_gem_shmem_unpin_locked(shmem); 194 191 } 195 192 196 193 /**
-1
include/drm/drm_gem_vram_helper.h
··· 170 170 * @vram_base: Base address of the managed video memory 171 171 * @vram_size: Size of the managed video memory in bytes 172 172 * @bdev: The TTM BO device. 173 - * @funcs: TTM BO functions 174 173 * 175 174 * The fields &struct drm_vram_mm.vram_base and 176 175 * &struct drm_vram_mm.vrm_size are managed by VRAM MM, but are
+1 -1
include/drm/drm_kunit_helpers.h
··· 75 75 * @_dev: The parent device object 76 76 * @_type: the type of the struct which contains struct &drm_device 77 77 * @_member: the name of the &drm_device within @_type. 78 - * @_features: Mocked DRM device driver features 78 + * @_feat: Mocked DRM device driver features 79 79 * 80 80 * This function creates a struct &drm_driver and will create a struct 81 81 * &drm_device from @_dev and that driver.
+2
include/drm/drm_lease.h
··· 6 6 #ifndef _DRM_LEASE_H_ 7 7 #define _DRM_LEASE_H_ 8 8 9 + #include <linux/types.h> 10 + 9 11 struct drm_file; 10 12 struct drm_device; 11 13 struct drm_master;
+1
include/drm/drm_of.h
··· 2 2 #ifndef __DRM_OF_H__ 3 3 #define __DRM_OF_H__ 4 4 5 + #include <linux/err.h> 5 6 #include <linux/of_graph.h> 6 7 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE) 7 8 #include <drm/drm_bridge.h>
+1 -1
include/drm/drm_suballoc.h
··· 37 37 * @manager: The drm_suballoc_manager. 38 38 * @soffset: Start offset. 39 39 * @eoffset: End offset + 1 so that @eoffset - @soffset = size. 40 - * @dma_fence: The fence protecting the allocation. 40 + * @fence: The fence protecting the allocation. 41 41 */ 42 42 struct drm_suballoc { 43 43 struct list_head olist;
+1
include/drm/i2c/ch7006.h
··· 37 37 * meaning. 38 38 */ 39 39 struct ch7006_encoder_params { 40 + /* private: FIXME: document the members */ 40 41 enum { 41 42 CH7006_FORMAT_RGB16 = 0, 42 43 CH7006_FORMAT_YCrCb24m16,
+1
include/drm/i2c/sil164.h
··· 36 36 * See "http://www.siliconimage.com/docs/SiI-DS-0021-E-164.pdf". 37 37 */ 38 38 struct sil164_encoder_params { 39 + /* private: FIXME: document the members */ 39 40 enum { 40 41 SIL164_INPUT_EDGE_FALLING = 0, 41 42 SIL164_INPUT_EDGE_RISING
+2 -2
include/drm/i915_gsc_proxy_mei_interface.h
··· 21 21 struct module *owner; 22 22 23 23 /** 24 - * send - Sends a proxy message to ME FW. 24 + * @send: Sends a proxy message to ME FW. 25 25 * @dev: device struct corresponding to the mei device 26 26 * @buf: message buffer to send 27 27 * @size: size of the message ··· 30 30 int (*send)(struct device *dev, const void *buf, size_t size); 31 31 32 32 /** 33 - * recv - Receives a proxy message from ME FW. 33 + * @recv: Receives a proxy message from ME FW. 34 34 * @dev: device struct corresponding to the mei device 35 35 * @buf: message buffer to contain the received message 36 36 * @size: size of the buffer
+13 -5
include/drm/i915_hdcp_interface.h
··· 54 54 }; 55 55 56 56 /** 57 - * enum hdcp_tc - ME/GSC Firmware defined index for transcoders 57 + * enum hdcp_transcoder - ME/GSC Firmware defined index for transcoders 58 58 * @HDCP_INVALID_TRANSCODER: Index for Invalid transcoder 59 59 * @HDCP_TRANSCODER_EDP: Index for EDP Transcoder 60 60 * @HDCP_TRANSCODER_DSI0: Index for DSI0 Transcoder ··· 106 106 * And Prepare AKE_Init. 107 107 * @verify_receiver_cert_prepare_km: Verify the Receiver Certificate 108 108 * AKE_Send_Cert and prepare 109 - AKE_Stored_Km/AKE_No_Stored_Km 109 + * AKE_Stored_Km/AKE_No_Stored_Km 110 110 * @verify_hprime: Verify AKE_Send_H_prime 111 111 * @store_pairing_info: Store pairing info received 112 112 * @initiate_locality_check: Prepare LC_Init ··· 170 170 /** 171 171 * struct i915_hdcp_arbiter - Used for communication between i915 172 172 * and hdcp drivers for the HDCP2.2 services 173 - * @hdcp_dev: device that provide the HDCP2.2 service from MEI Bus. 174 - * @hdcp_ops: Ops implemented by hdcp driver or intel_hdcp_gsc , used by i915 driver. 175 173 */ 176 174 struct i915_hdcp_arbiter { 175 + /** 176 + * @hdcp_dev: device that provides the HDCP2.2 service from MEI Bus. 177 + */ 177 178 struct device *hdcp_dev; 179 + 180 + /** 181 + * @ops: Ops implemented by hdcp driver or intel_hdcp_gsc, used by i915 182 + * driver. 183 + */ 178 184 const struct i915_hdcp_ops *ops; 179 185 180 - /* To protect the above members. */ 186 + /** 187 + * @mutex: To protect the above members. 188 + */ 181 189 struct mutex mutex; 182 190 }; 183 191
+20 -7
include/drm/i915_pxp_tee_interface.h
··· 12 12 13 13 /** 14 14 * struct i915_pxp_component_ops - ops for PXP services. 15 - * @owner: Module providing the ops 16 - * @send: sends data to PXP 17 - * @receive: receives data from PXP 18 15 */ 19 16 struct i915_pxp_component_ops { 20 17 /** 21 - * @owner: owner of the module provding the ops 18 + * @owner: Module providing the ops. 22 19 */ 23 20 struct module *owner; 24 21 22 + /** 23 + * @send: Send a PXP message. 24 + */ 25 25 int (*send)(struct device *dev, const void *message, size_t size, 26 26 unsigned long timeout_ms); 27 + /** 28 + * @recv: Receive a PXP message. 29 + */ 27 30 int (*recv)(struct device *dev, void *buffer, size_t size, 28 31 unsigned long timeout_ms); 32 + /** 33 + * @gsc_command: Send a GSC command. 34 + */ 29 35 ssize_t (*gsc_command)(struct device *dev, u8 client_id, u32 fence_id, 30 36 struct scatterlist *sg_in, size_t total_in_len, 31 37 struct scatterlist *sg_out); ··· 41 35 /** 42 36 * struct i915_pxp_component - Used for communication between i915 and TEE 43 37 * drivers for the PXP services 44 - * @tee_dev: device that provide the PXP service from TEE Bus. 45 - * @pxp_ops: Ops implemented by TEE driver, used by i915 driver. 46 38 */ 47 39 struct i915_pxp_component { 40 + /** 41 + * @tee_dev: device that provide the PXP service from TEE Bus. 42 + */ 48 43 struct device *tee_dev; 44 + 45 + /** 46 + * @ops: Ops implemented by TEE driver, used by i915 driver. 47 + */ 49 48 const struct i915_pxp_component_ops *ops; 50 49 51 - /* To protect the above members. */ 50 + /** 51 + * @mutex: To protect the above members. 52 + */ 52 53 struct mutex mutex; 53 54 }; 54 55
+11 -6
include/drm/ttm/ttm_bo.h
··· 83 83 * @resource: structure describing current placement. 84 84 * @ttm: TTM structure holding system pages. 85 85 * @deleted: True if the object is only a zombie and already deleted. 86 + * @bulk_move: The bulk move object. 87 + * @priority: Priority for LRU, BOs with lower priority are evicted first. 88 + * @pin_count: Pin count. 86 89 * 87 90 * Base class for TTM buffer object, that deals with data placement and CPU 88 91 * mappings. GPU mappings are really up to the driver, but for simpler GPUs ··· 131 128 struct work_struct delayed_delete; 132 129 133 130 /** 134 - * Special members that are protected by the reserve lock 135 - * and the bo::lock when written to. Can be read with 136 - * either of these locks held. 131 + * @sg: external source of pages and DMA addresses, protected by the 132 + * reservation lock. 137 133 */ 138 134 struct sg_table *sg; 139 135 }; 136 + 137 + #define TTM_BO_MAP_IOMEM_MASK 0x80 140 138 141 139 /** 142 140 * struct ttm_bo_kmap_obj ··· 145 141 * @virtual: The current kernel virtual address. 146 142 * @page: The page when kmap'ing a single page. 147 143 * @bo_kmap_type: Type of bo_kmap. 144 + * @bo: The TTM BO. 148 145 * 149 146 * Object describing a kernel mapping. Since a TTM bo may be located 150 147 * in various memory types with various caching policies, the 151 148 * mapping can either be an ioremap, a vmap, a kmap or part of a 152 149 * premapped region. 153 150 */ 154 - #define TTM_BO_MAP_IOMEM_MASK 0x80 155 151 struct ttm_bo_kmap_obj { 156 152 void *virtual; 157 153 struct page *page; ··· 175 171 * @force_alloc: Don't check the memory account during suspend or CPU page 176 172 * faults. Should only be used by TTM internally. 177 173 * @resv: Reservation object to allow reserved evictions with. 174 + * @bytes_moved: Statistics on how many bytes have been moved. 178 175 * 179 176 * Context for TTM operations like changing buffer placement or general memory 180 177 * allocation. ··· 269 264 * ttm_bo_reserve_slowpath: 270 265 * @bo: A pointer to a struct ttm_buffer_object. 271 266 * @interruptible: Sleep interruptible if waiting. 272 - * @sequence: Set (@bo)->sequence to this value after lock 267 + * @ticket: Ticket used to acquire the ww_mutex. 273 268 * 274 269 * This is called after ttm_bo_reserve returns -EAGAIN and we backed off 275 270 * from all our other reservations. Because there are no other reservations ··· 308 303 } 309 304 310 305 /** 311 - * ttm_bo_move_null = assign memory for a buffer object. 306 + * ttm_bo_move_null - assign memory for a buffer object. 312 307 * @bo: The bo to assign the memory to 313 308 * @new_mem: The memory to be assigned. 314 309 *
+2
include/drm/ttm/ttm_caching.h
··· 25 25 #ifndef _TTM_CACHING_H_ 26 26 #define _TTM_CACHING_H_ 27 27 28 + #include <linux/pgtable.h> 29 + 28 30 #define TTM_NUM_CACHING_TYPES 3 29 31 30 32 /**
+3 -4
include/drm/ttm/ttm_execbuf_util.h
··· 52 52 }; 53 53 54 54 /** 55 - * function ttm_eu_backoff_reservation 55 + * ttm_eu_backoff_reservation 56 56 * 57 57 * @ticket: ww_acquire_ctx from reserve call 58 58 * @list: thread private list of ttm_validate_buffer structs. ··· 64 64 struct list_head *list); 65 65 66 66 /** 67 - * function ttm_eu_reserve_buffers 67 + * ttm_eu_reserve_buffers 68 68 * 69 69 * @ticket: [out] ww_acquire_ctx filled in by call, or NULL if only 70 70 * non-blocking reserves should be tried. 71 71 * @list: thread private list of ttm_validate_buffer structs. 72 72 * @intr: should the wait be interruptible 73 73 * @dups: [out] optional list of duplicates. 74 - * @del_lru: true if BOs should be removed from the LRU. 75 74 * 76 75 * Tries to reserve bos pointed to by the list entries for validation. 77 76 * If the function returns 0, all buffers are marked as "unfenced", ··· 101 102 struct list_head *dups); 102 103 103 104 /** 104 - * function ttm_eu_fence_buffer_objects. 105 + * ttm_eu_fence_buffer_objects 105 106 * 106 107 * @ticket: ww_acquire_ctx from reserve call 107 108 * @list: thread private list of ttm_validate_buffer structs.
+2 -2
include/drm/ttm/ttm_kmap_iter.h
··· 20 20 */ 21 21 struct ttm_kmap_iter_ops { 22 22 /** 23 - * kmap_local() - Map a PAGE_SIZE part of the resource using 23 + * @map_local: Map a PAGE_SIZE part of the resource using 24 24 * kmap_local semantics. 25 25 * @res_iter: Pointer to the struct ttm_kmap_iter representing 26 26 * the resource. ··· 31 31 void (*map_local)(struct ttm_kmap_iter *res_iter, 32 32 struct iosys_map *dmap, pgoff_t i); 33 33 /** 34 - * unmap_local() - Unmap a PAGE_SIZE part of the resource previously 34 + * @unmap_local: Unmap a PAGE_SIZE part of the resource previously 35 35 * mapped using kmap_local. 36 36 * @res_iter: Pointer to the struct ttm_kmap_iter representing 37 37 * the resource.
+3 -2
include/drm/ttm/ttm_pool.h
··· 32 32 #include <drm/ttm/ttm_caching.h> 33 33 34 34 struct device; 35 - struct ttm_tt; 36 - struct ttm_pool; 35 + struct seq_file; 37 36 struct ttm_operation_ctx; 37 + struct ttm_pool; 38 + struct ttm_tt; 38 39 39 40 /** 40 41 * struct ttm_pool_type - Pool for a certain memory type
+5 -1
include/drm/ttm/ttm_resource.h
··· 251 251 * 252 252 * Container for the current bulk move state. Should be used with 253 253 * ttm_lru_bulk_move_init() and ttm_bo_set_bulk_move(). 254 + * All BOs in a bulk_move structure need to share the same reservation object to 255 + * ensure that the bulk as a whole is locked for eviction even if only one BO of 256 + * the bulk is evicted. 254 257 */ 255 258 struct ttm_lru_bulk_move { 256 259 struct ttm_lru_bulk_move_pos pos[TTM_NUM_MEM_TYPES][TTM_MAX_BO_PRIORITY]; ··· 369 366 const struct ttm_place *place, 370 367 size_t size); 371 368 bool ttm_resource_compatible(struct ttm_resource *res, 372 - struct ttm_placement *placement); 369 + struct ttm_placement *placement, 370 + bool evicting); 373 371 void ttm_resource_set_bo(struct ttm_resource *res, 374 372 struct ttm_buffer_object *bo); 375 373
+4
include/linux/fb.h
··· 694 694 __FB_GEN_DEFAULT_DEFERRED_OPS_RDWR(__prefix, __damage_range, sys) \ 695 695 __FB_GEN_DEFAULT_DEFERRED_OPS_DRAW(__prefix, __damage_area, sys) 696 696 697 + #define FB_GEN_DEFAULT_DEFERRED_DMAMEM_OPS(__prefix, __damage_range, __damage_area) \ 698 + __FB_GEN_DEFAULT_DEFERRED_OPS_RDWR(__prefix, __damage_range, sys) \ 699 + __FB_GEN_DEFAULT_DEFERRED_OPS_DRAW(__prefix, __damage_area, sys) 700 + 697 701 /* 698 702 * Initializes struct fb_ops for deferred I/O. 699 703 */
+22
include/uapi/drm/nouveau_drm.h
··· 73 73 __u64 value; 74 74 }; 75 75 76 + /* 77 + * Those are used to support selecting the main engine used on Kepler. 78 + * This goes into drm_nouveau_channel_alloc::tt_ctxdma_handle 79 + */ 80 + #define NOUVEAU_FIFO_ENGINE_GR 0x01 81 + #define NOUVEAU_FIFO_ENGINE_VP 0x02 82 + #define NOUVEAU_FIFO_ENGINE_PPP 0x04 83 + #define NOUVEAU_FIFO_ENGINE_BSP 0x08 84 + #define NOUVEAU_FIFO_ENGINE_CE 0x30 85 + 76 86 struct drm_nouveau_channel_alloc { 77 87 __u32 fb_ctxdma_handle; 78 88 __u32 tt_ctxdma_handle; ··· 103 93 104 94 struct drm_nouveau_channel_free { 105 95 __s32 channel; 96 + }; 97 + 98 + struct drm_nouveau_notifierobj_alloc { 99 + __u32 channel; 100 + __u32 handle; 101 + __u32 size; 102 + __u32 offset; 103 + }; 104 + 105 + struct drm_nouveau_gpuobj_free { 106 + __s32 channel; 107 + __u32 handle; 106 108 }; 107 109 108 110 #define NOUVEAU_GEM_DOMAIN_CPU (1 << 0)
+945
include/uapi/drm/panthor_drm.h
··· 1 + /* SPDX-License-Identifier: MIT */ 2 + /* Copyright (C) 2023 Collabora ltd. */ 3 + #ifndef _PANTHOR_DRM_H_ 4 + #define _PANTHOR_DRM_H_ 5 + 6 + #include "drm.h" 7 + 8 + #if defined(__cplusplus) 9 + extern "C" { 10 + #endif 11 + 12 + /** 13 + * DOC: Introduction 14 + * 15 + * This documentation describes the Panthor IOCTLs. 16 + * 17 + * Just a few generic rules about the data passed to the Panthor IOCTLs: 18 + * 19 + * - Structures must be aligned on 64-bit/8-byte. If the object is not 20 + * naturally aligned, a padding field must be added. 21 + * - Fields must be explicitly aligned to their natural type alignment with 22 + * pad[0..N] fields. 23 + * - All padding fields will be checked by the driver to make sure they are 24 + * zeroed. 25 + * - Flags can be added, but not removed/replaced. 26 + * - New fields can be added to the main structures (the structures 27 + * directly passed to the ioctl). Those fields can be added at the end of 28 + * the structure, or replace existing padding fields. Any new field being 29 + * added must preserve the behavior that existed before those fields were 30 + * added when a value of zero is passed. 31 + * - New fields can be added to indirect objects (objects pointed by the 32 + * main structure), iff those objects are passed a size to reflect the 33 + * size known by the userspace driver (see drm_panthor_obj_array::stride 34 + * or drm_panthor_dev_query::size). 35 + * - If the kernel driver is too old to know some fields, those will be 36 + * ignored if zero, and otherwise rejected (and so will be zero on output). 37 + * - If userspace is too old to know some fields, those will be zeroed 38 + * (input) before the structure is parsed by the kernel driver. 39 + * - Each new flag/field addition must come with a driver version update so 40 + * the userspace driver doesn't have to trial and error to know which 41 + * flags are supported. 42 + * - Structures should not contain unions, as this would defeat the 43 + * extensibility of such structures. 44 + * - IOCTLs can't be removed or replaced. New IOCTL IDs should be placed 45 + * at the end of the drm_panthor_ioctl_id enum. 46 + */ 47 + 48 + /** 49 + * DOC: MMIO regions exposed to userspace. 50 + * 51 + * .. c:macro:: DRM_PANTHOR_USER_MMIO_OFFSET 52 + * 53 + * File offset for all MMIO regions being exposed to userspace. Don't use 54 + * this value directly, use DRM_PANTHOR_USER_<name>_OFFSET values instead. 55 + * pgoffset passed to mmap2() is an unsigned long, which forces us to use a 56 + * different offset on 32-bit and 64-bit systems. 57 + * 58 + * .. c:macro:: DRM_PANTHOR_USER_FLUSH_ID_MMIO_OFFSET 59 + * 60 + * File offset for the LATEST_FLUSH_ID register. The Userspace driver controls 61 + * GPU cache flushing through CS instructions, but the flush reduction 62 + * mechanism requires a flush_id. This flush_id could be queried with an 63 + * ioctl, but Arm provides a well-isolated register page containing only this 64 + * read-only register, so let's expose this page through a static mmap offset 65 + * and allow direct mapping of this MMIO region so we can avoid the 66 + * user <-> kernel round-trip. 67 + */ 68 + #define DRM_PANTHOR_USER_MMIO_OFFSET_32BIT (1ull << 43) 69 + #define DRM_PANTHOR_USER_MMIO_OFFSET_64BIT (1ull << 56) 70 + #define DRM_PANTHOR_USER_MMIO_OFFSET (sizeof(unsigned long) < 8 ? \ 71 + DRM_PANTHOR_USER_MMIO_OFFSET_32BIT : \ 72 + DRM_PANTHOR_USER_MMIO_OFFSET_64BIT) 73 + #define DRM_PANTHOR_USER_FLUSH_ID_MMIO_OFFSET (DRM_PANTHOR_USER_MMIO_OFFSET | 0) 74 + 75 + /** 76 + * DOC: IOCTL IDs 77 + * 78 + * enum drm_panthor_ioctl_id - IOCTL IDs 79 + * 80 + * Place new ioctls at the end, don't re-order, don't replace or remove entries. 81 + * 82 + * These IDs are not meant to be used directly. Use the DRM_IOCTL_PANTHOR_xxx 83 + * definitions instead. 84 + */ 85 + enum drm_panthor_ioctl_id { 86 + /** @DRM_PANTHOR_DEV_QUERY: Query device information. */ 87 + DRM_PANTHOR_DEV_QUERY = 0, 88 + 89 + /** @DRM_PANTHOR_VM_CREATE: Create a VM. */ 90 + DRM_PANTHOR_VM_CREATE, 91 + 92 + /** @DRM_PANTHOR_VM_DESTROY: Destroy a VM. */ 93 + DRM_PANTHOR_VM_DESTROY, 94 + 95 + /** @DRM_PANTHOR_VM_BIND: Bind/unbind memory to a VM. */ 96 + DRM_PANTHOR_VM_BIND, 97 + 98 + /** @DRM_PANTHOR_VM_GET_STATE: Get VM state. */ 99 + DRM_PANTHOR_VM_GET_STATE, 100 + 101 + /** @DRM_PANTHOR_BO_CREATE: Create a buffer object. */ 102 + DRM_PANTHOR_BO_CREATE, 103 + 104 + /** 105 + * @DRM_PANTHOR_BO_MMAP_OFFSET: Get the file offset to pass to 106 + * mmap to map a GEM object. 107 + */ 108 + DRM_PANTHOR_BO_MMAP_OFFSET, 109 + 110 + /** @DRM_PANTHOR_GROUP_CREATE: Create a scheduling group. */ 111 + DRM_PANTHOR_GROUP_CREATE, 112 + 113 + /** @DRM_PANTHOR_GROUP_DESTROY: Destroy a scheduling group. */ 114 + DRM_PANTHOR_GROUP_DESTROY, 115 + 116 + /** 117 + * @DRM_PANTHOR_GROUP_SUBMIT: Submit jobs to queues belonging 118 + * to a specific scheduling group. 119 + */ 120 + DRM_PANTHOR_GROUP_SUBMIT, 121 + 122 + /** @DRM_PANTHOR_GROUP_GET_STATE: Get the state of a scheduling group. */ 123 + DRM_PANTHOR_GROUP_GET_STATE, 124 + 125 + /** @DRM_PANTHOR_TILER_HEAP_CREATE: Create a tiler heap. */ 126 + DRM_PANTHOR_TILER_HEAP_CREATE, 127 + 128 + /** @DRM_PANTHOR_TILER_HEAP_DESTROY: Destroy a tiler heap. */ 129 + DRM_PANTHOR_TILER_HEAP_DESTROY, 130 + }; 131 + 132 + /** 133 + * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number 134 + * @__access: Access type. Must be R, W or RW. 135 + * @__id: One of the DRM_PANTHOR_xxx id. 136 + * @__type: Suffix of the type being passed to the IOCTL. 137 + * 138 + * Don't use this macro directly, use the DRM_IOCTL_PANTHOR_xxx 139 + * values instead. 140 + * 141 + * Return: An IOCTL number to be passed to ioctl() from userspace. 142 + */ 143 + #define DRM_IOCTL_PANTHOR(__access, __id, __type) \ 144 + DRM_IO ## __access(DRM_COMMAND_BASE + DRM_PANTHOR_ ## __id, \ 145 + struct drm_panthor_ ## __type) 146 + 147 + #define DRM_IOCTL_PANTHOR_DEV_QUERY \ 148 + DRM_IOCTL_PANTHOR(WR, DEV_QUERY, dev_query) 149 + #define DRM_IOCTL_PANTHOR_VM_CREATE \ 150 + DRM_IOCTL_PANTHOR(WR, VM_CREATE, vm_create) 151 + #define DRM_IOCTL_PANTHOR_VM_DESTROY \ 152 + DRM_IOCTL_PANTHOR(WR, VM_DESTROY, vm_destroy) 153 + #define DRM_IOCTL_PANTHOR_VM_BIND \ 154 + DRM_IOCTL_PANTHOR(WR, VM_BIND, vm_bind) 155 + #define DRM_IOCTL_PANTHOR_VM_GET_STATE \ 156 + DRM_IOCTL_PANTHOR(WR, VM_GET_STATE, vm_get_state) 157 + #define DRM_IOCTL_PANTHOR_BO_CREATE \ 158 + DRM_IOCTL_PANTHOR(WR, BO_CREATE, bo_create) 159 + #define DRM_IOCTL_PANTHOR_BO_MMAP_OFFSET \ 160 + DRM_IOCTL_PANTHOR(WR, BO_MMAP_OFFSET, bo_mmap_offset) 161 + #define DRM_IOCTL_PANTHOR_GROUP_CREATE \ 162 + DRM_IOCTL_PANTHOR(WR, GROUP_CREATE, group_create) 163 + #define DRM_IOCTL_PANTHOR_GROUP_DESTROY \ 164 + DRM_IOCTL_PANTHOR(WR, GROUP_DESTROY, group_destroy) 165 + #define DRM_IOCTL_PANTHOR_GROUP_SUBMIT \ 166 + DRM_IOCTL_PANTHOR(WR, GROUP_SUBMIT, group_submit) 167 + #define DRM_IOCTL_PANTHOR_GROUP_GET_STATE \ 168 + DRM_IOCTL_PANTHOR(WR, GROUP_GET_STATE, group_get_state) 169 + #define DRM_IOCTL_PANTHOR_TILER_HEAP_CREATE \ 170 + DRM_IOCTL_PANTHOR(WR, TILER_HEAP_CREATE, tiler_heap_create) 171 + #define DRM_IOCTL_PANTHOR_TILER_HEAP_DESTROY \ 172 + DRM_IOCTL_PANTHOR(WR, TILER_HEAP_DESTROY, tiler_heap_destroy) 173 + 174 + /** 175 + * DOC: IOCTL arguments 176 + */ 177 + 178 + /** 179 + * struct drm_panthor_obj_array - Object array. 180 + * 181 + * This object is used to pass an array of objects whose size is subject to changes in 182 + * future versions of the driver. In order to support this mutability, we pass a stride 183 + * describing the size of the object as known by userspace. 184 + * 185 + * You shouldn't fill drm_panthor_obj_array fields directly. You should instead use 186 + * the DRM_PANTHOR_OBJ_ARRAY() macro that takes care of initializing the stride to 187 + * the object size. 188 + */ 189 + struct drm_panthor_obj_array { 190 + /** @stride: Stride of object struct. Used for versioning. */ 191 + __u32 stride; 192 + 193 + /** @count: Number of objects in the array. */ 194 + __u32 count; 195 + 196 + /** @array: User pointer to an array of objects. */ 197 + __u64 array; 198 + }; 199 + 200 + /** 201 + * DRM_PANTHOR_OBJ_ARRAY() - Initialize a drm_panthor_obj_array field. 202 + * @cnt: Number of elements in the array. 203 + * @ptr: Pointer to the array to pass to the kernel. 204 + * 205 + * Macro initializing a drm_panthor_obj_array based on the object size as known 206 + * by userspace. 207 + */ 208 + #define DRM_PANTHOR_OBJ_ARRAY(cnt, ptr) \ 209 + { .stride = sizeof((ptr)[0]), .count = (cnt), .array = (__u64)(uintptr_t)(ptr) } 210 + 211 + /** 212 + * enum drm_panthor_sync_op_flags - Synchronization operation flags. 213 + */ 214 + enum drm_panthor_sync_op_flags { 215 + /** @DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_MASK: Synchronization handle type mask. */ 216 + DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_MASK = 0xff, 217 + 218 + /** @DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_SYNCOBJ: Synchronization object type. */ 219 + DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_SYNCOBJ = 0, 220 + 221 + /** 222 + * @DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_TIMELINE_SYNCOBJ: Timeline synchronization 223 + * object type. 224 + */ 225 + DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_TIMELINE_SYNCOBJ = 1, 226 + 227 + /** @DRM_PANTHOR_SYNC_OP_WAIT: Wait operation. */ 228 + DRM_PANTHOR_SYNC_OP_WAIT = 0 << 31, 229 + 230 + /** @DRM_PANTHOR_SYNC_OP_SIGNAL: Signal operation. */ 231 + DRM_PANTHOR_SYNC_OP_SIGNAL = (int)(1u << 31), 232 + }; 233 + 234 + /** 235 + * struct drm_panthor_sync_op - Synchronization operation. 236 + */ 237 + struct drm_panthor_sync_op { 238 + /** @flags: Synchronization operation flags. Combination of DRM_PANTHOR_SYNC_OP values. */ 239 + __u32 flags; 240 + 241 + /** @handle: Sync handle. */ 242 + __u32 handle; 243 + 244 + /** 245 + * @timeline_value: MBZ if 246 + * (flags & DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_MASK) != 247 + * DRM_PANTHOR_SYNC_OP_HANDLE_TYPE_TIMELINE_SYNCOBJ. 248 + */ 249 + __u64 timeline_value; 250 + }; 251 + 252 + /** 253 + * enum drm_panthor_dev_query_type - Query type 254 + * 255 + * Place new types at the end, don't re-order, don't remove or replace. 256 + */ 257 + enum drm_panthor_dev_query_type { 258 + /** @DRM_PANTHOR_DEV_QUERY_GPU_INFO: Query GPU information. */ 259 + DRM_PANTHOR_DEV_QUERY_GPU_INFO = 0, 260 + 261 + /** @DRM_PANTHOR_DEV_QUERY_CSIF_INFO: Query command-stream interface information. */ 262 + DRM_PANTHOR_DEV_QUERY_CSIF_INFO, 263 + }; 264 + 265 + /** 266 + * struct drm_panthor_gpu_info - GPU information 267 + * 268 + * Structure grouping all queryable information relating to the GPU. 269 + */ 270 + struct drm_panthor_gpu_info { 271 + /** @gpu_id : GPU ID. */ 272 + __u32 gpu_id; 273 + #define DRM_PANTHOR_ARCH_MAJOR(x) ((x) >> 28) 274 + #define DRM_PANTHOR_ARCH_MINOR(x) (((x) >> 24) & 0xf) 275 + #define DRM_PANTHOR_ARCH_REV(x) (((x) >> 20) & 0xf) 276 + #define DRM_PANTHOR_PRODUCT_MAJOR(x) (((x) >> 16) & 0xf) 277 + #define DRM_PANTHOR_VERSION_MAJOR(x) (((x) >> 12) & 0xf) 278 + #define DRM_PANTHOR_VERSION_MINOR(x) (((x) >> 4) & 0xff) 279 + #define DRM_PANTHOR_VERSION_STATUS(x) ((x) & 0xf) 280 + 281 + /** @gpu_rev: GPU revision. */ 282 + __u32 gpu_rev; 283 + 284 + /** @csf_id: Command stream frontend ID. */ 285 + __u32 csf_id; 286 + #define DRM_PANTHOR_CSHW_MAJOR(x) (((x) >> 26) & 0x3f) 287 + #define DRM_PANTHOR_CSHW_MINOR(x) (((x) >> 20) & 0x3f) 288 + #define DRM_PANTHOR_CSHW_REV(x) (((x) >> 16) & 0xf) 289 + #define DRM_PANTHOR_MCU_MAJOR(x) (((x) >> 10) & 0x3f) 290 + #define DRM_PANTHOR_MCU_MINOR(x) (((x) >> 4) & 0x3f) 291 + #define DRM_PANTHOR_MCU_REV(x) ((x) & 0xf) 292 + 293 + /** @l2_features: L2-cache features. */ 294 + __u32 l2_features; 295 + 296 + /** @tiler_features: Tiler features. */ 297 + __u32 tiler_features; 298 + 299 + /** @mem_features: Memory features. */ 300 + __u32 mem_features; 301 + 302 + /** @mmu_features: MMU features. */ 303 + __u32 mmu_features; 304 + #define DRM_PANTHOR_MMU_VA_BITS(x) ((x) & 0xff) 305 + 306 + /** @thread_features: Thread features. */ 307 + __u32 thread_features; 308 + 309 + /** @max_threads: Maximum number of threads. */ 310 + __u32 max_threads; 311 + 312 + /** @thread_max_workgroup_size: Maximum workgroup size. */ 313 + __u32 thread_max_workgroup_size; 314 + 315 + /** 316 + * @thread_max_barrier_size: Maximum number of threads that can wait 317 + * simultaneously on a barrier. 318 + */ 319 + __u32 thread_max_barrier_size; 320 + 321 + /** @coherency_features: Coherency features. */ 322 + __u32 coherency_features; 323 + 324 + /** @texture_features: Texture features. */ 325 + __u32 texture_features[4]; 326 + 327 + /** @as_present: Bitmask encoding the number of address-space exposed by the MMU. */ 328 + __u32 as_present; 329 + 330 + /** @shader_present: Bitmask encoding the shader cores exposed by the GPU. */ 331 + __u64 shader_present; 332 + 333 + /** @l2_present: Bitmask encoding the L2 caches exposed by the GPU. */ 334 + __u64 l2_present; 335 + 336 + /** @tiler_present: Bitmask encoding the tiler units exposed by the GPU. */ 337 + __u64 tiler_present; 338 + 339 + /** @core_features: Used to discriminate core variants when they exist. */ 340 + __u32 core_features; 341 + 342 + /** @pad: MBZ. */ 343 + __u32 pad; 344 + }; 345 + 346 + /** 347 + * struct drm_panthor_csif_info - Command stream interface information 348 + * 349 + * Structure grouping all queryable information relating to the command stream interface. 350 + */ 351 + struct drm_panthor_csif_info { 352 + /** @csg_slot_count: Number of command stream group slots exposed by the firmware. */ 353 + __u32 csg_slot_count; 354 + 355 + /** @cs_slot_count: Number of command stream slots per group. */ 356 + __u32 cs_slot_count; 357 + 358 + /** @cs_reg_count: Number of command stream registers. */ 359 + __u32 cs_reg_count; 360 + 361 + /** @scoreboard_slot_count: Number of scoreboard slots. */ 362 + __u32 scoreboard_slot_count; 363 + 364 + /** 365 + * @unpreserved_cs_reg_count: Number of command stream registers reserved by 366 + * the kernel driver to call a userspace command stream. 367 + * 368 + * All registers can be used by a userspace command stream, but the 369 + * [cs_slot_count - unpreserved_cs_reg_count .. cs_slot_count] registers are 370 + * used by the kernel when DRM_PANTHOR_IOCTL_GROUP_SUBMIT is called. 371 + */ 372 + __u32 unpreserved_cs_reg_count; 373 + 374 + /** 375 + * @pad: Padding field, set to zero. 376 + */ 377 + __u32 pad; 378 + }; 379 + 380 + /** 381 + * struct drm_panthor_dev_query - Arguments passed to DRM_PANTHOR_IOCTL_DEV_QUERY 382 + */ 383 + struct drm_panthor_dev_query { 384 + /** @type: the query type (see drm_panthor_dev_query_type). */ 385 + __u32 type; 386 + 387 + /** 388 + * @size: size of the type being queried. 389 + * 390 + * If pointer is NULL, size is updated by the driver to provide the 391 + * output structure size. If pointer is not NULL, the driver will 392 + * only copy min(size, actual_structure_size) bytes to the pointer, 393 + * and update the size accordingly. This allows us to extend query 394 + * types without breaking userspace. 395 + */ 396 + __u32 size; 397 + 398 + /** 399 + * @pointer: user pointer to a query type struct. 400 + * 401 + * Pointer can be NULL, in which case, nothing is copied, but the 402 + * actual structure size is returned. If not NULL, it must point to 403 + * a location that's large enough to hold size bytes. 404 + */ 405 + __u64 pointer; 406 + }; 407 + 408 + /** 409 + * struct drm_panthor_vm_create - Arguments passed to DRM_PANTHOR_IOCTL_VM_CREATE 410 + */ 411 + struct drm_panthor_vm_create { 412 + /** @flags: VM flags, MBZ. */ 413 + __u32 flags; 414 + 415 + /** @id: Returned VM ID. */ 416 + __u32 id; 417 + 418 + /** 419 + * @user_va_range: Size of the VA space reserved for user objects. 420 + * 421 + * The kernel will pick the remaining space to map kernel-only objects to the 422 + * VM (heap chunks, heap context, ring buffers, kernel synchronization objects, 423 + * ...). If the space left for kernel objects is too small, kernel object 424 + * allocation will fail further down the road. One can use 425 + * drm_panthor_gpu_info::mmu_features to extract the total virtual address 426 + * range, and chose a user_va_range that leaves some space to the kernel. 427 + * 428 + * If user_va_range is zero, the kernel will pick a sensible value based on 429 + * TASK_SIZE and the virtual range supported by the GPU MMU (the kernel/user 430 + * split should leave enough VA space for userspace processes to support SVM, 431 + * while still allowing the kernel to map some amount of kernel objects in 432 + * the kernel VA range). The value chosen by the driver will be returned in 433 + * @user_va_range. 434 + * 435 + * User VA space always starts at 0x0, kernel VA space is always placed after 436 + * the user VA range. 437 + */ 438 + __u64 user_va_range; 439 + }; 440 + 441 + /** 442 + * struct drm_panthor_vm_destroy - Arguments passed to DRM_PANTHOR_IOCTL_VM_DESTROY 443 + */ 444 + struct drm_panthor_vm_destroy { 445 + /** @id: ID of the VM to destroy. */ 446 + __u32 id; 447 + 448 + /** @pad: MBZ. */ 449 + __u32 pad; 450 + }; 451 + 452 + /** 453 + * enum drm_panthor_vm_bind_op_flags - VM bind operation flags 454 + */ 455 + enum drm_panthor_vm_bind_op_flags { 456 + /** 457 + * @DRM_PANTHOR_VM_BIND_OP_MAP_READONLY: Map the memory read-only. 458 + * 459 + * Only valid with DRM_PANTHOR_VM_BIND_OP_TYPE_MAP. 460 + */ 461 + DRM_PANTHOR_VM_BIND_OP_MAP_READONLY = 1 << 0, 462 + 463 + /** 464 + * @DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC: Map the memory not-executable. 465 + * 466 + * Only valid with DRM_PANTHOR_VM_BIND_OP_TYPE_MAP. 467 + */ 468 + DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC = 1 << 1, 469 + 470 + /** 471 + * @DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED: Map the memory uncached. 472 + * 473 + * Only valid with DRM_PANTHOR_VM_BIND_OP_TYPE_MAP. 474 + */ 475 + DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED = 1 << 2, 476 + 477 + /** 478 + * @DRM_PANTHOR_VM_BIND_OP_TYPE_MASK: Mask used to determine the type of operation. 479 + */ 480 + DRM_PANTHOR_VM_BIND_OP_TYPE_MASK = (int)(0xfu << 28), 481 + 482 + /** @DRM_PANTHOR_VM_BIND_OP_TYPE_MAP: Map operation. */ 483 + DRM_PANTHOR_VM_BIND_OP_TYPE_MAP = 0 << 28, 484 + 485 + /** @DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP: Unmap operation. */ 486 + DRM_PANTHOR_VM_BIND_OP_TYPE_UNMAP = 1 << 28, 487 + 488 + /** 489 + * @DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY: No VM operation. 490 + * 491 + * Just serves as a synchronization point on a VM queue. 492 + * 493 + * Only valid if %DRM_PANTHOR_VM_BIND_ASYNC is set in drm_panthor_vm_bind::flags, 494 + * and drm_panthor_vm_bind_op::syncs contains at least one element. 495 + */ 496 + DRM_PANTHOR_VM_BIND_OP_TYPE_SYNC_ONLY = 2 << 28, 497 + }; 498 + 499 + /** 500 + * struct drm_panthor_vm_bind_op - VM bind operation 501 + */ 502 + struct drm_panthor_vm_bind_op { 503 + /** @flags: Combination of drm_panthor_vm_bind_op_flags flags. */ 504 + __u32 flags; 505 + 506 + /** 507 + * @bo_handle: Handle of the buffer object to map. 508 + * MBZ for unmap or sync-only operations. 509 + */ 510 + __u32 bo_handle; 511 + 512 + /** 513 + * @bo_offset: Buffer object offset. 514 + * MBZ for unmap or sync-only operations. 515 + */ 516 + __u64 bo_offset; 517 + 518 + /** 519 + * @va: Virtual address to map/unmap. 520 + * MBZ for sync-only operations. 521 + */ 522 + __u64 va; 523 + 524 + /** 525 + * @size: Size to map/unmap. 526 + * MBZ for sync-only operations. 527 + */ 528 + __u64 size; 529 + 530 + /** 531 + * @syncs: Array of struct drm_panthor_sync_op synchronization 532 + * operations. 533 + * 534 + * This array must be empty if %DRM_PANTHOR_VM_BIND_ASYNC is not set on 535 + * the drm_panthor_vm_bind object containing this VM bind operation. 536 + * 537 + * This array shall not be empty for sync-only operations. 538 + */ 539 + struct drm_panthor_obj_array syncs; 540 + 541 + }; 542 + 543 + /** 544 + * enum drm_panthor_vm_bind_flags - VM bind flags 545 + */ 546 + enum drm_panthor_vm_bind_flags { 547 + /** 548 + * @DRM_PANTHOR_VM_BIND_ASYNC: VM bind operations are queued to the VM 549 + * queue instead of being executed synchronously. 550 + */ 551 + DRM_PANTHOR_VM_BIND_ASYNC = 1 << 0, 552 + }; 553 + 554 + /** 555 + * struct drm_panthor_vm_bind - Arguments passed to DRM_IOCTL_PANTHOR_VM_BIND 556 + */ 557 + struct drm_panthor_vm_bind { 558 + /** @vm_id: VM targeted by the bind request. */ 559 + __u32 vm_id; 560 + 561 + /** @flags: Combination of drm_panthor_vm_bind_flags flags. */ 562 + __u32 flags; 563 + 564 + /** @ops: Array of struct drm_panthor_vm_bind_op bind operations. */ 565 + struct drm_panthor_obj_array ops; 566 + }; 567 + 568 + /** 569 + * enum drm_panthor_vm_state - VM states. 570 + */ 571 + enum drm_panthor_vm_state { 572 + /** 573 + * @DRM_PANTHOR_VM_STATE_USABLE: VM is usable. 574 + * 575 + * New VM operations will be accepted on this VM. 576 + */ 577 + DRM_PANTHOR_VM_STATE_USABLE, 578 + 579 + /** 580 + * @DRM_PANTHOR_VM_STATE_UNUSABLE: VM is unusable. 581 + * 582 + * Something put the VM in an unusable state (like an asynchronous 583 + * VM_BIND request failing for any reason). 584 + * 585 + * Once the VM is in this state, all new MAP operations will be 586 + * rejected, and any GPU job targeting this VM will fail. 587 + * UNMAP operations are still accepted. 588 + * 589 + * The only way to recover from an unusable VM is to create a new 590 + * VM, and destroy the old one. 591 + */ 592 + DRM_PANTHOR_VM_STATE_UNUSABLE, 593 + }; 594 + 595 + /** 596 + * struct drm_panthor_vm_get_state - Get VM state. 597 + */ 598 + struct drm_panthor_vm_get_state { 599 + /** @vm_id: VM targeted by the get_state request. */ 600 + __u32 vm_id; 601 + 602 + /** 603 + * @state: state returned by the driver. 604 + * 605 + * Must be one of the enum drm_panthor_vm_state values. 606 + */ 607 + __u32 state; 608 + }; 609 + 610 + /** 611 + * enum drm_panthor_bo_flags - Buffer object flags, passed at creation time. 612 + */ 613 + enum drm_panthor_bo_flags { 614 + /** @DRM_PANTHOR_BO_NO_MMAP: The buffer object will never be CPU-mapped in userspace. */ 615 + DRM_PANTHOR_BO_NO_MMAP = (1 << 0), 616 + }; 617 + 618 + /** 619 + * struct drm_panthor_bo_create - Arguments passed to DRM_IOCTL_PANTHOR_BO_CREATE. 620 + */ 621 + struct drm_panthor_bo_create { 622 + /** 623 + * @size: Requested size for the object 624 + * 625 + * The (page-aligned) allocated size for the object will be returned. 626 + */ 627 + __u64 size; 628 + 629 + /** 630 + * @flags: Flags. Must be a combination of drm_panthor_bo_flags flags. 631 + */ 632 + __u32 flags; 633 + 634 + /** 635 + * @exclusive_vm_id: Exclusive VM this buffer object will be mapped to. 636 + * 637 + * If not zero, the field must refer to a valid VM ID, and implies that: 638 + * - the buffer object will only ever be bound to that VM 639 + * - cannot be exported as a PRIME fd 640 + */ 641 + __u32 exclusive_vm_id; 642 + 643 + /** 644 + * @handle: Returned handle for the object. 645 + * 646 + * Object handles are nonzero. 647 + */ 648 + __u32 handle; 649 + 650 + /** @pad: MBZ. */ 651 + __u32 pad; 652 + }; 653 + 654 + /** 655 + * struct drm_panthor_bo_mmap_offset - Arguments passed to DRM_IOCTL_PANTHOR_BO_MMAP_OFFSET. 656 + */ 657 + struct drm_panthor_bo_mmap_offset { 658 + /** @handle: Handle of the object we want an mmap offset for. */ 659 + __u32 handle; 660 + 661 + /** @pad: MBZ. */ 662 + __u32 pad; 663 + 664 + /** @offset: The fake offset to use for subsequent mmap calls. */ 665 + __u64 offset; 666 + }; 667 + 668 + /** 669 + * struct drm_panthor_queue_create - Queue creation arguments. 670 + */ 671 + struct drm_panthor_queue_create { 672 + /** 673 + * @priority: Defines the priority of queues inside a group. Goes from 0 to 15, 674 + * 15 being the highest priority. 675 + */ 676 + __u8 priority; 677 + 678 + /** @pad: Padding fields, MBZ. */ 679 + __u8 pad[3]; 680 + 681 + /** @ringbuf_size: Size of the ring buffer to allocate to this queue. */ 682 + __u32 ringbuf_size; 683 + }; 684 + 685 + /** 686 + * enum drm_panthor_group_priority - Scheduling group priority 687 + */ 688 + enum drm_panthor_group_priority { 689 + /** @PANTHOR_GROUP_PRIORITY_LOW: Low priority group. */ 690 + PANTHOR_GROUP_PRIORITY_LOW = 0, 691 + 692 + /** @PANTHOR_GROUP_PRIORITY_MEDIUM: Medium priority group. */ 693 + PANTHOR_GROUP_PRIORITY_MEDIUM, 694 + 695 + /** @PANTHOR_GROUP_PRIORITY_HIGH: High priority group. */ 696 + PANTHOR_GROUP_PRIORITY_HIGH, 697 + }; 698 + 699 + /** 700 + * struct drm_panthor_group_create - Arguments passed to DRM_IOCTL_PANTHOR_GROUP_CREATE 701 + */ 702 + struct drm_panthor_group_create { 703 + /** @queues: Array of drm_panthor_queue_create elements. */ 704 + struct drm_panthor_obj_array queues; 705 + 706 + /** 707 + * @max_compute_cores: Maximum number of cores that can be used by compute 708 + * jobs across CS queues bound to this group. 709 + * 710 + * Must be less or equal to the number of bits set in @compute_core_mask. 711 + */ 712 + __u8 max_compute_cores; 713 + 714 + /** 715 + * @max_fragment_cores: Maximum number of cores that can be used by fragment 716 + * jobs across CS queues bound to this group. 717 + * 718 + * Must be less or equal to the number of bits set in @fragment_core_mask. 719 + */ 720 + __u8 max_fragment_cores; 721 + 722 + /** 723 + * @max_tiler_cores: Maximum number of tilers that can be used by tiler jobs 724 + * across CS queues bound to this group. 725 + * 726 + * Must be less or equal to the number of bits set in @tiler_core_mask. 727 + */ 728 + __u8 max_tiler_cores; 729 + 730 + /** @priority: Group priority (see enum drm_panthor_group_priority). */ 731 + __u8 priority; 732 + 733 + /** @pad: Padding field, MBZ. */ 734 + __u32 pad; 735 + 736 + /** 737 + * @compute_core_mask: Mask encoding cores that can be used for compute jobs. 738 + * 739 + * This field must have at least @max_compute_cores bits set. 740 + * 741 + * The bits set here should also be set in drm_panthor_gpu_info::shader_present. 742 + */ 743 + __u64 compute_core_mask; 744 + 745 + /** 746 + * @fragment_core_mask: Mask encoding cores that can be used for fragment jobs. 747 + * 748 + * This field must have at least @max_fragment_cores bits set. 749 + * 750 + * The bits set here should also be set in drm_panthor_gpu_info::shader_present. 751 + */ 752 + __u64 fragment_core_mask; 753 + 754 + /** 755 + * @tiler_core_mask: Mask encoding cores that can be used for tiler jobs. 756 + * 757 + * This field must have at least @max_tiler_cores bits set. 758 + * 759 + * The bits set here should also be set in drm_panthor_gpu_info::tiler_present. 760 + */ 761 + __u64 tiler_core_mask; 762 + 763 + /** 764 + * @vm_id: VM ID to bind this group to. 765 + * 766 + * All submission to queues bound to this group will use this VM. 767 + */ 768 + __u32 vm_id; 769 + 770 + /** 771 + * @group_handle: Returned group handle. Passed back when submitting jobs or 772 + * destroying a group. 773 + */ 774 + __u32 group_handle; 775 + }; 776 + 777 + /** 778 + * struct drm_panthor_group_destroy - Arguments passed to DRM_IOCTL_PANTHOR_GROUP_DESTROY 779 + */ 780 + struct drm_panthor_group_destroy { 781 + /** @group_handle: Group to destroy */ 782 + __u32 group_handle; 783 + 784 + /** @pad: Padding field, MBZ. */ 785 + __u32 pad; 786 + }; 787 + 788 + /** 789 + * struct drm_panthor_queue_submit - Job submission arguments. 790 + * 791 + * This is describing the userspace command stream to call from the kernel 792 + * command stream ring-buffer. Queue submission is always part of a group 793 + * submission, taking one or more jobs to submit to the underlying queues. 794 + */ 795 + struct drm_panthor_queue_submit { 796 + /** @queue_index: Index of the queue inside a group. */ 797 + __u32 queue_index; 798 + 799 + /** 800 + * @stream_size: Size of the command stream to execute. 801 + * 802 + * Must be 64-bit/8-byte aligned (the size of a CS instruction) 803 + * 804 + * Can be zero if stream_addr is zero too. 805 + */ 806 + __u32 stream_size; 807 + 808 + /** 809 + * @stream_addr: GPU address of the command stream to execute. 810 + * 811 + * Must be aligned on 64-byte. 812 + * 813 + * Can be zero is stream_size is zero too. 814 + */ 815 + __u64 stream_addr; 816 + 817 + /** 818 + * @latest_flush: FLUSH_ID read at the time the stream was built. 819 + * 820 + * This allows cache flush elimination for the automatic 821 + * flush+invalidate(all) done at submission time, which is needed to 822 + * ensure the GPU doesn't get garbage when reading the indirect command 823 + * stream buffers. If you want the cache flush to happen 824 + * unconditionally, pass a zero here. 825 + */ 826 + __u32 latest_flush; 827 + 828 + /** @pad: MBZ. */ 829 + __u32 pad; 830 + 831 + /** @syncs: Array of struct drm_panthor_sync_op sync operations. */ 832 + struct drm_panthor_obj_array syncs; 833 + }; 834 + 835 + /** 836 + * struct drm_panthor_group_submit - Arguments passed to DRM_IOCTL_PANTHOR_GROUP_SUBMIT 837 + */ 838 + struct drm_panthor_group_submit { 839 + /** @group_handle: Handle of the group to queue jobs to. */ 840 + __u32 group_handle; 841 + 842 + /** @pad: MBZ. */ 843 + __u32 pad; 844 + 845 + /** @queue_submits: Array of drm_panthor_queue_submit objects. */ 846 + struct drm_panthor_obj_array queue_submits; 847 + }; 848 + 849 + /** 850 + * enum drm_panthor_group_state_flags - Group state flags 851 + */ 852 + enum drm_panthor_group_state_flags { 853 + /** 854 + * @DRM_PANTHOR_GROUP_STATE_TIMEDOUT: Group had unfinished jobs. 855 + * 856 + * When a group ends up with this flag set, no jobs can be submitted to its queues. 857 + */ 858 + DRM_PANTHOR_GROUP_STATE_TIMEDOUT = 1 << 0, 859 + 860 + /** 861 + * @DRM_PANTHOR_GROUP_STATE_FATAL_FAULT: Group had fatal faults. 862 + * 863 + * When a group ends up with this flag set, no jobs can be submitted to its queues. 864 + */ 865 + DRM_PANTHOR_GROUP_STATE_FATAL_FAULT = 1 << 1, 866 + }; 867 + 868 + /** 869 + * struct drm_panthor_group_get_state - Arguments passed to DRM_IOCTL_PANTHOR_GROUP_GET_STATE 870 + * 871 + * Used to query the state of a group and decide whether a new group should be created to 872 + * replace it. 873 + */ 874 + struct drm_panthor_group_get_state { 875 + /** @group_handle: Handle of the group to query state on */ 876 + __u32 group_handle; 877 + 878 + /** 879 + * @state: Combination of DRM_PANTHOR_GROUP_STATE_* flags encoding the 880 + * group state. 881 + */ 882 + __u32 state; 883 + 884 + /** @fatal_queues: Bitmask of queues that faced fatal faults. */ 885 + __u32 fatal_queues; 886 + 887 + /** @pad: MBZ */ 888 + __u32 pad; 889 + }; 890 + 891 + /** 892 + * struct drm_panthor_tiler_heap_create - Arguments passed to DRM_IOCTL_PANTHOR_TILER_HEAP_CREATE 893 + */ 894 + struct drm_panthor_tiler_heap_create { 895 + /** @vm_id: VM ID the tiler heap should be mapped to */ 896 + __u32 vm_id; 897 + 898 + /** @initial_chunk_count: Initial number of chunks to allocate. */ 899 + __u32 initial_chunk_count; 900 + 901 + /** @chunk_size: Chunk size. Must be a power of two at least 256KB large. */ 902 + __u32 chunk_size; 903 + 904 + /** @max_chunks: Maximum number of chunks that can be allocated. */ 905 + __u32 max_chunks; 906 + 907 + /** 908 + * @target_in_flight: Maximum number of in-flight render passes. 909 + * 910 + * If the heap has more than tiler jobs in-flight, the FW will wait for render 911 + * passes to finish before queuing new tiler jobs. 912 + */ 913 + __u32 target_in_flight; 914 + 915 + /** @handle: Returned heap handle. Passed back to DESTROY_TILER_HEAP. */ 916 + __u32 handle; 917 + 918 + /** @tiler_heap_ctx_gpu_va: Returned heap GPU virtual address returned */ 919 + __u64 tiler_heap_ctx_gpu_va; 920 + 921 + /** 922 + * @first_heap_chunk_gpu_va: First heap chunk. 923 + * 924 + * The tiler heap is formed of heap chunks forming a single-link list. This 925 + * is the first element in the list. 926 + */ 927 + __u64 first_heap_chunk_gpu_va; 928 + }; 929 + 930 + /** 931 + * struct drm_panthor_tiler_heap_destroy - Arguments passed to DRM_IOCTL_PANTHOR_TILER_HEAP_DESTROY 932 + */ 933 + struct drm_panthor_tiler_heap_destroy { 934 + /** @handle: Handle of the tiler heap to destroy */ 935 + __u32 handle; 936 + 937 + /** @pad: Padding field, MBZ. */ 938 + __u32 pad; 939 + }; 940 + 941 + #if defined(__cplusplus) 942 + } 943 + #endif 944 + 945 + #endif /* _PANTHOR_DRM_H_ */